Securing WildFly Applications Using Okta on OpenShift
WildFly applications can be secured using OpenID Connect (OIDC) and deployed to OpenShift. By using OIDC to secure applications, you delegate authentication to OIDC providers. The elytron-oidc-client
subsystem can be used to secure an application deployed to WildFly using any OpenID Provider. This guide demonstrates how to secure an example application deployed to WildFly on OpenShift using Okta as the OpenID Provider.
Prerequisites
To complete this guide, you need:
-
Roughly 15 minutes
-
JDK 11+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9+
-
Roughly 15 minutes
-
Access to an OpenShift cluster (try the Red Hat Developer Sandbox for free)
Example Application
We will use a simple web application in this guide that consists of a single servlet. We will use the simple-webapp-okta application in this repository.
We will need to first fork, and then clone the elytron-examples repository. We will be using the simple-webapp-okta
directory in this repo:
git clone git@github.com:wildfly-security-incubator/elytron-examples.git
cd simple-webapp-okta
Log Into the OpenShift Cluster
Before we can deploy our application, we need to log in to an OpenShift cluster. You can log in via the OpenShift CLI:
oc login -u myUserName
Alternatively, you can log in using an API token:
oc login --token=myToken --server=myServerUrl
You can request the token via the Copy Login Command
link in the OpenShift web console.
If you don’t already have a project created, you can create one using:
oc new-project myProjectName
Configure Okta
For this guide, we will be using Okta as our OpenID provider. In order to secure the application, we will need to access the Okta web console and register our application as a client. The following set of steps outlines how to register an OpenID web-application with Okta:
-
Log in to the Okta dashboard to get started.
-
At the top right corner, click on Admin to be redirected to the admin dashboard.
-
On the left hand panel, from the Applications drop down, click on Applications and then Create App Integration. Choose OIDC - OpenID Connect under Sign-in method and Web Application for Application type and click Next.
-
Under General Settings add the following configurations:
-
App integration name:
simple-webapp-okta -
Grant type:
Leave it as is, withAuthorization Code
checked. -
Sign-in redirect URIs
: Leave it as is for now. We will edit it later. -
Under the
Assignments
tab, forControlled access
, select Skip group assignment for now. -
Click
Save
.
-
You can find more information about configuring settings for app integration on Okta here.
Next, we will be adding a user to our directory, and add them to the previously created application using the following steps:
-
Navigate to the Directory drop down on the left panel and click People. Click Add person and add a person with:
-
First name: Alice
-
Last name: Smith
-
Email: alice@example.org
-
User Name: alice@example.org
-
From the dropdown list for Password, choose Set by admin and set a password that fits the password requirements.
-
Uncheck User must change password on first login and hit
Save
. For more information about how to add a user manually click here.
-
-
Click on the Applications tab on the left hand side. Navigate to Applications and click on simple-webapp-okta. Under the Assignments tab, click on Assign, then click on Assign to People and select Alice. For more information about how to assign a user to an application, please see here.
For more information about managing users on Okta, please see here.
Advanced OpenID Configuration
In order to extract the user information through the id token, we will need to configure a custom authorization server. Follow the steps below for this:
-
Under the Security dropdown, select API and click on the edit button next to the Default server.
-
Under the Claims tab, click on the Add Claim button and to add a claim with the following configurations:
-
Name: IDTClaim
-
Include in token type: ID Token and keep it at always.
-
Value type: Expression
-
Value: appuser.userName and hit
Save
.
-
We will be using this claim later to extract the username of the user who is currently logged in. You can learn more about Okta Expression Language here. . Now go back to the API menu and copy the Issuer URI for the Default server. . This will be used as the provider url when configuring our WildFly application.
For more information about Customizing tokens returned from Okta, please refer to this guide.
Add Helm Configuration
-
Keep the URL obtained from the last step.
-
Switch to the
charts
directory in thesimple-webapp-okta
example.
cd /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-okta/charts
Notice there’s a helm.yaml file in this directory with the following content:
build:
uri: https://github.com/wildfly-security-incubator/elytron-examples.git
contextDir: simple-webapp-okta
deploy:
replicas: 1
env:
- name: OIDC_PROVIDER_URL
value: <OKTA_URL> (1)
- name: OIDC_CLIENT_ID
value: <CLIENT_ID> (2)
- name: OIDC_CLIENT_SECRET
value: <CLIENT_SECRET> (3)
We will need to make the following changes locally to the helm chart:
-
Replace OKTA_URL with the provider url you copied in the last step.
-
Replace CLIENT_ID with the Client ID listed on the Okta console. Navigate to the General tab for our application on the Okta admin console and copy the Client Id and add it beside the client-id attribute.
-
Replace CLIENT_SECRET with your Client Secret for this application listed on Okta.
Save this file and close it.
Configure the Deployment Settings
Applications deployed to WildFly can be secured with OIDC in a couple different ways:
-
Using deployment configuration by specifying the attribute values inside
oidc.json
-
or using the
elytron-oidc-client
subsystem.
This guide uses the deployment configuration, but you can use the same attributes to configure the elytron-oidc-client
subsystem. You can learn more about the elytron-oidc-client
subsystem here.
You can view the deployment configuration used in this example by navigating to the oidc.json file. Note that we are making use of the environment variables we defined in the helm chart.
Now that we have added the required changes, we can deploy our application, the helm chart will specify the location for this example application and pull information needed for our deployment specified in the oidc.json
file.
Deploy the Example Application to WildFly on OpenShift
If you haven’t already installed the WildFly Helm chart, install it:
helm repo add wildfly https://docs.wildfly.org/wildfly-charts/
If you’ve already installed the WildFly Helm Chart, be sure to update it to ensure you have the latest one:
helm repo update
We can deploy our example application to WildFly on OpenShift using the WildFly Helm Chart:
helm install oidc-app -f /PATH/TO/ELYTRON/EXAMPLES/simple-webapp-saml/charts/helm.yaml wildfly/wildfly
Notice that this command specifies the file we updated, helm.yaml
, that contains the values needed to build and deploy our application.
The application will now begin to build. This will take a couple of minutes.
The build can be observed using:
oc get build -w
Once complete, you can follow the deployment of the application using:
oc get deployment oidc-app -w
Alternatively, you can check status directly from the OpenShift web console.
Behind the Scenes
While our application is building, let’s take a closer look at our application.
Examine the pom.xml file. Notice that it contains an openshift profile. A profile in Maven lets you create a set of configuration values to customize your application build for different environments. The openshift profile in this example defines a configuration that will be used by the WildFly Helm Chart when provisioning the WildFly server on OpenShift.
<profiles>
<profile>
<id>openshift</id>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<version>${version.wildfly.maven.plugin}</version> (1)
<configuration>
<feature-packs>
<feature-pack>
<location>org.wildfly:wildfly-galleon-pack:${version.wildfly}</location>
</feature-pack>
<feature-pack>
<location>org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.wildfly.cloud.galleon.pack}</location>
</feature-pack>
</feature-packs>
<layers>
<layer>cloud-server</layer>
<layer>elytron-oidc-client</layer> (2)
</layers>
<filename>simple-webapp-okta.war</filename>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
-
wildfly-maven-plugin provisions a WildFly server with the specified layers with our application deployed.
-
elytron-oidc-client automatically adds the native OIDC client subsystem to our WildFly installation.
Now examine the web.xml file.
<login-config>
<auth-method>OIDC</auth-method> (1)
</login-config>
-
When the elytron-oidc-client subsystem sees auth-method is set to OIDC, it enables OIDC authentication mechanism for the application.
Finally, review the oidc.json file. The oidc.json is used to configure the native OIDC client subsystem.
{
"client-id" : "${env.CLIENT_ID}", (1)
"provider-url" : "${env.OIDC_PROVIDER_URL}", (2)
"public-client" : "false", (3)
"principal-attribute" : "IDTClaim", (4)
"ssl-required" : "EXTERNAL", (5)
"credentials" : {
"secret" : "${env.CLIENT_SECRET}" (6)
}
}
-
Client_ID is the unique identifier for our client used by the Okta OpenID provider. Usually for Keycloak, you can create your own client, but for Okta, you are assigned an id. As a result, we are using environment variables to specify this.
-
The provider URL, which is the URL for the authorization server that we created, is specified as an environment variable. We set its value previously in the helm configuration.
-
When public-client set to false, client credentials are sent when communicating with the OpenID provider.
-
We specify that the user name of the identity, which in our case is alice, is to be used as the principal for the identity. We are extracting this information here using a custom claim in the ID token.
-
When ssl-required is set to EXTERNAL, only the communication with external clients happens over HTTPs.
-
Client credentials helps the OIDC server authenticate the client when accepting a request. It is required when public-client is set to false.
Get the Application URL
Once the pod running your WildFly server has been provisioned, use the following command to find the URL for your example application:
SIMPLE_WEBAPP_OKTA_URL=https://$(oc get route oidc-app --template='{{ .spec.host }}') &&
echo "" &&
echo "Application URL: $SIMPLE_WEBAPP_OKTA_URL/simple-webapp-okta" &&
echo "Valid redirect URI: $SIMPLE_WEBAPP_OKTA_URL/simple-webapp-okta/secured/" &&
echo ""
We’ll make use of these URLs in the next two sections.
Finish Configuring Okta
Go back to the General Settings for your application and click on Edit. add the Valid redirect URI
under the Sign-in redirect URIs
and check the Allow wildcard * in login URI redirect
field and hit Save.
Access the App
Now we can access our application using the Application Url from the previous section. Click on "Access Secured Servlet".
Now you will be redirected to the login page for Okta. Login using Alice. You will be prompted for the username. Although we set the username to be alice@example.org, we can just input alice here. You will be presented with three options for loggin in. Choose Password
and enter the password you selected for Alice.
What’s next?
This guide demonstrates how to use an OpenID provider other than Keycloak to secure an application deployed to WildFly. Other OpenID providers can be used to secure WildFly applications as well. And while the specific terms may be slightly different, the overall process should be similar. Please refer to documentations by your OpenID provider for more information.