Chapter 3. Building and running JBoss EAP applications on OpenShift Container Platform You can follow the source-to-image (S2I) process to build and run a Java application on the JBoss EAP for OpenShift image. 3.1. Prerequisites You have an OpenShift instance installed and operational. 3.2. Preparing OpenShift to deploy an application As a JBoss EAP application developer, you can deploy your applications on OpenShift. In the following example, note that the kitchensink quickstart demonstrates a Jakarta EE web-enabled database application using Jakarta Server Faces, Jakarta Contexts and Dependency Injection, Jakarta Enterprise Beans, Jakarta Persistence, and Jakarta Bean Validation. See the JBoss EAP 8.0 kitchensink quickstart for more information. Deploy your application by following the procedures below. Procedure Log in to your OpenShift instance using the oc login command. Create a project in OpenShift. Create a project using the following command. With a project, you can organize and manage content separately from other groups. For example, for the kitchensink quickstart, create a project named eap-demo using the following command: Optional : Create a keystore and a secret. Note You must create a keystore and a secret if you use any HTTPS-enabled features in your OpenShift project. Use the Java keytool command to generate a keystore: Warning The following commands generate a self-signed certificate, but for production environments, use your own SSL certificate from a verified certificate authority (CA) for SSL-encrypted connections (HTTPS). For example, for the kitchensink quickstart, use the following command to generate a keystore: Use the following command to create a secret from your new keystore: For example, for the kitchensink quickstart, use the following command to create a secret: Additional resources ImageStreams and Pods fail to pull images when Dev Portal generated secret is added in the namespace 3.3. Building application images using source-to-image in OpenShift Follow the source-to-image (S2I) workflow to build reproducible container images for a JBoss EAP application. These generated container images include the application deployment and ready-to-run JBoss EAP servers. The S2I workflow takes source code from a Git repository and injects it into a container that's based on the language and framework you want to use. After the S2I workflow is completed, the src code is compiled, the application is packaged and is deployed to the JBoss EAP server. For more information, see Legacy server provisioning for JBoss EAP S2I . Note In JBoss EAP, you can use S2I images only if you develop your application using Jakarta EE 10. Prerequisites You have an active Red Hat customer account. You have a Registry Service Account. Follow the instructions on the Red Hat Customer Portal to create an authentication token using a registry service account . You have downloaded the OpenShift secret YAML file, which you can use to pull images from Red Hat Ecosystem Catalog. For more information, see OpenShift Secret . You used the oc login command to log in to OpenShift. You have installed Helm. For more information, see Installing Helm . You have installed the repository for the JBoss EAP Helm charts by entering this command in the management CLI: Procedure Create a file named helm.yaml using the following YAML content: Use the following command to deploy your JBoss EAP application on OpenShift. Verification Access the application using curl . You get the output Hello World! confirming that the application is deployed. 3.4. Deploying a third-party application on OpenShift You can create application images for OpenShift deployments by using compiled WAR files or EAR archives. Use a Dockerfile to deploy these archives onto JBoss EAP server, along with an updated and comprehensive runtime stack that includes the operating system, Java, and JBoss EAP components. Note Red Hat do not provide pre-built JBoss EAP server images. 3.4.1. Provisioning JBoss EAP servers with the default configuration You can install and configure a JBoss EAP server with its default configuration on OpenShift by using the builder image. For seamless deployment, follow the procedure to provision the server, transfer the application files, and make any necessary customization. Prerequisites You have access to the supported Red Hat JBoss Enterprise Application Platform container images. For example: registry.redhat.io/jboss-eap-8/eap8-openjdk17-builder-openshift-rhel8 registry.redhat.io/jboss-eap-8/eap8-openjdk17-runtime-openshift-rhel8 You have podman installed on your system. Use the latest podman version available on supported RHEL. For more information, see Red Hat JBoss Enterprise Application Platform 8.0 Supported Configurations . Procedure Copy the following Dockerfile contents as provided: # Use EAP 8 Builder image to create a JBoss EAP 8 server # with its default configuration FROM registry.redhat.io/jboss-eap-8/eap8-openjdk17-builder-openshift-rhel8:latest AS builder # Set up environment variables for provisioning. 1 ENV GALLEON_PROVISION_FEATURE_PACKS org.jboss.eap:wildfly-ee-galleon-pack,org.jboss.eap.cloud:eap-cloud-galleon-pack ENV GALLEON_PROVISION_LAYERS cloud-default-config # Specify the JBoss EAP version 2 ENV GALLEON_PROVISION_CHANNELS org.jboss.eap.channels:eap-8.0 # Run the assemble script to provision the server. RUN /usr/local/s2i/assemble # Copy the JBoss EAP 8 server from the builder image to the runtime image. FROM registry.redhat.io/jboss-eap-8/eap8-openjdk17-runtime-openshift-rhel8:latest AS runtime # Set appropriate ownership and permissions. COPY --from=builder --chown=jboss:root USDJBOSS_HOME USDJBOSS_HOME # Steps to add: # (1) COPY the WAR/EAR to USDJBOSS_HOME/standalone/deployments # with the jboss:root user. For example: # COPY --chown=jboss:root my-app.war USDJBOSS_HOME/standalone/deployments 3 # (2) (optional) server modification. You can modify EAP server configuration: # # * invoke management operations. For example # # RUN USDJBOSS_HOME/bin/jboss-cli.sh --commands="embed-server,/system-property=Foo:add(value=Bar)" # # First operation must always be embed-server. # # * copy a modified standalone.xml in USDJBOSS_HOME/standalone/configuration/ # for example # # COPY --chown=jboss:root standalone.xml USDJBOSS_HOME/standalone/configuration # Ensure appropriate permissions for the copied files. RUN chmod -R ug+rwX USDJBOSS_HOME 1 You can specify the MAVEN_MIRROR_URL environment variable, which is used by the JBoss EAP Maven plugin internally within the image. For more information, see Artifact repository mirrors . 2 You do not need to update this Dockerfile for any of the minor releases. Specify the JBoss EAP version in the GALLEON_PROVISION_CHANNELS environment variable if you want to use a specific version. For more information, see Environment variables . 3 Modify the copied Dockerfile to include your WAR file in the container. For example: COPY --chown=jboss:root <my-app.war> USDJBOSS_HOME/standalone/deployments Replace <myapp.war> with the path to the Web archive you want to add to the image. Build the application image using podman: USD podman build -t my-app . After the command is executed, the my-app container image is ready to be deployed on OpenShift. Upload your container image to one of the following options: Your internal registry that is accessible from OpenShift. The OpenShift registry by pushing the image directly from the machine where it was built. For more information, see How to push a container image into the image registry in RHOCP 4 . When deploying your image from the registry, use deployment strategies such as Helm charts, Operator, or Deployment. Select your preferred method and use either the full image URL or ImageStreams based on your requirements. For more information, see Using Helm charts to build and deploy JBoss EAP applications on OpenShift . 3.5. Using OpenID Connect to secure JBoss EAP applications on OpenShift Use the JBoss EAP native OpenID Connect (OIDC) client to delegate authentication using an external OpenID provider. OIDC is an identity layer that enables clients, such as JBoss EAP, to verify a user's identity based on the authentication performed by an OpenID provider. The elytron-oidc-client subsystem and elytron-oidc-client Galleon layer provides a native OIDC client in JBoss EAP to connect with OpenID providers. JBoss EAP automatically creates a virtual security domain for your application, based on your OpenID provider configurations. You can configure the elytron-oidc-client subsystem in three different ways: Adding an oidc.json into your deployment. Running a CLI script to configure the elytron-oidc-client subsystem. Defining environment variables to configure an elytron-oidc-client subsystem on start of JBoss EAP server on OpenShift. Note This procedure explains how you can configure an elytron-oidc-client subsystem using the environment variables to secure application with OIDC. 3.5.1. OpenID Connect configuration in JBoss EAP When you secure your applications using an OpenID provider, you do not need to configure any security domain resources locally. The elytron-oidc-client subsystem provides a native OpenID Connect (OIDC) client in JBoss EAP to connect with OpenID providers. JBoss EAP automatically creates a virtual security domain for your application, based on your OpenID provider configurations. Important Use the OIDC client with Red Hat build of Keycloak. You can use other OpenID providers if they can be configured to use access tokens that are JSON Web Tokens (JWTs) and can be configured to use the RS256, RS384, RS512, ES256, ES384, or ES512 signature algorithm. To enable the use of OIDC, you can configure either the elytron-oidc-client subsystem or an application itself. JBoss EAP activates the OIDC authentication as follows: When you deploy an application to JBoss EAP, the elytron-oidc-client subsystem scans the deployment to detect if the OIDC authentication mechanism is required. If the subsystem detects OIDC configuration for the deployment in either the elytron-oidc-client subsystem or the application deployment descriptor, JBoss EAP enables the OIDC authentication mechanism for the application. If the subsystem detects OIDC configuration in both places, the configuration in the elytron-oidc-client subsystem secure-deployment attribute takes precedence over the configuration in the application deployment descriptor. Additional resources OpenID Connect specification OpenID Connect Libraries Securing applications using OpenID Connect with Red Hat build of Keycloak 3.5.2. Creating an application secured with OpenID Connect For creating a web-application, create a Maven project with the required dependencies and the directory structure. Create a web application containing a servlet that returns the user name obtained from the logged-in user's principal and attributes. If there is no logged-in user, the servlet returns the text "NO AUTHENTICATED USER". Prerequisites You have installed Maven. For more information, see Downloading Apache Maven . Procedure Set up a Maven project using the mvn command. The command creates the directory structure for the project and the pom.xml configuration file. Syntax Example Navigate to the application root directory: Syntax Example Replace the content of the generated pom.xml file with the following text: <?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> <groupId>com.example.app</groupId> <artifactId>simple-webapp-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>simple-webapp-example Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.maven.war.plugin>3.3.2</version.maven.war.plugin> <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> <version.server>8.0.0.GA-redhat-00009</version.server> <version.bom.ee>USD{version.server}</version.bom.ee> </properties> <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee-with-tools</artifactId> <version>USD{version.bom.ee}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-auth-server</artifactId> </dependency> </dependencies> <build> <finalName>USD{project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>USD{version.maven.war.plugin}</version> </plugin> <plugin> <groupId>org.jboss.eap.plugins</groupId> <artifactId>eap-maven-plugin</artifactId> <version>USD{version.eap.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap:wildfly-ee-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap.cloud:eap-cloud-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</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> Note <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> is an example version of JBoss EAP Maven plugin. See the Red Hat Maven repository for more information on JBoss EAP Maven plugin releases: https://maven.repository.redhat.com/earlyaccess/all/org/jboss/eap/plugins/eap-maven-plugin/ . Create a directory to store the Java files. Syntax Example Navigate to the new directory. Syntax Example Create a file SecuredServlet.java with the following content: package com.example.app; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.authz.Attributes; import org.wildfly.security.authz.Attributes.Entry; /** * A simple secured HTTP servlet. It returns the user name and * attributes obtained from the logged-in user's Principal. If * there is no logged-in user, it returns the text * "NO AUTHENTICATED USER". */ @WebServlet("/secured") public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (PrintWriter writer = resp.getWriter()) { Principal user = req.getUserPrincipal(); SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity(); Attributes identityAttributes = identity.getAttributes(); Set <String> keys = identityAttributes.keySet(); String attributes = "<ul>"; for (String attr : keys) { attributes += "<li> " + attr + " : " + identityAttributes.get(attr).toString() + "</li>"; } attributes+="</ul>"; writer.println("<html>"); writer.println(" <head><title>Secured Servlet</title></head>"); writer.println(" <body>"); writer.println(" <h1>Secured Servlet</h1>"); writer.println(" <p>"); writer.print(" Current Principal '"); writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER"); writer.print("'"); writer.print(user != null ? "\n" + attributes : ""); writer.println(" </p>"); writer.println(" </body>"); writer.println("</html>"); } } } Configure the application's web.xml to protect the application resources. Example <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/secured</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Users</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>OIDC</auth-method> </login-config> <security-role> <role-name>*</role-name> </security-role> </web-app> In this example, only the users with the role Users can access the application. 3.5.3. Deploying the application on OpenShift As a JBoss EAP application developer, you can deploy your applications on OpenShift that uses the OpenID Connect subsystem and integrate it with a Red Hat build of Keycloak server. Deploy your application by following the procedures below. Prerequisites You have configured the Red Hat build of Keycloak server in your OpenShift with the following configuration. For more information, see Red Hat build of Keycloak Operator . Create a realm called JBossEAP . Create a user called demo . Set a password for the user called demo . Toggle Temporary to OFF and click Set Password . In the confirmation prompt, click Set password . Create a role called Users . Assign the role Users to the user demo . In the Client Roles field, select the realm-management you configured for JBoss EAP. Assign the role create-client to the client realm-management . Procedure Deploy your application code to Git Repository. Create a secret containing the OIDC configuration. Create a file named oidc-secret.yaml using the following content: Use the following command to create a secret: Create a file named helm.yaml using the following content: Deploy the example application using JBoss EAP Helm charts: Add the environment variables to the oidc-secret.yaml file to configure the OIDC provider URL and application hostname. The value for OIDC_HOSTNAME_HTTPS corresponds to the following output: The value for OIDC_PROVIDER_URL corresponds to the following output: A route discovery attempt is made if OIDC_HOSTNAME_HTTP(S) is not set. To enable route discovery, the OpenShift user must be able to list the route resources. For example, to create and associate the routeview role with the view user, use the following oc command: Update the secret with oc apply -f oidc-secret.yaml . Deploy the application again to ensure OpenShift uses the new environment variables: Verification In your browser, navigate to https://<eap-oidc-test-app route>/ . You will be redirected to Red Hat build of Keycloak login page. Access the secured servlet. Log in with the following credentials: A page appears that contains the Principal ID. 3.5.4. Environment variable based configuration Use these environment variables to configure JBoss EAP OIDC support on OpenShift image. Table 3.1. Environment Variables Environment variable Legacy SSO environment variable Description Required Default Value OIDC_PROVIDER_NAME NONE. When SSO_* environment variable are used, "rh-sso" name is internally set. You must set to rh-sso when using OIDC_PROVIDER_NAME variable. Yes OIDC_PROVIDER_URL USDSSO_URL/realms/USDSSO_REALM The URL of the provider. Yes OIDC_USER_NAME SSO_USERNAME Dynamic client registration requires the username to receive a token. Yes OIDC_USER_PASSWORD SSO_PASSWORD Dynamic client registration requires the user password to receive a token. Yes OIDC_SECURE_DEPLOYMENT_SECRET SSO_SECRET It is known to both the secure-deployment subsystem and the authentication server client. No OIDC_SECURE_DEPLOYMENT_PRINCIPAL_ATTRIBUTE SSO_PRINCIPAL_ATTRIBUTE Configure the value of the principal name. No Defaults to sub (ID token) for rh-sso . Typical value: preferred_username. OIDC_SECURE_DEPLOYMENT_ENABLE_CORS SSO_ENABLE_CORS Enable CORS for Single Sign-On applications. No Defaults to False . OIDC_SECURE_DEPLOYMENT_BEARER_ONLY SSO_BEARER_ONLY Deployment that accepts only bearer token and does not support logging. No Defaults to False . OIDC_PROVIDER_SSL_REQUIRED NONE Defaults to external, such as private and local address, but does not support https. No External OIDC_PROVIDER_TRUSTSTORE SSO_TRUSTSTORE Specify the realm trustore file. If it is not set, the adapter cannot use a trust manager when processing HTTPS requests. No OIDC_PROVIDER_TRUSTSTORE_DIR SSO_TRUSTSTORE_DIR Directory to find the realm truststore . If it is not set, the adapter cannot use a trust manager when processing HTTPS requests. No OIDC_PROVIDER_TRUSTSTORE_PASSWORD SSO_TRUSTSTORE_PASSWORD Specify the realm truststore password. If it is not set, the adapter cannot use a trust manager when processing HTTPS requests. No OIDC_PROVIDER_TRUSTSTORE_CERTIFICATE_ALIAS SSO_TRUSTSTORE_CERTIFICATE_ALIAS Specify the realm trustore alias. It is required to interact with the authentication server to register a client. No OIDC_DISABLE_SSL_CERTIFICATE_VALIDATION SSO_DISABLE_SSL_CERTIFICATE_VALIDATION Disable certificate validation when interacting with the authentication server to register a client. No OIDC_HOSTNAME_HTTP HOSTNAME_HTTP Hostname used for unsecure routes. No Routes are discovered. OIDC_HOSTNAME_HTTPS HOSTNAME_HTTPS Hostname used for secured routes. No Secured routes are discovered. NONE SSO_PUBLIC_KEY Public key of the Single Sign-On realm. This option is not used, public key is automatically retrieved by the OIDC subsystem. No If set, a warning is displayed that this option is being ignored. 3.6. Securing applications by using SAML The Security Assertion Markup Language (SAML) serves as a data format and protocol that enables the exchange of authentication and authorization information between two parties. These two parties typically include an identity provider and a service provider. This information takes the form of SAML tokens containing assertions. Identity providers issue these SAML tokens to subjects to enable these subjects to authenticate with service providers. Subjects can reuse SAML tokens with multiple service providers, which enables browser-based Single Sign-On in SAML v2. You can secure web applications by using the Galleon layers that the Keycloak SAML adapter feature pack provides. For information about the Keycloak SAML adapter feature pack, see Keycloak SAML adapter feature pack for securing applications by using SAML . 3.6.1. Keycloak SAML adapter feature pack for securing applications by using SAML Keycloak SAML adapter Galleon pack is a Galleon feature pack that includes the keycloak-saml layer. Use the keycloak-saml layer in the feature pack to install the necessary modules and configurations in JBoss EAP. These modules and configurations are required if you want to use Red Hat build of Keycloak as an identity provider for Single Sign-On (SSO) when using SAML. When using the keycloak-saml SAML adapter Galleon layer for source-to-image (S2I), you can optionally use the SAML client feature that enables automatic registration with an Identity Service Provider (IDP), such as Red Hat build of Keycloak. 3.6.2. Configuring Red Hat build of Keycloak as SAML provider for OpenShift Red Hat build of Keycloak is an identity and access management provider for securing web applications with Single Sign-On (SSO). It supports OpenID Connect, which is an extension to OAuth 2.0, and SAML. The following procedure outlines the essential steps needed to secure applications with SAML. For more information, see Red Hat build of Keycloak documentation . Prerequisites You have administrator access to Red Hat build of Keycloak. Red Hat build of Keycloak is running. For more information, see Red Hat build of Keycloak Operator . You used the oc login command to log in to OpenShift. Procedure Create a Single Sign-On realm, users, and roles . Generate the key and certificate by using the Java keytool command: keytool -genkeypair -alias saml-app -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -storepass password -dname "CN=saml-basic-auth,OU=EAP SAML Client,O=Red Hat EAP QE,L=MB,S=Milan,C=IT" -ext ku:c=dig,keyEncipherment -validity 365 Import the keystore into a Java KeyStore (JKS) format: keytool -importkeystore -deststorepass password -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass password Create a secret in OpenShift for the keystore: USD oc create secret generic saml-app-secret --from-file=keystore.jks=./keystore.jks --type=opaque Note These steps are only necessary when using the automatic SAML client registration feature. When JBoss EAP registers a new SAML client into Red Hat build of Keycloak as the client-admin user, JBoss EAP must store the certificate of the new SAML client in the Red Hat build of Keycloak client configuration. This allows JBoss EAP to retain the private key while only storing the public certificate in Red Hat build of Keycloak, which establishes an authenticated client for communication with Red Hat build of Keycloak. 3.6.3. Creating an application secured with SAML You can enhance web application security by using the Security Assertion Markup Language (SAML). SAML provides effective user authentication and authorization, along with Single Sign-On (SSO) capabilities, making it a dependable choice for strengthening web applications. Prerequisites You have installed Maven. For more information, see Downloading Apache Maven . Procedure Set up a Maven project by using the mvn command. This command creates both the directory structure for the project and the pom.xml configuration file. Syntax Example Navigate to the application root directory: Syntax Example Replace the content of the generated pom.xml file with the following text: <?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> <groupId>com.example.app</groupId> <artifactId>simple-webapp-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>simple-webapp-example Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.maven.war.plugin>3.3.2</version.maven.war.plugin> <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> <version.server>8.0.0.GA-redhat-00009</version.server> <version.bom.ee>USD{version.server}</version.bom.ee> </properties> <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee-with-tools</artifactId> <version>USD{version.bom.ee}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-auth-server</artifactId> </dependency> </dependencies> <build> <finalName>USD{project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>USD{version.maven.war.plugin}</version> </plugin> <plugin> <groupId>org.jboss.eap.plugins</groupId> <artifactId>eap-maven-plugin</artifactId> <version>USD{version.eap.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap:wildfly-ee-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap.cloud:eap-cloud-galleon-pack</location> </feature-pack> <feature-pack> <location>org.keycloak:keycloak-saml-adapter-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</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> Note <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> is an example version of JBoss EAP Maven plugin. See the Red Hat Maven repository for more information on JBoss EAP Maven plugin releases: https://maven.repository.redhat.com/earlyaccess/all/org/jboss/eap/plugins/eap-maven-plugin/ . Create a directory to store the Java files. Syntax Example Navigate to the new directory. Syntax Example Create a file named SecuredServlet.java that contains the following settings: package com.example.app; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.util.Set; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.authz.Attributes; /** * A simple secured HTTP servlet. It returns the user name and * attributes obtained from the logged-in user's Principal. If * there is no logged-in user, it returns the text * "NO AUTHENTICATED USER". */ @WebServlet("/secured") public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (PrintWriter writer = resp.getWriter()) { Principal user = req.getUserPrincipal(); SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity(); Attributes identityAttributes = identity.getAttributes(); Set <String> keys = identityAttributes.keySet(); String attributes = "<ul>"; for (String attr : keys) { attributes += "<li> " + attr + " : " + identityAttributes.get(attr).toString() + "</li>"; } attributes+="</ul>"; writer.println("<html>"); writer.println(" <head><title>Secured Servlet</title></head>"); writer.println(" <body>"); writer.println(" <h1>Secured Servlet</h1>"); writer.println(" <p>"); writer.print(" Current Principal '"); writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER"); writer.print("'"); writer.print(user != null ? "\n" + attributes : ""); writer.println(" </p>"); writer.println(" </body>"); writer.println("</html>"); } } } Create the directory structure for the web.xml file: Configure the application's web.xml file to protect the application resources. Example <?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/secured</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>KEYCLOAK-SAML</auth-method> </login-config> <security-role> <role-name>user</role-name> </security-role> </web-app> In this example, only users with the user role can access the application. Verification After creating the application, commit it to a remote Git repository. Create a Git repository such as https://github.com/your-username/simple-webapp-example . For more information about remote repositories and Git, see Getting started with Git - About remote repositories . From the root folder of the application, run the following Git commands: git init -b main git add pom.xml src git commit -m "First commit" git remote add origin git@github.com:your-username/simple-webapp-example.git git remote -v git push -u origin main These steps commit your application to the remote repository, making it accessible online. 3.6.4. Building and deploying a SAML-secured application on OpenShift You can build and deploy your application secured with SAML on OpenShift by using the JBoss EAP and Single Sign-On (SSO) Galleon layers. Prerequisites You have installed Helm. For more information, see Installing Helm . You have created the SAML application project and made it accessible in a Git repository. You have installed the repository for the JBoss EAP Helm charts by entering this command in the management CLI: USD helm repo add jboss-eap https://jbossas.github.io/eap-charts/ Procedure Deploy your application code to the Git Repository. Create an OpenShift secret containing the required environment variables: apiVersion: v1 kind: Secret metadata: name: saml-secret type: Opaque stringData: SSO_REALM: "saml-basic-auth" SSO_USERNAME: "client-admin" SSO_PASSWORD: "client-admin" SSO_SAML_CERTIFICATE_NAME: "saml-app" SSO_SAML_KEYSTORE: "keystore.jks" SSO_SAML_KEYSTORE_PASSWORD: "password" SSO_SAML_KEYSTORE_DIR: "/etc/sso-saml-secret-volume" SSO_SAML_LOGOUT_PAGE: "/simple-webapp-example" SSO_DISABLE_SSL_CERTIFICATE_VALIDATION: "true" Save the provided YAML content to a file, such as saml-secret.yaml . Apply the saved YAML file by using the following command: oc apply -f saml-secret.yaml Create a file named helm.yaml that contains the following settings: build: uri: [WEB ADDRESS TO YOUR GIT REPOSITORY] deploy: volumes: - name: saml-keystore-volume secret: secretName: saml-app-secret volumeMounts: - name: saml-keystore-volume mountPath: /etc/sso-saml-secret-volume readOnly: true envFrom: - secretRef: name: saml-secret Note Specify the web address in the HTTP format, such as http://www.redhat.com . If you are using a maven mirror, specify the web address as follows: build: uri: [WEB ADDRESS TO YOUR GIT REPOSITORY] env: - name: "MAVEN_MIRROR_URL" value: "http://..." Deploy the example application by using JBoss EAP Helm charts: USD helm install saml-app -f helm.yaml jboss-eap/eap8 Add the environment variables to the saml-secret.yaml file to configure the Keycloak server URL and application route: stringData: ... HOSTNAME_HTTPS: <saml-app application route> SSO_URL: https://<host of the Keycloak server> Replace <saml-app application route> and <host of the Keycloak server> with the appropriate values. The value for HOSTNAME_HTTPS corresponds to the following output: echo USD(oc get route saml-app --template='{{ .spec.host }}') The value for SSO_URL corresponds to the following output: echo https://USD(oc get route sso --template='{{ .spec.host }}') Note If you cannot use this command, use oc get routes to list the available routes and select the route to your Red Hat build of Keycloak instance. Update the secret with oc apply -f saml-secret.yaml . Verification Deploy the application again to ensure that OpenShift uses the new environment variables: USD oc rollout restart deploy saml-app In a browser, navigate to the application URL. For example, https://<saml-app route>/simple-webapp-example . You are redirected to the Red Hat build of Keycloak login page. To get the web address, use the following command to access the secured servlet: echo https://USD(oc get route saml-app --template='{{ .spec.host }}')/simple-webapp-example/secured Log in with the following credentials: username: demo password: demo A page is displayed that contains the Principal ID. Your application is now secured using SAML. 3.6.5. Creating a SSO realm, users, and roles You can configure a Single Sign-On (SSO) realm, define user roles, and manage access control in your Red Hat build of Keycloak environment. These actions enable you to enhance security and simplify user access management, ensuring a streamlined authentication experience. This is essential for optimizing your SSO setup and improving user authentication processes. Prerequisites You have administrator access to Red Hat build of Keycloak. Red Hat build of Keycloak is running. Procedure Log in to the Red Hat build of Keycloak admin console using the URL: https://<SSO route>/ . Create a realm in Red Hat build of Keycloak; for example, saml-basic-auth . You can subsequently use this realm to create the required users, roles, and a client. For more information, see Creating a realm . Create a role within the saml-basic-auth realm. For example, user . For more information, see Creating a realm role . Create a user. For example, demo . For more information, see Creating users . Create a password for the user. For example, demo . Ensure that the password is not temporary. For more information, see Setting a password for a user . Assign the user role to the demo user for login access. For more information, see Assigning role mappings . Create a user. For example, client-admin . To create the SAML client in the Keycloak server when the JBoss EAP server starts, you can use the client-admin user, which requires additional privileges. For more information, see Creating users . Create a password for the user. For example, client-admin . Ensure that the password is not temporary. For more information, see Setting a password for a user . Select realm-management from the Client Roles drop down list. Assign the roles create-client , manage-clients , and manage-realm to the client-admin user. For more information, see Assigning role mappings . 3.6.6. Environment variables for configuring the SAML subsystem You can optimize the integration of the Keycloak server within your environment by understanding and using the following variables. This ensures a seamless and secure Keycloak setup for your application. Table 3.2. Environment variables Environment variable Description Required APPLICATION_NAME Used as a prefix for the client name, derived from the deployment name. Optional HOSTNAME_HTTP Custom hostname for the HTTP OpenShift route. If not set, route discovery is performed. Optional HOSTNAME_HTTPS Custom hostname for the HTTPS OpenShift route. If not set, route discovery is performed. Optional SSO_DISABLE_SSL_CERTIFICATE_VALIDATION Choose between true or false to enable or disable validation of the Keycloak server certificate. Consider setting this to true when the SSO server generates a self-signed certificate. Optional SSO_PASSWORD The password for a user with privileges to interact with the Keycloak realm and to create and register clients. For example, client-admin . True SSO_REALM The SSO realm for associating application clients. For example, saml-basic-auth . Optional SSO_SAML_CERTIFICATE_NAME Alias of private key and certificate in the SAML client keystore. For example, saml-app . True SSO_SAML_KEYSTORE Name of the keystore file. For example, keystore.jks . True SSO_SAML_KEYSTORE_DIR Directory that contains the client keystore. For example, /etc/sso-saml-secret-volume . True SSO_SAML_KEYSTORE_PASSWORD Keystore password. For example, password . True SSO_SAML_LOGOUT_PAGE Logout page. For example, simple-webapp-example . True SSO_SAML_VALIDATE_SIGNATURE Specify true to validate the signature or false to not validate it. True by default. Optional SSO_SECURITY_DOMAIN The name of the security domain used to secure undertow and ejb subsystems. The default is keycloak . Optional SSO_TRUSTSTORE The truststore file name containing the server certificate. Optional SSO_TRUSTSTORE_CERTIFICATE_ALIAS Certificate alias within the truststore. Optional SSO_TRUSTSTORE_DIR Directory that contains the truststore. Optional SSO_TRUSTSTORE_PASSWORD The password for the truststore and certificate . For example, mykeystorepass . Optional SSO_URL The URL for the SSO server. For example, <SSO server accessible route> . True SSO_USERNAME The username of a user with privileges to interact with the Keycloak realm and to create and register clients. For example, client-admin . True 3.6.7. Route discovery in JBoss EAP server You can optimize your server's performance and simplify route configurations in your specified namespace by using the route discovery feature in the JBoss EAP server. This feature is essential for improving server efficiency to provide a smoother operational experience, particularly when the HOSTNAME_HTTPS variable is unspecified. If the HOSTNAME_HTTPS variable is not set, the JBoss EAP server automatically attempts route discovery. To enable route discovery, you must create the required permissions: oc create role routeview --verb=list --resource=route -n YOUR_NAME_SPACE oc policy add-role-to-user routeview system:serviceaccount:YOUR_NAME_SPACE:default --role-namespace=YOUR_NAME_SPACE -n YOUR_NAME_SPACE 3.6.8. Additional resources Red Hat build of Keycloak Server Administration Guide 3.7. Additional resources OpenShift Container Platform Getting Started

Commands:
oc new-project <project_name>
oc new-project eap-demo
keytool -genkey -keyalg RSA -alias <alias_name> -keystore <keystore_filename.jks> -validity 360 -keysize 2048
keytool -genkey -keyalg RSA -alias eapdemo-selfsigned -keystore keystore.jks -validity 360 -keysize 2048
oc create secret generic <secret_name> --from-file= <keystore_filename.jks>
oc create secret generic eap-app-secret --from-file=keystore.jks
helm repo add jboss-eap https://jbossas.github.io/eap-charts/
build: uri: https://github.com/jboss-developer/jboss-eap-quickstarts.git ref: EAP_8.0.0.GA contextDir: helloworld deploy: replicas: 1
helm install helloworld -f helm.yaml jboss-eap/eap8
curl https://USD(oc get route helloworld --template='{{ .spec.host }}')/HelloWorld
Use EAP 8 Builder image to create a JBoss EAP 8 server with its default configuration FROM registry.redhat.io/jboss-eap-8/eap8-openjdk17-builder-openshift-rhel8:latest AS builder Set up environment variables for provisioning. 1 ENV GALLEON_PROVISION_FEATURE_PACKS org.jboss.eap:wildfly-ee-galleon-pack,org.jboss.eap.cloud:eap-cloud-galleon-pack ENV GALLEON_PROVISION_LAYERS cloud-default-config Specify the JBoss EAP version 2 ENV GALLEON_PROVISION_CHANNELS org.jboss.eap.channels:eap-8.0 Run the assemble script to provision the server. RUN /usr/local/s2i/assemble Copy the JBoss EAP 8 server from the builder image to the runtime image. FROM registry.redhat.io/jboss-eap-8/eap8-openjdk17-runtime-openshift-rhel8:latest AS runtime Set appropriate ownership and permissions. COPY --from=builder --chown=jboss:root USDJBOSS_HOME USDJBOSS_HOME Steps to add: (1) COPY the WAR/EAR to USDJBOSS_HOME/standalone/deployments with the jboss:root user. For example: COPY --chown=jboss:root my-app.war USDJBOSS_HOME/standalone/deployments 3 (2) (optional) server modification. You can modify EAP server configuration: # * invoke management operations. For example # RUN USDJBOSS_HOME/bin/jboss-cli.sh --commands="embed-server,/system-property=Foo:add(value=Bar)" # First operation must always be embed-server. # * copy a modified standalone.xml in USDJBOSS_HOME/standalone/configuration/ for example # COPY --chown=jboss:root standalone.xml USDJBOSS_HOME/standalone/configuration Ensure appropriate permissions for the copied files. RUN chmod -R ug+rwX USDJBOSS_HOME
COPY --chown=jboss:root <my-app.war> USDJBOSS_HOME/standalone/deployments
podman build -t my-app .
mvn archetype:generate -DgroupId= USD{group-to-which-your-application-belongs} -DartifactId= USD{name-of-your-application} -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.example.app -DartifactId=simple-webapp-example -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
cd <name-of-your-application>
cd simple-webapp-example
<?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> <groupId>com.example.app</groupId> <artifactId>simple-webapp-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>simple-webapp-example Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.maven.war.plugin>3.3.2</version.maven.war.plugin> <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> <version.server>8.0.0.GA-redhat-00009</version.server> <version.bom.ee>USD{version.server}</version.bom.ee> </properties> <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee-with-tools</artifactId> <version>USD{version.bom.ee}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-auth-server</artifactId> </dependency> </dependencies> <build> <finalName>USD{project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>USD{version.maven.war.plugin}</version> </plugin> <plugin> <groupId>org.jboss.eap.plugins</groupId> <artifactId>eap-maven-plugin</artifactId> <version>USD{version.eap.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap:wildfly-ee-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap.cloud:eap-cloud-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</layer> <layer>elytron-oidc-client</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>
mkdir -p src/main/java/<path_based_on_artifactID>
mkdir -p src/main/java/com/example/app
cd src/main/java/<path_based_on_artifactID>
cd src/main/java/com/example/app
package com.example.app; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.authz.Attributes; import org.wildfly.security.authz.Attributes.Entry; /** * A simple secured HTTP servlet. It returns the user name and * attributes obtained from the logged-in user's Principal. If * there is no logged-in user, it returns the text * "NO AUTHENTICATED USER". */ @WebServlet("/secured") public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (PrintWriter writer = resp.getWriter()) { Principal user = req.getUserPrincipal(); SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity(); Attributes identityAttributes = identity.getAttributes(); Set <String> keys = identityAttributes.keySet(); String attributes = "<ul>"; for (String attr : keys) { attributes += "<li> " + attr + " : " + identityAttributes.get(attr).toString() + "</li>"; } attributes+="</ul>"; writer.println("<html>"); writer.println(" <head><title>Secured Servlet</title></head>"); writer.println(" <body>"); writer.println(" <h1>Secured Servlet</h1>"); writer.println(" <p>"); writer.print(" Current Principal '"); writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER"); writer.print("'"); writer.print(user != null ? "\n" + attributes : ""); writer.println(" </p>"); writer.println(" </body>"); writer.println("</html>"); } } }
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/secured</url-pattern> </web-resource-collection> <auth-constraint> <role-name>Users</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>OIDC</auth-method> </login-config> <security-role> <role-name>*</role-name> </security-role> </web-app>
apiVersion: v1 kind: Secret metadata: name: oidc-secret type: Opaque stringData: OIDC_PROVIDER_NAME: rh-sso OIDC_USER_NAME: demo OIDC_USER_PASSWORD: demo OIDC_SECURE_DEPLOYMENT_SECRET: mysecret
oc apply -f oidc-secret.yaml
build: uri: [URL TO YOUR GIT REPOSITORY] deploy: envFrom: - secretRef: name: oidc-secret
helm install eap-oidc-test-app -f helm.yaml jboss-eap/eap8
yaml stringData: OIDC_HOSTNAME_HTTPS: <host of the application> OIDC_PROVIDER_URL: https://<host of the SSO provider>/realms/JBossEAP
echo USD(oc get route eap-oidc-test-app --template='{{ .spec.host }}')
echo https://USD(oc get route sso --template='{{ .spec.host }}')/realms/JBossEAP
oc create role <role-name> --verb=list --resource=route oc adm policy add-role-to-user <role-name> <user-name> --role-namespace=<your namespace>
oc rollout restart deploy eap-oidc-test-app
username: demo password: demo
keytool -genkeypair -alias saml-app -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -storepass password -dname "CN=saml-basic-auth,OU=EAP SAML Client,O=Red Hat EAP QE,L=MB,S=Milan,C=IT" -ext ku:c=dig,keyEncipherment -validity 365
keytool -importkeystore -deststorepass password -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass password
oc create secret generic saml-app-secret --from-file=keystore.jks=./keystore.jks --type=opaque
mvn archetype:generate -DgroupId= USD{group-to-which-your-application-belongs} -DartifactId= USD{name-of-your-application} -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
mvn archetype:generate -DgroupId=com.example.app -DartifactId=simple-webapp-example -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
cd <name-of-your-application>
cd simple-webapp-example
<?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> <groupId>com.example.app</groupId> <artifactId>simple-webapp-example</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>simple-webapp-example Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <version.maven.war.plugin>3.3.2</version.maven.war.plugin> <version.eap.plugin>1.0.0.Final-redhat-00014</version.eap.plugin> <version.server>8.0.0.GA-redhat-00009</version.server> <version.bom.ee>USD{version.server}</version.bom.ee> </properties> <repositories> <repository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>jboss</id> <url>https://maven.repository.redhat.com/ga/</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> <dependencyManagement> <dependencies> <dependency> <groupId>org.jboss.bom</groupId> <artifactId>jboss-eap-ee-with-tools</artifactId> <version>USD{version.bom.ee}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.wildfly.security</groupId> <artifactId>wildfly-elytron-auth-server</artifactId> </dependency> </dependencies> <build> <finalName>USD{project.artifactId}</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>USD{version.maven.war.plugin}</version> </plugin> <plugin> <groupId>org.jboss.eap.plugins</groupId> <artifactId>eap-maven-plugin</artifactId> <version>USD{version.eap.plugin}</version> <configuration> <channels> <channel> <manifest> <groupId>org.jboss.eap.channels</groupId> <artifactId>eap-8.0</artifactId> </manifest> </channel> </channels> <feature-packs> <feature-pack> <location>org.jboss.eap:wildfly-ee-galleon-pack</location> </feature-pack> <feature-pack> <location>org.jboss.eap.cloud:eap-cloud-galleon-pack</location> </feature-pack> <feature-pack> <location>org.keycloak:keycloak-saml-adapter-galleon-pack</location> </feature-pack> </feature-packs> <layers> <layer>cloud-server</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>
mkdir -p src/main/java/<path_based_on_artifactID>
mkdir -p src/main/java/com/example/app
cd src/main/java/<path_based_on_artifactID>
cd src/main/java/com/example/app
package com.example.app; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.util.Set; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.wildfly.security.auth.server.SecurityDomain; import org.wildfly.security.auth.server.SecurityIdentity; import org.wildfly.security.authz.Attributes; /** * A simple secured HTTP servlet. It returns the user name and * attributes obtained from the logged-in user's Principal. If * there is no logged-in user, it returns the text * "NO AUTHENTICATED USER". */ @WebServlet("/secured") public class SecuredServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try (PrintWriter writer = resp.getWriter()) { Principal user = req.getUserPrincipal(); SecurityIdentity identity = SecurityDomain.getCurrent().getCurrentSecurityIdentity(); Attributes identityAttributes = identity.getAttributes(); Set <String> keys = identityAttributes.keySet(); String attributes = "<ul>"; for (String attr : keys) { attributes += "<li> " + attr + " : " + identityAttributes.get(attr).toString() + "</li>"; } attributes+="</ul>"; writer.println("<html>"); writer.println(" <head><title>Secured Servlet</title></head>"); writer.println(" <body>"); writer.println(" <h1>Secured Servlet</h1>"); writer.println(" <p>"); writer.print(" Current Principal '"); writer.print(user != null ? user.getName() : "NO AUTHENTICATED USER"); writer.print("'"); writer.print(user != null ? "\n" + attributes : ""); writer.println(" </p>"); writer.println(" </body>"); writer.println("</html>"); } } }
mkdir -p src/main/webapp/WEB-INF cd src/main/webapp/WEB-INF
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" metadata-complete="false"> <security-constraint> <web-resource-collection> <web-resource-name>secured</web-resource-name> <url-pattern>/secured</url-pattern> </web-resource-collection> <auth-constraint> <role-name>user</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>KEYCLOAK-SAML</auth-method> </login-config> <security-role> <role-name>user</role-name> </security-role> </web-app>
git init -b main git add pom.xml src git commit -m "First commit" git remote add origin git@github.com:your-username/simple-webapp-example.git git remote -v git push -u origin main
helm repo add jboss-eap https://jbossas.github.io/eap-charts/
apiVersion: v1 kind: Secret metadata: name: saml-secret type: Opaque stringData: SSO_REALM: "saml-basic-auth" SSO_USERNAME: "client-admin" SSO_PASSWORD: "client-admin" SSO_SAML_CERTIFICATE_NAME: "saml-app" SSO_SAML_KEYSTORE: "keystore.jks" SSO_SAML_KEYSTORE_PASSWORD: "password" SSO_SAML_KEYSTORE_DIR: "/etc/sso-saml-secret-volume" SSO_SAML_LOGOUT_PAGE: "/simple-webapp-example" SSO_DISABLE_SSL_CERTIFICATE_VALIDATION: "true"
apply -f saml-secret.yaml
build: uri: [WEB ADDRESS TO YOUR GIT REPOSITORY] deploy: volumes: - name: saml-keystore-volume secret: secretName: saml-app-secret volumeMounts: - name: saml-keystore-volume mountPath: /etc/sso-saml-secret-volume readOnly: true envFrom: - secretRef: name: saml-secret
build: uri: [WEB ADDRESS TO YOUR GIT REPOSITORY] env: - name: "MAVEN_MIRROR_URL" value: "http://..."
helm install saml-app -f helm.yaml jboss-eap/eap8
stringData: HOSTNAME_HTTPS: <saml-app application route> SSO_URL: https://<host of the Keycloak server>
echo USD(oc get route saml-app --template='{{ .spec.host }}')
echo https://USD(oc get route sso --template='{{ .spec.host }}')
oc rollout restart deploy saml-app
echo https://USD(oc get route saml-app --template='{{ .spec.host }}')/simple-webapp-example/secured
username: demo password: demo
create role routeview --verb=list --resource=route -n YOUR_NAME_SPACE policy add-role-to-user routeview system:serviceaccount:YOUR_NAME_SPACE:default --role-namespace=YOUR_NAME_SPACE -n YOUR_NAME_SPACE