Skip to content

Commit

Permalink
Merge pull request #152 from fabiobrz/demo.add-wildfly-saml-adapter-l…
Browse files Browse the repository at this point in the history
…ayer

[issue 140] Examples: demonstrate WildFly with Keycloack SAML adapter Galleon Pack s2i provisioning with Intersmash
  • Loading branch information
tommaso-borgato authored Mar 28, 2024
2 parents e5e2e8f + 85159f1 commit cc13cd3
Show file tree
Hide file tree
Showing 11 changed files with 474 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<modules>
<module>ws-bootable-jar-example</module>
<module>wstrust</module>
<module>wildfly-keycloak-saml-adapter</module>
</modules>

<build>
Expand Down
79 changes: 79 additions & 0 deletions examples/wildfly-keycloak-saml-adapter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Intersmash examples - Wildfly with Keycloak SAML Adapter Galleon Pack

This example shows how to use Intersmash to provision and test a WildFly application on OpenShift via a s2i binary
build.

## Overview
The application is a simple "Hello World!" Java EE application, which is executed by a WildFly instance that is
provisioned via the WildFly Maven Plugin. Such plugin allows for tailoring a WildFly server with just the
required modules and configuration enabled.

In this example, the application project POM also demonstrates how to configure the plugin for adding the WildFly
Keycloak SAML Adapter Galleon Pack and the related `keycloak-saml` layer to the server configuration.

There is no interoperability involved in this example, as there isn't a Keycloak server that the WildFly application
interacts with, and the test ony verifies that the server configuration contains the elements related to the
Keycloak SAML Adapter resources.

## Test code
The test code consists of an Intersmash _application descriptor_ class, i.e.
[KeycloakCapableImageBasedWildflyApplication](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplication.java)
and an Intersmash test class, i.e.
[KeycloakCapableImageBasedWildflyApplicationTest](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplicationTest.java).

### The _application descriptor_
[KeycloakCapableImageBasedWildflyApplication](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplication.java) provides the information that the provisioner will use to deploy the
service on OpenShift. For instance, it can define environment variables, or secrets, and the build input.
This is the input for the s2i build that the provisioner will orchestrate on
OpenShift, in order to generate the final immutable image containing the WildFly application server and the
application deployment itself.
In our case the build input is represented by a local WildFly deployment, as generated by the WildFly Maven plugin
execution.

#### Resolving the build input
The [templating-maven-plugin](https://www.mojohaus.org/templating-maven-plugin/) is used to have - for example - Maven
project properties injected with concrete values in Java classes at runtime.

When built, this example uses such plugin in order to generate the
`KeycloackCapableWildflyDeploymentConfiguration` Java class from the
[KeycloackCapableWildflyDeploymentConfiguration.java](../wildfly-keycloak-saml-adapter/src/test/resources/java-templates/org/jboss/intersmash/examples/wildfly/keycloak/saml/config/KeycloackCapableWildflyDeploymentConfiguration.java) template.
This class contains the information needed to identify the built artifact properties or location, and is used by
[KeycloakCapableImageBasedWildflyApplication](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplication.java)
to initialize the build input with the `target/server` directory produced by the WildFly Maven Plugin.

#### The _provisioner_
The _provisioner_ is
[selected by Intersmash](../../../intersmash/provisioners/README.md#mapping-of-implemented-provisioners-), based on the
`Application` type that a given _application descriptor_ implements.

[KeycloakCapableImageBasedWildflyApplication](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplication.java)
extends
[WildflyImageOpenShiftApplication](../../../intersmash/provisioners/src/main/java/org/jboss/intersmash/application/openshift/WildflyImageOpenShiftApplication.java)
which is provisioned by
[WildflyImageOpenShiftProvisioner](/../../../intersmash/provisioners/src/main/java/org/jboss/intersmash/provision/openshift/WildflyImageOpenShiftProvisioner.java).

Such provisioner infers the build input runtime type in order to create the resources for either a source or binary
based s2i build to happen on OpenShift and to generate the final WildFly application image that will be fed to a
`DeploymentConfig` resource, which is eventually used for orchestrating the pods that run the actual application
service workload.

### The test class

[KeycloakCapableImageBasedWildflyApplicationTest](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplicationTest.java)
is a valid Intersmash test class - as per the `@Intersmash` annotation, and its lifecycle is fully managed by
Intersmash, based on the information provided by the `@Service` annotations.
The scenario consists of just one service, i.e. the one represented by the
[KeycloakCapableImageBasedWildflyApplication](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplication.java)
_application descriptor_.
It uses the `@ServiceUrl` annotation in order to let Intersmash inject the URL that exposes the application service
outside OpenShift, and which is used by one test method, which is a simple call to check that the server
configuration actually contains the resources defined by the WildFly Keycloak SAML Adapter Galleon pack.

## Running the test

After building the project, just issue:
```shell
mvn clean install -Pdemo -pl examples/wildfly-keycloak-saml-adapter
```

Or simply start the [test](../wildfly-keycloak-saml-adapter/src/test/java/org/jboss/intersmash/examples/wildfly/keycloak/saml/KeycloakCapableImageBasedWildflyApplicationTest.java) within your favourite IDE.
174 changes: 174 additions & 0 deletions examples/wildfly-keycloak-saml-adapter/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jboss.intersmash.examples</groupId>
<artifactId>intersmash-examples</artifactId>
<version>0.0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>wildfly-keycloak-saml-adapter</artifactId>
<packaging>war</packaging>

<name>Intersmash Demos : (Wildfly): Wildfly with Keycloak SAML Adapter</name>

<properties>
<formatting-style-base-directory>${project.parent.parent.basedir}/ide-config</formatting-style-base-directory>
<version.maven-war-plugin>3.3.2</version.maven-war-plugin>
<!-- Wildfly default version -->
<version.wildfly-server>30.0.0.Final</version.wildfly-server>
<!-- WildFly Maven Plugin version -->
<wildfly-maven-plugin.version>4.2.2.Final</wildfly-maven-plugin.version>
<!-- Default WildFly `ee` BOMs version is set here and can be overridden for pulling the right BOM -->
<bom.wildfly-ee.version>${version.wildfly-server}</bom.wildfly-ee.version>
<!--
Feature packs and channel:
- EAP = org.jboss.eap:wildfly-ee-galleon-pack (only EE specs included)
- EAP XP = org.jboss.eap:wildfly-galleon-pack (EE specs as well as MP specs)
- WF = org.wildfly:wildfly-galleon-pack (EE specs as well as MP specs)
Note: WF builds have both `wildfly-galleon-pack` and `wildfly-ee-galleon-pack`
-->
<wildfly.feature-pack.location>org.wildfly:wildfly-galleon-pack:${version.wildfly-server}</wildfly.feature-pack.location>
<wildfly.ee-feature-pack.location>org.wildfly:wildfly-ee-galleon-pack:${version.wildfly-server}</wildfly.ee-feature-pack.location>
<wildfly.cloud-feature-pack.location>org.wildfly.cloud:wildfly-cloud-galleon-pack:5.0.1.Final</wildfly.cloud-feature-pack.location>

<!-- Keycloak SAML -->
<keycloak-saml-adapter-galleon-pack.groupId>org.keycloak</keycloak-saml-adapter-galleon-pack.groupId>
<keycloak-saml-adapter-galleon-pack.artifactId>keycloak-saml-adapter-galleon-pack</keycloak-saml-adapter-galleon-pack.artifactId>
<keycloak-saml-adapter-galleon-pack.version>22.0.3</keycloak-saml-adapter-galleon-pack.version>
</properties>

<dependencyManagement>
<dependencies>
<!-- Lock all the provided Jakarta dependencies to match the WildFly/EAP 8 version -->
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-ee</artifactId>
<version>${bom.wildfly-ee.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
</dependency>
<dependency>
<groupId>org.wildfly.core</groupId>
<artifactId>wildfly-controller-client</artifactId>
<version>23.0.0.Beta4</version>
</dependency>

<dependency>
<groupId>org.jboss.intersmash</groupId>
<artifactId>intersmash-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.intersmash</groupId>
<artifactId>intersmash-provisioners</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.intersmash.test</groupId>
<artifactId>deployments-provider</artifactId>
<version>0.0.2-SNAPSHOT</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>templating-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>filter-src</id>
<goals>
<goal>filter-test-sources</goal>
</goals>
<configuration>
<!--
Note the two following parameters are the default one.
These are specified here just as a reminder.
But as the Maven philosophy is strongly about conventions,
it's better to just not specify them.
-->
<testSourceDirectory>${basedir}/src/test/resources/java-templates/org/jboss/intersmash/examples/wildfly/keycloak/saml/config/</testSourceDirectory>
<testOutputDirectory>${project.build.directory}/generated-sources</testOutputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!--
Deployment are setting the WAR file name to ROOT, according to the wildfly-maven-plugin configuration
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>${version.maven-war-plugin}</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>ROOT</warName>
</configuration>
</plugin>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${wildfly-maven-plugin.version}</version>
<configuration>
<filename>ROOT.war</filename>
<!-- some tests check for the provisioned galleon layers -->
<record-provisioning-state>true</record-provisioning-state>
<feature-packs>
<feature-pack>
<location>${wildfly.feature-pack.location}</location>
</feature-pack>
<feature-pack>
<location>${wildfly.cloud-feature-pack.location}</location>
</feature-pack>
<feature-pack>
<groupId>${keycloak-saml-adapter-galleon-pack.groupId}</groupId>
<artifactId>${keycloak-saml-adapter-galleon-pack.artifactId}</artifactId>
<version>${keycloak-saml-adapter-galleon-pack.version}</version>
</feature-pack>
</feature-packs>
<layers>
<layer>cloud-default-config</layer>
<layer>keycloak-saml</layer>
</layers>
<galleon-options>
<jboss-fork-embedded>true</jboss-fork-embedded>
</galleon-options>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jboss.intersmash.examples.wildfly.keycloak.saml;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
@ApplicationScoped
public class HelloResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String greet() {
return "Hello world!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.jboss.intersmash.examples.wildfly.keycloak.saml;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/")
public class RestApplication extends Application {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jboss.intersmash.examples.wildfly.keycloak.saml;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

@Path("/config")
@ApplicationScoped
public class ServerConfigurationResource {
@GET
@Path("/read")
@Produces(MediaType.TEXT_PLAIN)
public String read() throws IOException {
String fileName = System.getProperty("jboss.server.config.dir") + "/standalone.xml";
try (FileInputStream fis = new FileInputStream(fileName)) {
return new BufferedReader(
new InputStreamReader(fis, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"));

}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.jboss.intersmash.examples.wildfly.keycloak.saml;

import java.nio.file.Path;
import java.nio.file.Paths;

import org.jboss.intersmash.application.openshift.WildflyImageOpenShiftApplication;
import org.jboss.intersmash.application.openshift.input.BinarySource;
import org.jboss.intersmash.application.openshift.input.BuildInput;
import org.jboss.intersmash.examples.wildfly.keycloak.saml.config.KeycloackCapableWildflyDeploymentConfiguration;

public class KeycloakCapableImageBasedWildflyApplication implements WildflyImageOpenShiftApplication {

@Override
public String getName() {
return "wildfly-app";
}

@Override
public BuildInput getBuildInput() {
return (BinarySource) () -> {
Path path = Paths.get(KeycloackCapableWildflyDeploymentConfiguration.deploymentPath());
if (path.toFile().exists() && path.toFile().isDirectory()) {
return path;
}
throw new RuntimeException("Cannot find sources root directory: " + path.toFile().getAbsolutePath());
};
}
}
Loading

0 comments on commit cc13cd3

Please sign in to comment.