Chapter 2. 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.

2.1. Prerequisites

  • You have an OpenShift instance installed and operational.

2.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-beta kitchensink quickstart for more information. Deploy your application by following the procedures below.

Procedure

  1. Log in to your OpenShift instance using the oc login command.
  2. 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.

    $ oc new-project <project_name>

    For example, for the kitchensink quickstart, create a project named eap-demo using the following command:

    $ oc new-project eap-demo
  3. 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; for example, the eap74-https-s2i template. The kitchensink quickstart example does not use an HTTPS template, so it doesn’t require a keystore and secret.

    1. 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).

      $ keytool -genkey -keyalg RSA -alias <alias_name> -keystore <keystore_filename.jks> -validity 360 -keysize 2048

      For example, for the kitchensink quickstart, use the following command to generate a keystore:

      $ keytool -genkey -keyalg RSA -alias eapdemo-selfsigned -keystore keystore.jks -validity 360 -keysize 2048
    2. Use the following command to create a secret from your new keystore:

      $ oc create secret generic <secret_name> --from-file=<keystore_filename.jks>

      For example, for the kitchensink quickstart, use the following command to create a secret:

      $ oc create secret generic eap-app-secret --from-file=keystore.jks

2.3. Configure authentication to the Red Hat Container Registry

Before you can import and use the JBoss EAP for OpenShift image, you must first configure authentication to the Red Hat Container Registry.

Red Hat recommends that you create an authentication token using a registry service account to configure access to the Red Hat Container Registry. This means that you don’t have to use or store your Red Hat account’s username and password in your OpenShift configuration.

Procedure

  1. Follow the instructions on Red Hat Customer Portal to create an authentication token using a registry service account.
  2. Download the YAML file containing the OpenShift secret for the token. You can download the YAML file from the OpenShift Secret tab on your token’s Token Information page.
  3. Create the authentication token secret for your OpenShift project using the YAML file that you downloaded:

    oc create -f 1234567_myserviceaccount-secret.yaml
  4. Configure the secret for your OpenShift project using the following commands, replacing the secret name in the example with the name of your secret created in the previous step.

    oc secrets link default 1234567-myserviceaccount-pull-secret --for=pull
    oc secrets link builder 1234567-myserviceaccount-pull-secret --for=pull
Note

If your OCP cluster is managed by Red Hat, For example, dev-sandbox the authentication secret is setup automatically.

See the OpenShift documentation for more information on other methods for configuring access to secured registries.

See the Red Hat Customer Portal for more information on configuring authentication to the Red Hat Container Registry.

2.4. 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:

    $ helm repo add jboss-eap https://jbossas.github.io/eap-charts/

Procedure

  1. Create a file named helm.yaml using the following YAML content:

    build:
      url: https://github.com/jboss-developer/jboss-eap-quickstarts.git
      ref: EAP_8.0.0.Beta
      contextDir: helloworld
    deploy:
      replicas: 1
  2. Use the following command to deploy your JBoss EAP application on OpenShift.

    $ helm install helloworld -f helm.yaml jboss-eap/eap8

Verification

  • Access the application using curl.

    $ curl https://$(oc get route helloworld --template='{{ .spec.host }}')/HelloWorld

    You get the output Hello World! confirming that the application is deployed.

2.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.

2.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 Single Sign-On. 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.

2.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

Procedure

  1. 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

    $ mvn archetype:generate \
    -DgroupId=${group-to-which-your-application-belongs} \
    -DartifactId=${name-of-your-application} \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp \
    -DinteractiveMode=false

    Example

    $ mvn archetype:generate \
    -DgroupId=com.example.app \
    -DartifactId=simple-webapp-example \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp \
    -DinteractiveMode=false

  2. Navigate to the application root directory:

    Syntax

    $ cd <name-of-your-application>

    Example

    $ cd simple-webapp-example

  3. 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>
        <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.Beta-redhat-00001</version.eap.plugin>
      </properties>
    
      <repositories>
        <repository>
            <id>jboss</id>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
            <id>jboss</id>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
      </pluginRepositories>
    
      <dependencies>
        <dependency>
          <groupId>jakarta.servlet</groupId>
          <artifactId>jakarta.servlet-api</artifactId>
          <version>6.0.0</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.wildfly.security</groupId>
          <artifactId>wildfly-elytron-auth-server</artifactId>
          <version>1.19.0.Final</version>
        </dependency>
      </dependencies>
    
    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>${version.maven.war.plugin}</version>
            </plugin>
            <plugin>
                <groupId>org.jboss.eap.plugins</groupId>
                <artifactId>eap-maven-plugin</artifactId>
                <version>${version.eap.plugin}</version>
                <configuration>
                    <channels>
                        <channel>
                            <groupId>org.jboss.eap.channels</groupId>
                            <artifactId>eap-8.0-beta</artifactId>
                        </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>
  4. Create a directory to store the Java files.

    Syntax

    $ mkdir -p src/main/java/<path_based_on_artifactID>

    Example

    $ mkdir -p src/main/java/com/example/app

  5. Navigate to the new directory.

    Syntax

    $ cd src/main/java/<path_based_on_artifactID>

    Example

    $ cd src/main/java/com/example/app

  6. 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>");
            }
        }
    
    }
  7. 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.

2.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 Single Sign-On server. Deploy your application by following the procedures below.

Prerequisites

You have configured the Red Hat Single Sign-On server in your OpenShift with the following configuration. For more information, see Red Hat Single Sign-On 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

  1. Deploy your application code to Git Repository.
  2. Create a secret containing the OIDC configuration.

    1. Create a file named oidc-secret.yaml using the following content:

      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
    2. Use the following command to create a secret:

      $ oc apply -f oidc-secret.yaml
  3. Create a file named helm.yaml using the following content:

    build:
      uri: [URL TO YOUR GIT REPOSITORY]
    deploy:
      envFrom:
    	- secretRef:
        	  name: oidc-secret
  4. Deploy the example application using JBoss EAP Helm charts:

    $ helm install eap-oidc-test-app -f helm.yaml jboss-eap/eap8
  5. Add the environment variables to the oidc-secret.yaml file to configure the OIDC provider URL and application hostname.

    yaml
    stringData:
      ...
      OIDC_HOSTNAME_HTTPS: <host of the application>
      OIDC_PROVIDER_URL: https://<host of the SSO provider>/auths/realms/JBossEAP

    The value for OIDC_HOSTNAME_HTTPS corresponds to the following output:

    echo $(oc get route eap-oidc-test-app --template='{{ .spec.host }}')

    The value for OIDC_PROVIDER_URL corresponds to the following output:

    echo https://$(oc get route sso --template='{{ .spec.host }}')/auth/realms/JBossEAP

    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:

    $ oc create role <role-name> --verb=list --resource=route
    
    $ oc adm policy add-role-to-user <role-name> <user-name> --role-namespace=<your namespace>
  6. Update the secret with oc apply -f oidc-secret.yaml.
  7. Deploy the application again to ensure OpenShift uses the new environment variables:

    $ oc rollout restart deploy eap-oidc-test-app

Verification

  1. In your browser, navigate to https://<eap-oidc-test-app route>/.

    You will be redirected to Red Hat Single Sign-On login page.

  2. Access the secured servlet.
  3. Log in with the following credentials:

    username: demo
    password: demo

    A page appears that contains the Principal ID.

Additional resources

2.5.4. Environment variable based configuration

Use these environment variables to configure JBoss EAP OIDC support on OpenShift image.

Table 2.1. Environment Variables

Environment variableLegacy SSO environment variableDescriptionRequiredDefault 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

$SSO_URL/realms/$SSO_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.

2.6. Additional resources