WildFly Elytron

Trying Out An Upcoming Security Feature for WildFly on OpenShift

A future release of WildFly will include the ability to add additional scope values when securing applications using OpenID Connect (OIDC). This blog post demonstrates how to secure a WildFly application using OpenID Connect and configure scope values to request additional claims using an in-progress version of the feature. This feature adds the ability to specify additional scope values in the authentication request for applications secured using OIDC. For updates on the status of the feature, please keep an eye on WFLY-16532. We will also walk through how to deploy this feature on the cloud using OpenShift.

OpenID Connect

OpenID Connect is an identity layer on top of the OAuth 2.0 protocol that makes it possible for a client to verify a user’s identity based on authentication that’s performed by an OpenID provider. A future release of WildFly will allow the user to configure additional scope values to request specific claim values.

Prerequisites

We can deploy this application using OpenShift Developer Sandbox. There are other options available for running OpenShift. Please refer to this getting started guide to learn more about WildFly on OpenShift. We will be making use of the following tools for this walkthrough:

Example Application

For this walkthrough, we will be making use of the elytron-oidc-client-scope project which makes use of the ability to configure additional scope values for OpenID Connect. First, clone the elytron-examples repo locally and navigate to the elytron-oidc-client-scope directory:

git clone https://github.com/prarthonapaul/elytron-examples
git checkout elytron-oidc-client-scope
cd PATH/TO/elytron-examples/elytron-oidc-client-scope

Log Into the OpenShift Cluster

Before we can deploy our application, we need to log into an OpenShift cluster. You can log in via the OpenShift CLI:

oc login -u myUserName

Alternatively, to log in using the API token, navigate to Developer Sandbox, click on your username at the top right corner, and click on Copy login command. It will redirect you to a page where you can copy your login command and paste it on your terminal. The command will be in this format:

oc login --token=myToken --server=myServerUrl

Once you have your environment set up with the required tools, we can move on to the next step to build and deploy our application on OpenShift.

Start Red Hat Single Sign On

Developer Sandbox gives us access to the enterprise version of Red Hat’s OpenID provider: Red Hat Single Sign On (RH-SSO). On the topology view of OpenShift, click on the Add to Project button at the top left and add the version of RH-SSO that is compatible with the version of OpenShift you are running and wait for it to finish deploying. Please refer to the RH-SSO for OpenShift Documentation to learn more about it.

OpenShift CLI

Once the RH-SSO pod has been provisioned, use the following command to find the URL for your RH-SSO instance’s Admin Console:

RHSSO_URL=https://$(oc get route sso --template='{{ .spec.host }}') &&
echo "" &&
echo "RHSSO Admin Console: $RHSSO_URL/admin" && echo ""

OpenShift Web Console

Alternatively, you can click on the Open URL button on the Routes tab of the pod to be redirected to the RH-SSO landing page and click on Administration Console. You will be able to sign in using the admin username and password that is specified in the yaml configuration of the RH-SSO pod.

Configure RH-SSO

  1. First log in to the RH-SSO admin console using the username and password specified in the yaml configuration for the SSO pod.

  2. From here, create a realm called myrealm, and a client called myclient as follows:

    • General settings:

      • Client type (or Client Protocol, depending on your RH-SSO version): OpenID Connect

      • Client ID: myclient

    • Capability config:

      • Authentication flow: Standard flow, Direct access grants

    • Login Settings: For the Valid Redirect URIs, enter a * for now. We will come back to edit it later.

  3. Navigate to the Client Scopes tab for myclient. Here you will see that some scope values are under Assigned Default Client Scopes field and some others are under Assigned Optional Client Scopes field. When client scopes are added to Default, the claims associated with them are automatically added to the access token you receive without the need to configure them. Changing it to Optional ensures that they are not included by default and you will only get access to claims if you configure the corresponding scope values. This list of scope values you see here are the values that RH-SSO allows and it varies for different OpenID providers. RH-SSO also allows you to create new scopes, but we will not be doing that for this blog.

  4. Now, click on Roles and create two roles, user and admin.

  5. Finally, create a user called alice whose First Name is Alice and Last Name is Smith and assign her the user and admin roles.

  6. Next, navigate to the Credentials tab and create a password for Alice. Toggle the Temporary switch off, so you are not prompted to update the password after the first login.

Build Container Images for WildFly on OpenShift

Normally to use WildFly features that have been released, we just need to add the WildFly Helm release using the chart that is already available on OpenShift. However, since we are making use of a feature that is not released yet, we will need to build our own image of WildFly from the source code and deploy our application on that.

Clone the WildFly and Elytron Projects

First we need to clone the wildfly and the wildfly-elytron projects with the branches that contain the OIDC scope feature:

git clone https://github.com/PrarthonaPaul/wildfly.git
git checkout WFLY-16532

Next, go to the directory where the wildfly-elytron project should be cloned and clone it:

git clone https://github.com/PrarthonaPaul/wildfly-elytron.git
git checkout WFLY-16532

Notice that we are not using wildfly/wildfly and the wildfly-security/wildfly-elytron repositories. Instead, we are using a forked versions of the projects. This feature does not add any changes to the wildfly-core project. However, to ensure that the branch for wildfly-Core is compatible with the branches in the wildfly and the wildfly-elytron projects, we have created a branch called WFLY-16532, which we will use for this guide.

git clone https://github.com/PrarthonaPaul/wildfly-core.git
git checkout WFLY-16532

Build the WildFly Project

Next, we need to build these projects to use the local version of the code. To do this, we will specify the SNAPSHOT versions of wildfly-elytron and wildfly-core:

cd /PATH/TO/wildfly-elytron
mvn clean install -DskipTests

cd /PATH/TO/wildfly-core
mvn clean install -DskipTests -Dversion.org.wildfly.security.elytron=<insert_SNAPSHOT_VERSION_OF_ELYTRON>

cd /PATH/TO/wildfly
mvn clean install -DskipTests -Dversion.org.wildfly.core=<insert_SNAPSHOT_VERSION_OF_WILDFLY-CORE>

The -DskipTests tag skips all the tests, since we only need to build the projects. You can also go in and manually update the versions in the main pom.xml files of the projects and then use maven to build them.

Build the Docker Image for Quay

In order to deploy our application on OpenShift, we need to first create a container image of the application using Docker or Podman. In this post we are using Docker, but you can also use Podman using the podman keyword, or using an alias.

Navigate to the wildfly project and create a Dockerfile inside the root directory of the project. We will be creating an image of the current version of WildFly using the wildfly-runtime-jdk image on Quay. Quay is a repository for building and storing container images of your projects.

Head over to Quay.io and create a repository called wildfly. For more information on how to create one, visit the Quay documentation.

Now we can create the container image for our WildFly project. Enter the following commands inside your Dockerfile:

FROM quay.io/wildfly/wildfly-runtime-jdk11:latest
COPY --chown=jboss:root dist/target/wildfly-31.0.0.Beta1-SNAPSHOT $JBOSS_HOME
RUN chmod -R ug+rwX $JBOSS_HOME

Please note that the WildFly version may be different for you. Please update the version to match the WildFly version you have built in previous step. Now run the following commands on your terminal from the wildfly directory to create an image and push it to your Quay repository:

docker build -t quay.io/<your-quay-username>/wildfly:wildfly-app .
docker push quay.io/<your-quay-username>/wildfly:wildfly-app

Replace <your-quay-username> with your username for Quay. The -t command indicates that we are specifying a tag, which in this case is wildfly-app. The tag is used to identify different images inside the same repository. Using this image, we can ensure that we are running your local version of WildFly, as opposed to the version of WildFly that is present on OpenShift. You may need to log into quay.io using your username and password if you have not done so already using the command below:

docker login -u=<your-quay-username> -p=<your-quay-password> quay.io

Build the Application

Now that we have our WildFly container image, we can use it to deploy our application on it. Navigate to the elytron-examples/elytron-oidc-client-scope directory and create a deployment file for your application using this command:

mvn clean package

This will create a simple-webapp-oidc.war file inside the target directory.

Next, create a new Dockerfile inside the elytron-oidc-client-scope project with the following commands inside it:

FROM quay.io/<your-quay-username>/wildfly:wildfly-app
ADD target/simple-webapp-oidc.war /opt/server/standalone/deployments/

Here, we are making use of the container image of WildFly we made earlier and copying over the deployment file to the container image so we can deploy it on OpenShift by running the server. Next, build and push a new image of your application using the following commands:

docker build -t quay.io/<your-quay-username>/wildfly:latest .
docker push quay.io/<your-quay-username>/wildfly:latest

Notice that we have added a . at the end of the first command. This is to indicate the path to the project for which we are creating an image. If you are not running it from the directory of the project whose image you are trying to build, then replace the . with the path to the project.

Configure Image Pull Secret

In order to pull the image from Quay, you will need to configure a pull secret and connect it to your helm release. If you have already configured a pull secret for Quay, then you can skip this step.

Navigate to your Quay console, click on Account Settings, Generate Encrypted Password and log in. Under the Kubernetes Secret tab you will be able to download the yaml file for your Kubernetes secret. Upload it to your OpenShift Secrets by going to the Secret tab on Developer Sandbox, clicking on Create, From Yaml and replacing it with the contents of your Kubernetes Secret.

Alternatively you can link your pull secret so OpenShift can automatically use your pull secret to obtain the image when needed. You can learn more about handling secrets on OpenShift on their documentation.

Add Helm Configuration

Lastly, we will be creating a helm release of our local WildFly image and use that to deploy our application on OpenShift using a helm chart. Navigate to charts directory and open the helm.yaml file.

cd /PATH/TO/ELYTRON/EXAMPLES/elytron-oidc-client-scope/charts

The contents of the file will be as follows:

image:
  name: quay.io/<your-quay-username>/wildfly
build:
  enabled: false
deploy:
  env:
    - name: OIDC_PROVIDER_URL
      value: '<OIDC_PROVIDER_URL>'/auth/
    - name: WILDFLY_OVERRIDING_ENV_VARS
      value: "1"
    - name: SUBSYSTEM_LOGGING_PATTERN_FORMATTER_COLOR_PATTERN__PATTERN
      value: "[redhat-openshift] %-5p %s%e%n"

Replace <OIDC_PROVIDER_URL> to match the url for your RH-SSO instance on OpenShift and add a /auth/ to the end of the URL as seen above. There are three fields that we have specified: image, build and deploy.

Using the image field, we are specifying that we want the pod to use the image of our application that we just built. Notice that we did not specify the tag corresponding to our Quay image. This is because when the helm chart uploads, the latest tag is appended to it by default, which is why we tagged our application image as that. If you want to use a different tag, then you can edit this by clicking on the 3 dots at the bottom of the pod, click on Edit Deployment and changing it under Image Name.

We have also added some environment variables. Notice the OIDC_PROVIDER_URL. The value of this will be the url for your RH-SSO pod, which can be found by clicking on the Open URL button on the pod. So, copy that link and paste it as the value. The OIDC_PROVIDER_URL variable is being used by the oidc.json file inside the WEB-INF directory when specifying the provider-url.

Change the image name on the charts/helm.yaml file to include your quay username instead of <your-quay-username>.

Deploy the Example Application to WildFly on OpenShift

Use the following commands to deploy your webapp on OpenShift using the WildFly helm chart:

helm repo add wildfly https://docs.wildfly.org/wildfly-charts/
helm install simple-webapp-oidc -f charts/helm.yaml wildfly/wildfly

After running the commands above, you should expect to see the following output:

Waited for 1.068205845s due to client-side throttling, not priority and fairness,
request: GET:https://api.sandbox-m4.g2pi.p1.openshiftapps.com:6443/apis/triggers.tekton.dev/v1beta1?timeout=32s
NAME: simple-webapp-oidc
LAST DEPLOYED: <current date and time>
NAMESPACE: <your namespace>
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
To follow the deployment of your application, run:

$ oc get deployment simple-webapp-oidc -w

At this point, if you see that the deployment is failing, you can fix it by clicking on the three dots beside the simple-webapp-oidc pod’s name and click on Edit Deployment. Make sure that the image name is quay.io/<your-quay-username>/wildfly:latest. If not, edit it to reflect the correct image name under Image Name. Under Show advanced image options, set the Pull Secret to be the one you configured in the last section and click Save.

Your application is now deploying. Click on the simple-webapp-oidc pod and under the resources tab, you should see the status of your deployment. Alternatively, you can use the following commands:

$ oc get deployment simple-webapp-oidc -w

Get the Application URL

Just like RH-SSO, you can find the url for your webapp by clicking on Open URL which will redirect you to the WildFly landing page. Alternatively, you can use the OC client to do this using the following commands:

SIMPLE_WEBAPP_OIDC_URL=https://$(oc get route simple-webapp-oidc --template='{{ .spec.host }}') &&
echo "" &&
echo "Application URL:              $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc" &&
echo "Valid redirect URI:           $SIMPLE_WEBAPP_OIDC_URL/simple-webapp-oidc/*" &&
echo ""

Finish Configuring RH-SSO

Copy the link for your webapp and go back to the admin console for RH-SSO and add <Simple-webapp-oidc-url>/simple-webapp-oidc/* to the Valid Redirect URIs field. Notice that the link starts with https. We will be changing it to http since we have not performed any ssl configuration.

Access the Application

Now, let’s try accessing our application using <Simple-webapp-oidc-url>/simple-webapp-oidc.

Click on "Access Secured Servlet".

Now, you’ll be redirected to RH-SSO’s login page. If you click on the url on the search bar, you will see the scope values specified in the redirect-uri field with the different scope values separated by a +. You will also notice that a new scope value: openid. This indicates that we are going to be using OpenID Connect to authenticate the user.

Log in with Alice and the password that you set when configuring RH-SSO.

Next, you’ll be redirected back to our application, and you should see the "Secured Servlet" page. That means that we were able to successfully log in to our application using the RH-SSO OpenID provider!

This page will display the current principal, and a list of claim values obtained using the scope values you configured. This is what it will look like:

Secured Servlet

Current Principal 'alice'
Claims received using additional scope values:
Using the "profile" scope, we got User's name: Alice Smith
Using the "email" scope, we got email verified: true
Using the "microprofile-jwt" scope, we got the user's groups: [default-roles-myrealm, offline_access, admin, uma_authorization, user]

Note that the value for Current Principal may be different, since that is the client secret.

Notice that there are no claims obtained using the offline_access scope. To learn more about what this scope value does, please refer to the OpenID Documentation.

Summary

This post demonstrated how to deploy an OIDC secured WildFly application on OpenShift using Developer Sandbox. We also looked into how to configure additional scope values to request specific claim values. For more details on the elytron-oidc-client subsystem, please check out the documentation. Details on the scope attribute will be available once the feature is released. For more details on WildFly on OpenShift, you can check out this guide. If you have any questions or comments about this new upcoming feature, please let us know over on the WildFly User Forum.