Skip to content

Commit

Permalink
[WFLY-18476] helloworld-mutual-ssl Quickstart Common Enhancements CY2…
Browse files Browse the repository at this point in the history
…023Q3
  • Loading branch information
Prarthona Paul committed Dec 20, 2023
1 parent 543ee74 commit 83d5ac2
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 9 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/quickstart_helloworld-mutual-ssl_ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: WildFly helloworld-mutual-ssl Quickstart CI

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- 'helloworld-mutual-ssl/**'
- '.github/workflows/quickstart_ci.yml'

jobs:
call-quickstart_ci:
uses: ./.github/workflows/quickstart_ci.yml
with:
QUICKSTART_PATH: helloworld-mutual-ssl
SERVER_PROVISIONING_SERVER_HOST: https://localhost:8443/
TEST_PROVISIONED_SERVER: true
TEST_OPENSHIFT: false
9 changes: 9 additions & 0 deletions helloworld-mutual-ssl/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,8 @@ DHo1uoz5/dzXZz0EjjWCPJk+LVEhEvH0GcWAp3x3irpNU4hRZLd0XomY0Z4NnUt7VMBNYDOxVxgT9qcL
aEWK4zhPVFynfnMaOxI67FC2QzhfzERyKqHj47WuwN0xWbS/1gBypS2nUwvItyxaEQG2X5uQY8j8QoY9wcMzIIkP2Mk14gJGHUnA8=
----

// Server Distribution Testing
include::../shared-doc/run-integration-tests-with-server-distribution.adoc[leveloffset=+2]
// Undeploy the Quickstart
include::../shared-doc/undeploy-the-quickstart.adoc[leveloffset=+1]
// Restore the {productName} Standalone Server Configuration
Expand Down Expand Up @@ -286,6 +288,7 @@ After you are done with this quickstart, remember to remove the certificate that
// Run the Quickstart in Red Hat Studio or Eclipse
include::../shared-doc/run-the-quickstart-in-jboss-developer-studio.adoc[leveloffset=+1]


// Additional Red Hat CodeReady Studio instructions
* Make sure you configure the keystore and client certificate as described under xref:set_up_client_keystore_using_java_keytool[Set Up the Client Keystore Using Java Keytool].
* Depending on the browser you choose, make sure you either xref:import_the_client_certificate_into_google_chrome[import the certificate into Google Chrome] or xref:import_the_client_certificate_into_mozilla_firefox[import the certificate into Mozilla Firefox].
Expand All @@ -307,6 +310,12 @@ $ mvn dependency:resolve -Dclassifier=javadoc
//*************************************************
// Product Release content only
//*************************************************
// Build and run sections for other environments/builds
ifndef::ProductRelease,EAPXPRelease[]
:server_provisioning_server_host: https://localhost:8443
include::../shared-doc/build-and-run-the-quickstart-with-provisioned-server.adoc[leveloffset=+1]
endif::[]
ifdef::ProductRelease[]
// Quickstart not compatible with OpenShift
Expand Down
19 changes: 19 additions & 0 deletions helloworld-mutual-ssl/configure-client-cert.cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Configure the client's keystore. This will be used to generate the client's certificate.
# The path to the keystore file doesn’t actually have to exist yet.
/subsystem=elytron/key-store=clientKS:add(path=client.keystore.P12, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=PKCS12)

# Generate a new key pair for the client. We'll use an RSA key of size 2048 and we'll use CN=quickstartUser
/subsystem=elytron/key-store=clientKS:generate-key-pair(alias=quickstartUser, algorithm=RSA, key-size=2048, validity=365, credential-reference={clear-text=secret}, distinguished-name="cn=quickstartUser")

# Export the client's certificate to a file called clientCert.crt
/subsystem=elytron/key-store=clientKS:export-certificate(alias=quickstartUser, path=clientCert.crt, relative-to=jboss.server.config.dir, pem=true)

# Create the server's truststore
/subsystem=elytron/key-store=serverTS:add(path=server.truststore, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, type=PKCS12)

# Import the client certificate into the server's truststore
/subsystem=elytron/key-store=serverTS:import-certificate(alias=quickstartUser, path=clientCert.crt, relative-to=jboss.server.config.dir, credential-reference={clear-text=secret}, validate=false)

# Persist the changes we've made to the client's keystore and the server's truststore
/subsystem=elytron/key-store=serverTS:store()
/subsystem=elytron/key-store=clientKS:store()
10 changes: 8 additions & 2 deletions helloworld-mutual-ssl/configure-ssl.cli
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@
batch

# Add the keystore and trust manager configuration in the elytron subsystem
/subsystem=elytron/key-store=qsTrustStore:add(path=client.truststore,relative-to=jboss.server.config.dir,type=JKS,credential-reference={clear-text=secret})
/subsystem=elytron/key-store=qsTrustStore:add(path=server.truststore,relative-to=jboss.server.config.dir,type=JKS,credential-reference={clear-text=secret})
/subsystem=elytron/trust-manager=qsTrustManager:add(key-store=qsTrustStore)

# Update the default server-ssl-context to reference the new trust-manager and require client auth
/subsystem=elytron/server-ssl-context=applicationSSC:write-attribute(name=trust-manager, value=qsTrustManager)
/subsystem=elytron/server-ssl-context=applicationSSC:write-attribute(name=need-client-auth, value=true)

# Generate the server's certificate
/subsystem=elytron/key-store=applicationKS:generate-key-pair(alias=server, algorithm=RSA, key-size=2048, validity=365, credential-reference={clear-text=password}, distinguished-name="cn=localhost")

# Store the key-pair in a keystore file
/subsystem=elytron/key-store=applicationKS:store()

# Run the batch commands
run-batch

# Reload the server configuration
reload
#reload


113 changes: 106 additions & 7 deletions helloworld-mutual-ssl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@
<version>5</version>
<relativePath/>
</parent>

<properties>
<!-- the version for the Server -->
<version.server>30.0.0.Final</version.server>
<!-- The versions for BOMs, Packs and Plugins -->
<version.bom.ee>${version.server}</version.bom.ee>
<version.pack.cloud>5.0.0.Beta1</version.pack.cloud>
<version.plugin.wildfly>4.2.0.Final</version.plugin.wildfly>
</properties>

<artifactId>helloworld-mutual-ssl</artifactId>
<version>31.0.0.Beta1-SNAPSHOT</version>
<packaging>war</packaging>
Expand All @@ -43,11 +53,6 @@
</license>
</licenses>

<properties>
<!-- The versions for BOMs, Dependencies and Plugins -->
<version.server.bom>30.0.0.Final</version.server.bom>
</properties>

<repositories>
<repository>
<id>jboss-public-maven-repository</id>
Expand Down Expand Up @@ -109,15 +114,14 @@
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-ee-with-tools</artifactId>
<version>${version.server.bom}</version>
<version>${version.bom.ee}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<!-- Import the CDI API, we use provided scope as the API is included in JBoss WildFly -->
<dependency>
<groupId>jakarta.enterprise</groupId>
Expand All @@ -140,5 +144,100 @@
<scope>provided</scope>
</dependency>

<!-- For tests -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependencies>

<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.plugin.wildfly}</version>
</plugin>
</plugins>
</pluginManagement>
</build>

<profiles>
<profile>
<id>provisioned-server</id>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<configuration>
<feature-packs>
<feature-pack>
<location>org.wildfly:wildfly-galleon-pack:${version.server}</location>
</feature-pack>
</feature-packs>
<layers>
<!-- layers may be used to customize the server to provision-->
<layer>cloud-server</layer>
<layer>undertow-https</layer>
</layers>
<!-- use cli script(s) to configure the server -->
<packaging-scripts>
<packaging-script>
<scripts>
<script>${basedir}/configure-client-cert.cli</script>
<script>${basedir}/configure-ssl.cli</script>
</scripts>
<!-- Expressions resolved during server execution -->
<resolve-expressions>false</resolve-expressions>
</packaging-script>
</packaging-scripts>
<!-- deploys the quickstart on root web context -->
<name>ROOT.war</name>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>integration-testing</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>
<include>**/BasicRuntimeIT</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
7 changes: 7 additions & 0 deletions helloworld-mutual-ssl/restore-client-certs.cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Remove the keypairs and certificates from the keystore and truststore
/subsystem=elytron/key-store=serverTS:remove-alias(alias=quickstartUser)
/subsystem=elytron/key-store=clientKS:remove-alias(alias=quickstartUser)

# Remove the keystore and truststore
/subsystem=elytron/key-store=serverTS:remove
/subsystem=elytron/key-store=clientKS:remove
3 changes: 3 additions & 0 deletions helloworld-mutual-ssl/restore-configuration.cli
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# Start batching commands
batch

# Remove the keypair with the alias server from the application keystore
/subsystem=elytron/key-store=applicationKS:remove-alias(alias=server)

# Remove the changes that were made to the default server-ssl-context
/subsystem=elytron/server-ssl-context=applicationSSC:undefine-attribute(name=trust-manager)
/subsystem=elytron/server-ssl-context=applicationSSC:undefine-attribute(name=need-client-auth)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright 2023 JBoss by Red Hat.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.as.quickstarts.helloworld_mutual_ssl;

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyStore;
import java.security.KeyStoreException;

import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.DefaultSchemePortResolver;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import javax.net.ssl.SSLContext;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpResponse;

import static org.jboss.as.quickstarts.helloworld_mutual_ssl.KeyStoreUtils.loadKeyPairFromKeyStore;
import static org.junit.Assert.assertEquals;

/**
* The very basic runtime integration testing.
* @author Prarthona Paul
* @author emartins
*/
public class BasicRuntimeIT {

private static final String DEFAULT_SERVER_HOST = "https://localhost:8443/helloworld-mutual-ssl";

@Test
public void testHTTPEndpointIsAvailable() throws IOException, InterruptedException, URISyntaxException, KeyStoreException {
String serverHost = System.getenv("SERVER_HOST");
if (serverHost == null) {
serverHost = System.getProperty("server.host");
}
if (serverHost == null) {
serverHost = DEFAULT_SERVER_HOST;
}
String serverDir = System.getenv("SERVER_HOME");
if (serverDir == null) {
if (System.getProperty("jboss.server.config.dir").contains("target/server")) {
serverDir = System.getProperty("user.dir") + "/" + System.getProperty("jboss.server.config.dir");
} else {
serverDir = System.getProperty("jboss.server.config.dir");
}
}
HttpGet request = new HttpGet(new URI(serverHost+"/"));
KeyStore trustStore = loadKeyPairFromKeyStore(serverDir, "application.keystore", "password", "server", "PKCS12");
final HttpClient client = getHttpClientWithSSL(new File(serverDir + "/client.keystore.P12"), "secret", "PKCS12", new File(serverDir + "/client.truststore"), "password", "PKCS12");
HttpResponse response = client.execute(request);
assertEquals(200, response.getStatusLine().getStatusCode());
}

public HttpClient getHttpClientWithSSL(File keyStoreFile, String keyStorePassword, String keyStoreProvider,
File trustStoreFile, String trustStorePassword, String trustStoreProvider) {

try {
KeyStore trustStore = KeyStore.getInstance(trustStoreProvider);
try (FileInputStream fis = new FileInputStream(trustStoreFile)) {
trustStore.load(fis, trustStorePassword.toCharArray());
}
SSLContextBuilder sslContextBuilder = SSLContexts.custom()
.setProtocol("TLS")
.loadTrustMaterial(trustStore, null);
if (keyStoreFile != null) {
KeyStore keyStore = KeyStore.getInstance(keyStoreProvider);
try (FileInputStream fis = new FileInputStream(keyStoreFile)) {
keyStore.load(fis, keyStorePassword.toCharArray());
}
sslContextBuilder.loadKeyMaterial(keyStore, keyStorePassword.toCharArray(), null);
}
SSLContext sslContext = sslContextBuilder.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);

Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", socketFactory)
.build();

return HttpClientBuilder.create()
.setSSLSocketFactory(socketFactory)
// .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setConnectionManager(new PoolingHttpClientConnectionManager(registry))
.setSchemePortResolver(new DefaultSchemePortResolver())
.build();

} catch (Exception e) {
throw new RuntimeException("Creating HttpClient with customized SSL failed.", e);
}
}
}
Loading

0 comments on commit 83d5ac2

Please sign in to comment.