Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions web-modules/jersey-2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@
<artifactId>jakarta.xml.bind-api</artifactId>
<version>${jaxb-runtime.version}</version> <!-- Or the latest version -->
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<version>${wiremock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down Expand Up @@ -144,6 +150,7 @@
<jaxb-runtime.version>3.0.1</jaxb-runtime.version>
<junit.jupiter.version>5.8.2</junit.jupiter.version>
<mockito-junit-jupiter.version>4.5.1</mockito-junit-jupiter.version>
<wiremock.version>3.13.0</wiremock.version>
</properties>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.baeldung.jersey.https;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.get;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.SSLContext;

import org.apache.hc.core5.ssl.SSLContextBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Response;

/**
* 1. run {@code gen-keys.sh api.service} to generate server certificate/stores
* 2. specify system properties with the directory of the certificates and password
* 3. create api.service entries for 127.0.0.1 in /etc/hosts
* 4. run this class
*/
class JerseyHttpsClientManualTest {

static final String MOCK_HOST = "api.service";
static final String CERTS_DIR = System.getProperty("certs.dir");
static final String PASSWORD = System.getProperty("certs.password");

WireMockServer api;

void setup(boolean mTls) {
api = mockHttpsServer(mTls);
api.stubFor(get(urlEqualTo("/test")).willReturn(aResponse().withHeader("Content-Type", "text/plain")
.withStatus(200)
.withBody("ok")));
api.start();

System.out.println(">> Mock server started on HTTPS port: " + api.httpsPort());
}

@AfterEach
void teardown() {
if (api != null) {
api.stop();
}
}

@Test
void whenUsingJVMParameters_thenCorrectCertificateUsed() {
setup(false);

System.setProperty("javax.net.ssl.trustStore", CERTS_DIR + "/trust." + MOCK_HOST + ".p12");
System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);

Response response = ClientBuilder.newClient().target(String.format("https://%s:%d/test", api.getOptions().bindAddress(), api.httpsPort()))
.request()
.get();

assertEquals(200, response.getStatus());
}

@Test
void whenUsingCustomSSLContext_thenCorrectCertificateUsed() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
setup(false);

SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(Paths.get(CERTS_DIR + "/trust." + MOCK_HOST + ".p12"), PASSWORD.toCharArray())
.build();

Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.build();

Response response = client.target(String.format("https://%s:%d/test", api.getOptions().bindAddress(), api.httpsPort()))
.request()
.get();
assertEquals(200, response.getStatus());
}

@Test
void whenUsingMutualTLS_thenCorrectCertificateUsed() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
setup(true);

char[] password = PASSWORD.toCharArray();

SSLContext sslContext = SSLContextBuilder.create()
.loadTrustMaterial(Paths.get(CERTS_DIR + "/trust." + MOCK_HOST + ".p12"), password)
.loadKeyMaterial(Paths.get(CERTS_DIR + "/client." + MOCK_HOST + ".p12"), password, password)
.build();

Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.build();

Response response = client.target(String.format("https://%s:%d/test", api.getOptions().bindAddress(), api.httpsPort()))
.request()
.get();
assertEquals(200, response.getStatus());
}

private static WireMockServer mockHttpsServer(boolean mTls) {
WireMockConfiguration config = WireMockConfiguration.options()
.bindAddress(MOCK_HOST)
.dynamicPort()
.dynamicHttpsPort()
.keystorePath(CERTS_DIR + "/server." + MOCK_HOST + ".p12")
.keystorePassword(PASSWORD)
.keyManagerPassword(PASSWORD);

if (mTls) {
config.trustStorePath(CERTS_DIR + "/trust." + MOCK_HOST + ".p12")
.trustStorePassword(PASSWORD)
.needClientAuth(true);
}

return new WireMockServer(config);
}
}
49 changes: 49 additions & 0 deletions web-modules/jersey-2/src/test/resources/https/gen-keys.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash -e
# @see JerseyHttpsClientManualTest
# generates a CA, signed client/server keys and trust stores for the provided host.
# e.g.: gen-keys.sh api.service <desired-password>
MYSELF="$(readlink -f $0)"
MYDIR="${MYSELF%/*}"

HOST=${1}
if [[ -z "$HOST" ]]; then
echo "arg 1 should be the host/alias"
exit 1
fi

PASSWORD="${2}"
if [[ -z "$PASSWORD" ]]; then
echo "arg 2 should be the desired password"
exit 1
fi

VALIDITY_DAYS=1
CERTS_DIR=$MYDIR/keystore

mkdir -p "$CERTS_DIR"

keytool=$JAVA_HOME/bin/keytool
$JAVA_HOME/bin/java -version

echo '1. creating certificate authority (CA)'
openssl genrsa -out $CERTS_DIR/ca.${HOST}.key 2048
openssl req -x509 -new -nodes -key $CERTS_DIR/ca.${HOST}.key -sha256 -days $VALIDITY_DAYS -out $CERTS_DIR/ca.${HOST}.crt -subj "/CN=${HOST}"

echo '2. generating server key and CSR'
openssl genrsa -out $CERTS_DIR/server.${HOST}.key 2048
openssl req -new -key $CERTS_DIR/server.${HOST}.key -out $CERTS_DIR/server.${HOST}.csr -subj "/CN=${HOST}"
openssl x509 -req -in $CERTS_DIR/server.${HOST}.csr -CA $CERTS_DIR/ca.${HOST}.crt -CAkey $CERTS_DIR/ca.${HOST}.key -CAcreateserial -out $CERTS_DIR/server.${HOST}.crt -days $VALIDITY_DAYS -sha256

echo '3. generating client key and CSR'
openssl genrsa -out $CERTS_DIR/client.${HOST}.key 2048
openssl req -new -key $CERTS_DIR/client.${HOST}.key -out $CERTS_DIR/client.${HOST}.csr -subj "/CN=${HOST}"
openssl x509 -req -in $CERTS_DIR/client.${HOST}.csr -CA $CERTS_DIR/ca.${HOST}.crt -CAkey $CERTS_DIR/ca.${HOST}.key -CAcreateserial -out $CERTS_DIR/client.${HOST}.crt -days $VALIDITY_DAYS -sha256

echo '4. creating PKCS12 keystores'
openssl pkcs12 -export -out $CERTS_DIR/server.${HOST}.p12 -inkey $CERTS_DIR/server.${HOST}.key -in $CERTS_DIR/server.${HOST}.crt -certfile $CERTS_DIR/ca.${HOST}.crt -name ${HOST} -passout pass:$PASSWORD
openssl pkcs12 -export -out $CERTS_DIR/client.${HOST}.p12 -inkey $CERTS_DIR/client.${HOST}.key -in $CERTS_DIR/client.${HOST}.crt -certfile $CERTS_DIR/ca.${HOST}.crt -name ${HOST} -passout pass:$PASSWORD

echo '5. creating truststore'
$keytool -importcert -keystore $CERTS_DIR/trust.${HOST}.p12 -storetype PKCS12 -storepass $PASSWORD -alias ca.${HOST} -file $CERTS_DIR/ca.${HOST}.crt -noprompt

echo done