Integrating Okta with SAML2 to Crafter Engine

In CrafterCMS, Crafter Engine is built with the ability to add security to your end user application as well (enterprise website, customer portal, employee intranet, mobile app, etc). In fact, you are able to integrate Crafter Engine with multiple authentication providers. Review the document for Engine Site Security Guide for more details.

Today, within a modern cloud-based application, there are many cases where application end users want to use Single Sign-on (SSO). In which, users log in to an Identity Provider for identifying, then use this information to authenticate to many services without the need to re-enter credentials information. In this tutorial, we demonstrate such an authentication method by using Okta with SAML2.

What is SAML

SAML (Security Assertion Markup Language) is an open standard that has two components: Identity Provider (IdP) and Service Provider (SP). The authentication credentials pass from IdP to SP so that users do not have to reauthenticate in SP again.

What is Okta

Okta is a platform in Identity-as-a-Service (IDaaS) category, a drop-in solution to add authentication and authorization services to various applications. In this tutorial, Okta acts as the Identity Provider component in the SAML standard. We will use Okta to authenticate Crafter Engine, which is the Service Provider in this case.

Prerequisites

This tutorial uses CrafterCMS 3.1 Enterprise Edition. SSO support is only available in the Enterprise edition of CrafterCMS. Contact info@craftercms.com for a free trial.


We will also use the default Website Editorial Blueprint to create a site for convenience. However, Okta authentication is not limited to any specific blueprint, and you can use any blueprint of your own.

SAML2 Authentication with Crafter Engine

A full document on how to use SAML2 authentication with Crafter Engine can be found here: Engine SAML2 Configuration — CrafterCMS 3.1 documentation.

In the next sections of this tutorial, we concentrate on how to set up SAML2 with Okta as the specific IdP.

Okta Setup

First of all, an Okta organization is required. This is usually tied to your company or a certain service, for example, https://craftersoftware.okta.com.

For testing purposes, you can also sign up for a free developer account at https://developer.okta.com/signup.

Create an application

Log in to your organization Okta account, from Dashboard, select Applications > Create App Integration.





Select SAML 2.0 option from display popup



Enter App name (Ex: Crafter CMS Engine) and optionally upload an app logo.

Click Next, enter detailed SAML2 configuration as following:

  • Single sign-on URL: http://localhost:9080/saml/SSO
    Checkbox for Use this for Recipient URL and Destination URL

  • Audience URI (SP Entity ID) : http://localhost:9080/saml/metadata

Note: This tutorial uses localhost as the domain. You should use your own service domain if required.



Input attribute statements



These attributes are needed for Crafter Engine to authenticate. The user’s first name will be displayed on authenticated pages. You can also add more attributes as needed. We will review this later on when configuring details for Crafter Engine.

Input Okta feedback

Finish Setup


Assign Okta users to the application

In order to log in to a website with an Okta account, an Okta admin needs to add Okta users of the organization to the Crafter Engine Application. From the Assignments tab, Click Assign and choose Assign to People.




Within displaying popup, confirm assigning a user with a correct email address then click Save and Go Back.


This completes the whole setup for Okta. We will continue the next section for Crafter Studio and Crafter Engine configuration.

Crafter Studio Setup

First of all, we need to create a new site with the Editorial Blueprint. All the configuration going forward will be tied to this site since authenticating for Crafter Engine is based on a site.

After a site is created, we also have to configure Crafter Studio for the Engine. Refer to this document on how to configure Engine to use SAML2 in general.

We will configure based on this document but with some specific samples for the case of Okta.

Create certificate

Create KeyStore and export certificate with the following commands:

$ keytool -genkey -alias CREDENTIAL_NAME -keystore keystore.jks -storepass STORE_PASSWORD
$ keytool -export -alias CREDENTIAL_NAME -keystore keystore.jks -rfc -file CREDENTIAL_NAME.cer

Create sp.xml (Service Provider) metadata file. Here is a sample:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://localhost:9080/saml/metadata">
<md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIE1DCCBH+gAwIBAgIEC+xT5zANBglghkgBZQMEAwIFADBsMRAwDgYDVQQGEwdV
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du
MB4XDTIxMDYxNDA4NTUyNFoXDTIxMDkxMjA4NTUyNFowbDEQMA4GA1UEBhMHVW5r
bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE
ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC
A0IwggI1BgcqhkjOOAQBMIICKAKCAQEAj3k12bmq6b+r7Yh6z0lRtvMuxZ47rzcY
6OrElh8+/TYG50NRqcQYMzm4CefCrhxTm6dHW4XQEa24tHmHdUmEaVysDo8UszYI
KKIv+icRCj1iqZNFNAmg/mlsRlj4S90ggZw3CaAQV7GVrc0AIz26VIS2KR+dZI74
g0SGd5ec7AS0NKasLnXpmF3iPbApL8ERjJ/6nYGB5zONt5K3MNe540lZL2gJmHIV
ORXqPWuLRlPGM0WPgDsypMLg8nKQJW5OP4o7CDihxFDk4YwaKaN9316hQ95LZv8E
kD7VzxYj4VjUh8YI6X8hHNgdyiPLbjgHZfgi40K+SEwFdjk5YBzWZwIdALr2lqaF
ePff3uf6Z8l3x4XvMrIzuuWAwLzVaV0CggEAFqZcWCBIUHBOdQKjl1cEDTTaOjR4
wVTU5KXALSQu4E+W5h5L0JBKvayPN+6x4J8xgtI8kEPLZC+IAEFg7fnKCbMgdqec
MqYn8kc+kYebosTnRL0ggVRMtVuALDaNH6g+1InpTg+gaI4yQopceMR4xo0FJ7cc
mjq7CwvhLERoljnn08502xAaZaorh/ZMaCbbPscvS1WZg0u07bAvfJDppJbTpV1T
W+v8RdT2GfY/Pe27hzklwvIk4HcxKW2oh+weR0j4fvtf3rdUhDFrIjLe5VPdrwIR
Kw0fAtowlzIk/ieu2oudSyki2bqL457Z4QOmPFKBC8aIt+LtQxbh7xfb3gOCAQUA
AoIBAFCRO2AVfAe1LxlfHfO2gowQ1RaIBds252QrO2qKwTMuO2k9AEWBh5bbegYZ
Yu2s96axq7GSXpSrpWZuBz1eJ07Mo1IqU1DizhlcaprUzjvyAZooL+bpDirUYZ78
JFjnR8Pfdngudl35eLNlra/zZxw1XUG0Vxdl+gqWM0sR0Xw2jCR7ErqJVOloivto
U7ngLVIJa79JMX6DFaOEqsynPsh14XUtpc4Zx+v9PfdfRIzihd7inc1/VLKDDIyp
kB0cs1TxYpN2z7qOSZPqDkjy0sa4q4+pFHwKqYkiM8f5dhCxOnhwzcIlBaZ5aC9F
DSy3zPXc8E8NZaxDZdCK5vq8JxqjITAfMB0GA1UdDgQWBBRN9EC+xJq23ggIMRwg
5xCuEISqDzANBglghkgBZQMEAwIFAANAADA9Ahwf6Do107+Pspo3JrcV+pc/f5nK
FrE6qEtQmuHyAh0ArEu1b5S4Z+eyhOzT1sINpzkcXOijEbYBG6/dWQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIE1DCCBH+gAwIBAgIEC+xT5zANBglghkgBZQMEAwIFADBsMRAwDgYDVQQGEwdV
bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD
VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du
MB4XDTIxMDYxNDA4NTUyNFoXDTIxMDkxMjA4NTUyNFowbDEQMA4GA1UEBhMHVW5r
bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE
ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC
A0IwggI1BgcqhkjOOAQBMIICKAKCAQEAj3k12bmq6b+r7Yh6z0lRtvMuxZ47rzcY
6OrElh8+/TYG50NRqcQYMzm4CefCrhxTm6dHW4XQEa24tHmHdUmEaVysDo8UszYI
KKIv+icRCj1iqZNFNAmg/mlsRlj4S90ggZw3CaAQV7GVrc0AIz26VIS2KR+dZI74
g0SGd5ec7AS0NKasLnXpmF3iPbApL8ERjJ/6nYGB5zONt5K3MNe540lZL2gJmHIV
ORXqPWuLRlPGM0WPgDsypMLg8nKQJW5OP4o7CDihxFDk4YwaKaN9316hQ95LZv8E
kD7VzxYj4VjUh8YI6X8hHNgdyiPLbjgHZfgi40K+SEwFdjk5YBzWZwIdALr2lqaF
ePff3uf6Z8l3x4XvMrIzuuWAwLzVaV0CggEAFqZcWCBIUHBOdQKjl1cEDTTaOjR4
wVTU5KXALSQu4E+W5h5L0JBKvayPN+6x4J8xgtI8kEPLZC+IAEFg7fnKCbMgdqec
MqYn8kc+kYebosTnRL0ggVRMtVuALDaNH6g+1InpTg+gaI4yQopceMR4xo0FJ7cc
mjq7CwvhLERoljnn08502xAaZaorh/ZMaCbbPscvS1WZg0u07bAvfJDppJbTpV1T
W+v8RdT2GfY/Pe27hzklwvIk4HcxKW2oh+weR0j4fvtf3rdUhDFrIjLe5VPdrwIR
Kw0fAtowlzIk/ieu2oudSyki2bqL457Z4QOmPFKBC8aIt+LtQxbh7xfb3gOCAQUA
AoIBAFCRO2AVfAe1LxlfHfO2gowQ1RaIBds252QrO2qKwTMuO2k9AEWBh5bbegYZ
Yu2s96axq7GSXpSrpWZuBz1eJ07Mo1IqU1DizhlcaprUzjvyAZooL+bpDirUYZ78
JFjnR8Pfdngudl35eLNlra/zZxw1XUG0Vxdl+gqWM0sR0Xw2jCR7ErqJVOloivto
U7ngLVIJa79JMX6DFaOEqsynPsh14XUtpc4Zx+v9PfdfRIzihd7inc1/VLKDDIyp
kB0cs1TxYpN2z7qOSZPqDkjy0sa4q4+pFHwKqYkiM8f5dhCxOnhwzcIlBaZ5aC9F
DSy3zPXc8E8NZaxDZdCK5vq8JxqjITAfMB0GA1UdDgQWBBRN9EC+xJq23ggIMRwg
5xCuEISqDzANBglghkgBZQMEAwIFAANAADA9Ahwf6Do107+Pspo3JrcV+pc/f5nK
FrE6qEtQmuHyAh0ArEu1b5S4Z+eyhOzT1sINpzkcXOijEbYBG6/dWQ==</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:9080/saml/logout"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:9080/saml/SSO" index="0" isDefault="true"/>
</md:SPSSODescriptor>
</md:EntityDescriptor>

Note:

  • entityID: Audience Restriction we added in the Okta application.
  • X509Certificate: Content of CREDENTIAL_NAME.cer in the previous step.

Create idp.xml (Identity Provider) metadata file:

Go back to Okta Application, select Sign On tab, click View Setup Instructions.

Scroll down, copy the content of IDP metadata and save to a new file idp.xml:


Last but not least, copy the metadata files and keystore to the above site sandbox Engine configuration location in Crafter Studio:


$ cd <PATH TO SITE REPOSITORY>
$ mkdir config/engine/saml2
$ cp ~/keystore.jks config/engine/saml2/
$ cp ~/idp.xml config/engine/saml2/
$ cp ~/sp.xml config/engine/saml2
$ git add .
$ git commit -m "Add SAML2 config files"


Configure

The configuration is exactly as mentioned in this document: Engine SAML2 Configuration — CrafterCMS 3.1 documentation.

Go to Site > Configuration > Select Engine Site Configuration


Add a <security> tag to indicate which pages need authentication and which authentication method the site is using.

Here is a sample configuration:

<site>
<version>2</version>
<security>
<headers>
<standalone>true</standalone>
</headers>
<urlRestrictions>
<restriction>
<url>/**</url>
<expression>isAuthenticated()</expression>
</restriction>
</urlRestrictions>
<saml2>
<enable>true</enable>
<reverseProxy>false</reverseProxy>
<context>
<forwardedProtoHeaderName>X-Forwarded-Proto</forwardedProtoHeaderName>
<forwardedHostHeaderName>X-Forwarded-Host</forwardedHostHeaderName>
<forwardedPortHeaderName>X-Forwarded-Port</forwardedPortHeaderName>
<scheme>http</scheme>
<serverName>localhost</serverName>
<serverPort>9080</serverPort>
<contextPath>/</contextPath>
</context>
<profile>
<passive>true</passive>
<forceAuthN>true</forceAuthN>
<includeScoping>false</includeScoping>
</profile>
<attributes>
<mappings>
<mapping>
<name>email</name>
<attribute>email</attribute>
</mapping>
<mapping>
<name>name</name>
<attribute>name</attribute>
</mapping>
</mappings>
</attributes>
<role>
<mappings>
<mapping>
<name>editor</name>
<role>ROLE_EDITOR</role>
</mapping>
</mappings>
</role>
<keystore>
<defaultCredential>okta_sso_1</defaultCredential>
<password>okta-secret-password</password>
<credentials>
<credential>
<name>okta_sso_1</name>
<password>okta-secret-password</password>
</credential>
</credentials>
</keystore>
<identityProviderName>http://www.okta.com/exk10hl3k0dlNxbEM5d7</identityProviderName>
<serviceProviderName>http://localhost:9080/saml/metadata</serviceProviderName>
</saml2>
</security>
</site>

Note:

  • In this example, we authenticate all the pages with URL pattern /** and expression isAuthenticated(). This means, if a user is not authenticated, she does not have access to any page. Refer to this document for more details on how to restrict pages or restrict URLs.
  • <attributes> tag: We added 2 attributes: email and name. They are configured in Okta as in previous steps.
  • <identityProviderName> tag: This is the information from “Identity Provider Issuer” configured in Okta Application. Retrieve this by going back to Okta Application, select Sign On tab, click View Setup Instructions, then copy the value.


  • <serviceProviderName> tag: Audience Restriction information from Okta Application

  • In this tutorial, we don’t use reverseProxy and use localhost with port 9080 as the domain/port for Engine so reverseProxy is set to false. If your application is under a proxy, make sure to configure this with correct values

Crafter Engine Setup

In the above section, we mentioned how to configure Crafter Studio for Okta authentication. In order to make this work in the Delivery Environment, we also have to publish the whole site to Delivery and configure Crafter Engine for the Delivery Environment as well

  1. Setup Delivery Environment
    Refer to this document how to set up a site in the delivery environment: Setup Site for a Delivery Environment — CrafterCMS 3.1 documentation
  2. Configure Engine

    After publishing the site, we configure the delivery engine to serve single tenancy in Engine as mentioned in this document: Configure Single-Tenancy in Engine — CrafterCMS 3.1 documentation. This guarantees when we access http://localhost:9080, the displaying site is pointed to our site.

This completes our whole setup. Make sure to publish all your content to Delivery and then restart Delivery. If there is no configuration issue, users should be redirected to the Okta login page.

Note: If you have accessed the Delivery website before, make sure to delete related cookies information before accessing Crafter Studio again. If you follow the tutorial and have any issues, check out catalina.out log file for any printout error.



Input your Okta Username/Password then sign in. You should be redirected to the website.



On the Home page, notice that it displays “Howdy, <Your-First-Name>”. This indicates this user is logged in and the Crafter Engine could read the attributes configured from Okta. Authenticated information is stored in a variable named authToken and therefore could be used as a template variable. Refer to this document to understand more about authenticated attributes: Engine Site Security Guide — CrafterCMS 3.1 documentation.

Conclusion

In this tutorial, we demonstrated how to integrate Okta with SAML2 for Crafter Engine. Okta acts as Identity Provider in SAML2 standard and Crafter Engine acts as Service Provider. While Okta is a convenient and easy-to-use Identity Provider, Crafter Engine itself is not limited to Okta; it can be used with any other SAML2 supported Identity Provider. By using Okta, we can easily create authenticated applications, assign users to them with some basic information as well as metadata such as roles.