Fediz authentication in Tomcat

This document describes configuring Fediz in Tomcat 8.5/9.0. By default Semarchy xDM has Tomcat's FormAuthenticator enabled. This document walks through the details of using an alternative authentication mechanism: the Semarchy FederationAuthenticator which is based on Fediz. This allows you to use SAML or WS-Federation external identity providers (IDP) like Active Directory Federation Services (ADFS) and Okta where xDM tomcat server will be the service provider (SP). You can find more details on Fediz here, http://cxf.apache.org/fediz-tomcat.html.

WS-Federation and SAML are time sensitive protocols, and multiple time-based assertions are performed to check validity of tokens. It is very important to synchronize IDP and SP through NTP (Network Time Protocol) to avoid time drift related issues that can be hard to troubleshoot

Step-by-step guide

  1. Most IDP requires https, so you may have to configure Tomcat to use https (SSL/TLS).
  2. Ensure that Semarchy's Tomcat tools are available (9.0.3 or more). This is to permit mapping of external groups (such as Active Directory groups or OKTA groups) to Semarchy roles (referred to as "role mapping"). Semarchy's Tomcat tools file ships with Semarchy xDM (com.semarchy.tool.jee.tomcat-9.0.x.jar). 

    Check Tomcat tool availability
    # Is com.semarchy.tool.jee.tomcat-* present?
    ls -l /usr/share/tomcat9/lib/

    If the jar file is not present, then get it from the standard Semarchy Installation files.

    Get Tomcat tools from standard Semarchy installation
    # Get Semarchy Install 
    # Browser version of these steps: 
    #   1. Download from "Server Installation" from here: https://www.semarchy.com/all-downloads/
    #   2. Unzip the xDM Server Installation zip file 
    # Command line version. (correct for 5.2.3):
    curl https://www.semarchy.com/downloads/products/5.2/semarchy-xdm-install-5.2.3.ga-20200807-0643.zip -O
    # Extract Semarchy Tomcat Tools from the .zip file
    unzip -j semarchy-xdm-install-5.2.3.ga-20200807-0643.zip mdm-server/additional-libraries/com.semarchy.tool.jee.tomcat-8.5.10-ga-20200807-0643.jar
    
    # Copy the jar into place
    sudo cp com.semarchy.tool.jee.tomcat-8.5.10-ga-20200807-0643.jar /usr/share/tomcat8/lib/
  3. Download latest Fediz 1.6 connector for tomcat (with dependencies) here :
    https://repo1.maven.org/maven2/org/apache/cxf/fediz/fediz-tomcat/1.6.1/fediz-tomcat-1.6.1-zip-with-dependencies.zip

    Example of getting the Fediz connector
    curl https://repo1.maven.org/maven2/org/apache/cxf/fediz/fediz-tomcat/1.6.1/fediz-tomcat-1.6.1-zip-with-dependencies.zip -O
    unzip fediz-tomcat-1.6.1-zip-with-dependencies.zip
  4. Create sub-directory called Fediz to hold the fediz jar files in ${catalina.home}/lib

    Example of creating Fediz directory
    sudo mkdir /usr/share/tomcat9/lib/fediz
  5. Update catalina.properties in ${catalina.home}/conf to add the previously created directory to the common loader:

    Updating catalina.properties
    # original
    common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
    
    # modified
    common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,"${catalina.home}/lib/fediz/*.jar"
  6. Deploy the libraries to the directory created in step 4.

    Deploying libraries
    sudo cp /tmp/*.jar /usr/share/tomcat9/lib/fediz/
  7. Configure Fediz Valve in semarchy.xml
    Remove (comment out) the existing FormAuthenticator and replace it with FederationAuthenticator.

    Configure Fediz valve in semarchy.xml with Role Mapping
        <!-- This is the default authenticator valve
        <Valve className="org.apache.catalina.authenticator.FormAuthenticator" landingPage="/" />
        -->
    
        <!-- This Semarchy class is based on the Fediz class. It allows us to do role mapping and to do fallback for REST API authentication. -->
        <!-- https://www.semarchy.com/doc/semarchy-xdm/semng.html#using-the-tomcat-role-mapper -->
        <Valve className="com.semarchy.tool.jee.tomcat.FederationAuthenticator" 
            rolesMappingPathName="/some/custom/path/my-roles-mapping.properties" 
            configFile="conf/fediz_config.xml" 
            keepMappedRoles="false" 
            keepUnmappedRoles="false" 
        />
        <!-- Example: store credentials to be used for REST calls in tomcat-users.xml. This works because we do preemptive basic authentication. (Won't work for form login.) -->
        <!--
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
        -->
    
    Configure Fediz valve in semarchy.xml without Role Mapping
        <!-- This is the default authenticator valve
        <Valve className="org.apache.catalina.authenticator.FormAuthenticator" landingPage="/" />
        -->
    
           <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" />
          
           <!-- This Semarchy class is based on the Fediz class. It allows us to do role mapping and to do fallback for REST API authentication. -->
           <!-- https://www.semarchy.com/doc/semarchy-xdm/semng.html#using-the-tomcat-role-mapper -->
           <!-- <Valve className="com.semarchy.tool.jee.tomcat.FederationAuthenticator" configFile="conf/fediz_config.xml" /> 
          
           <!-- Example: store credentials to be used for REST calls in tomcat-users.xml. This works because we do preemptive basic authentication. (Won't work for form login.)
           <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
           -->
    
  8. You need to provide the relevant cert to Tomcat so that your authentication provider (for example OKTA) will trust Tomcat.

    Create a keystore (or use your existing keystore) and import your Identity Provider certificate for your Semarchy xDM application (Note that if your Identity Provider certificate is a PEM file you can skip keystore import and point configuration directly to it).
    For example, in OKTA when using SAML download the X.509 Certificate for your Semarchy xDM instance as "okta.cert" (you'll have different certs for each application: dev, prod, etc.)

    # Sample import into a keystore
    keytool -import -trustcacerts -alias customer_saml_cert -file okta.cert -keystore keystore.jks
  9. Configure your Identity Provider.
    For example, configure Okta as described here: https://developer.okta.com/standards/SAML/setting_up_a_saml_application_in_okta.
    Specifically it's best to set the 'Audience URI (SP Entity ID)' to the server URL including context. For example, http://example.com/semarchy/ or https://example.com/semarchy/. This is what Semarchy will expect, by default, in the response token from Okta. This should match the 'audienceItem' section of the fediz_config.xml file as described in step 10.
    If the 'Audience URI (SP Entity ID)' setting in Okta needs to be something other than the server URL, you must configure the 'audienceItem' AND add a realm in the protocol section of fediz_config.xml as described in step 10. This is due to the fact that Fediz can also be used as an IDP itself or used for relaying authentication and not just a SP.
  10. Configure Fediz by creating fediz_config.xml here: ${catalina.home}/conf/fediz_config.xml
    References:
    http://cxf.apache.org/fediz-configuration.html
    https://github.com/apache/cxf-fediz/blob/master/plugins/core/src/main/resources/schemas/FedizConfig.xsd
    Additional samples in "Sample Configurations" below

    Create fediz_config.xml
    sudo vim /etc/tomcat9/fediz_config.xml
    Configure fediz_config.xml
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <FedizConfig>
        <contextConfig name="/semarchy">
            <audienceUris>
                <audienceItem>https://mydomain:8443/semarchy/</audienceItem> <!-- This value must match the Okta 'Audience URI (SP Entity ID)' setting. If the 'Audience URI (SP Entity ID)' setting is not the server URL including context, you must also set the optional realm below in the protocol section. See step 9.-->
            </audienceUris>
            <certificateStores>
                <trustManager>
                    <keyStore file="conf/keystore.jks" password="keystore_password" type="JKS" />
                </trustManager>
            </certificateStores>
            <!-- maximumClockSkew sets the tolerance time between IDP and SP. 
                 It is still highly recommended to synchronize servers through NTP 
            -->
    		<!-- <maximumClockSkew>10</maximumClockSkew> --> 
            <trustedIssuers>
                <issuer certificateValidation="PeerTrust" />
            </trustedIssuers>
            <!-- Only one protocol may be defined. Here are two examples. -->
            <!-- WS-Federation protocol:  -->
            <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="federationProtocolType" version="1.2">
                <issuer><!-- Your Identity Provider Issuer. For example: https://login.customer.com/adfs/ls/ --></issuer>
                <roleURI><!-- Your URI to get roles. For example for ADFS: http://schemas.microsoft.com/ws/2008/06/identity/claims/role --></roleURI>
            </protocol>
            <!-- SAML protocol: -->
            <!-- Comments on frequently used values:
                 doNotEnforceKnownIssuer is used when:
                   - Fediz is expecting issuer as specified above (SSO IDP URL), Okta is sending something else 
                 disableDeflateEncoding is used when:
                   - Fediz is expecting SAML response to be gziped, Okta is not compressing response
            -->
            <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="samlProtocolType" version="2.0">
    			<doNotEnforceKnownIssuer>true</doNotEnforceKnownIssuer>
                <disableDeflateEncoding>true</disableDeflateEncoding>
                <issuer>
                    <!-- Your Identity Provider Single Sign on URL. This should link to a login screen. Examples: 
                	     https://mydomain.okta.com/app/mydomaine_semarchydev_1/hsosjgkwlsjCUREU7T2p6/sso/saml 
                	     https://YOUR.PINGFEDERATE.SERVER/idp/SSO.saml2
                         https://www.mysite.com/adfs/ls
                    -->
                </issuer>
                <!-- Your roleURI configuration could be different, but "groups" is often the roleURI. -->
                <roleURI>groups</roleURI>
    			<!-- The realm tag is not generally required. 
                     It is needed, for example, if the Okta 'Audience URI (SP Entity ID)' setting is not set to the server URL including context. 
                     See step 9 for more details. 
                -->
                <!-- <realm type="String">http://10.10.10.10/semarchy/welcome</realm> -->
            </protocol>
    		<!-- Uncomment logoutURL below to enable SSO logout -->
    		<!--<logoutURL>/sem_check2</logoutURL>-->
    
    		<!-- Or uncomment below to enable local logout with redirect to you have been logged out page -->
    		<!--<logoutRedirectToConstraint>.*</logoutRedirectToConstraint>-->
        </contextConfig>
    </FedizConfig>
    

Logout

By default in xDM logout is not performing a SSO logout. SSO logout is configured by adding following to configuration

<logoutURL>/sem_check2</logoutURL>


If for some reasons you need to perform a local logout (logout from xDM only, but keep SSO sign-in), standard Fediz is not working well with xDM logout action, so you need to use semarchy version (com.semarchy.tool.jee.tomcat.FederationAuthenticator)

The local logout is redirecting by default to a big black screen image. In order to redirect to our page "you have been logged out" you need to add following configuration:

<logoutRedirectToConstraint>.*</logoutRedirectToConstraint>

Note that currently the url redirected after logout is not configurable, if a customer requires this feature, fill a Jira story 

Enable Logging for Fediz

  1. Activate this logger

    Activate this logger
    sudo vim /etc/tomcat8/logging.properties
    
    # These are included but commented out by default.
    # Enable them now, so we get the detailed logging we need.
    # From Semarchy
    # enable realm logging
    org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/semarchy].level = ALL
    org.apache.catalina.realm.level = ALL
    org.apache.catalina.realm.useParentHandlers = true
    org.apache.catalina.authenticator.level = ALL
    org.apache.catalina.authenticator.useParentHandlers = true
    
    
    # Turn on Fediz logging - add these lines at the end
    com.semarchy.tool.jee.tomcat.level = FINE
    org.apache.cxf.fediz.level = ALL
    org.apache.wss4j.level = ALL
    
    # Remember that Log4j uses ERROR, WARN, INFO, DEBUG, TRACE, etc 
    # but JULI uses these: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, or ALL
    # By default Tomcat 8 uses JULI logging.
  2. SAML-tracer. In addition to logging in Tomcat, it's also useful to see the SAML token in the browser to understand what's going on. The Firefox add-on "SAML-tracer" is very helpful:
    https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/  or Chrome version https://chrome.google.com/webstore/detail/saml-tracer/mpdajninpobndbfcldcmbpnnbhibjmch?hl=en

    You cannot browse the contents of the token if it is encrypted. Obviously. So do not encrypt. (Or enable encryption after everything is working without encryption.)

    There is more general information about configuring Fediz logging in this article if your Tomcat configuration is different.

AuthnRequest Request Builder configuration

Some IDPs may not support default SAML Sign-in Request generated by fediz. We provide a way to customize some parts of this Request: 

  • com.semarchy.tool.jee.tomcat.fediz.PingFederateSamlRequestBuilder: pre-configured builder for PingFederate server
  • com.semarchy.tool.jee.tomcat.fediz.ADFSSamlRequestBuilder: pre-configured builder for ADFS server
  • com.semarchy.tool.jee.tomcat.fediz.ConfigurableSAMLPRequestBuilder: configurable builder

The custom builder can be configured in protocol part of fediz_config.xml

		<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="samlProtocolType" version="2.0">
			<authnRequestBuilder>com.semarchy.tool.jee.tomcat.fediz.ConfigurableSAMLPRequestBuilder</authnRequestBuilder>
			....
		</protocol>

com.semarchy.tool.jee.tomcat.fediz.ConfigurableSAMLPRequestBuilder requires an additional configuration file in conf of tomcat named fediz-samlp-request.properties

Sample file below shows supported properties with default values. For example to customize nameID, you need to uncomment nameid.format and put the value you expect.

Sample properties file
#nameid.format = urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
#authn.ctx.classref = urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
#nameid.qualifier = true
#authn.force = false
#passive = false
#protocol.binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST

Sign SAML Request token

You need a certificate to sign tokens. If you do not have a certificate you can generate one (steps are similar than for generating an https certificate).

The following configuration is required to sign Request tokens: 

Sign request tokens
<FedizConfig>
	<contextConfig name="/semarchy">
		....
		<signingKey keyAlias="mytomrpkey" keyPassword="tompass">
			<keyStore file="/path/to/mykeystore.jks" password="tompass" type="JKS" /> 
		</signingKey>
		.....
		<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="samlProtocolType" version="2.0">
			<signRequest>true</signRequest>
		</protocol>
		.........
	</contextConfig>
</FedizConfig>

Default Digest algorithm for signature is RSA_SHA1 or DSA_SHA1 when using DSA certificates. 

Some IDPs may only support RSA_SHA256 signatures, in this case you need to be sure the certificate used to sign tokens is a RSA certificate, then fediz can be configured like this:

Change signature algorithm
<signRequest algorithm="RSA_SHA256">true</signRequest>

Support for Encrypted tokens

The configuration needs to define the certificate used to decrypt tokens

Decrypt certificate
<FedizConfig>
	<contextConfig name="/semarchy">
		.......
		<tokenDecryptionKey keyAlias="mytomrpkey" keyPassword="tompass">
            <keyStore file="/path/to/mykeystore.jks" password="tompass" type="JKS" />
        </tokenDecryptionKey>
		.........
	</contextConfig>
</FedizConfig>

Fediz normally requires tokens to be signed, but when tokens are encrypted, signature validation can be disabled (to support encrypted tokens that are not signed)

Support for not signed tokens
<FedizConfig>
	<contextConfig name="/semarchy">
		......
		<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="samlProtocolType" version="2.0">
			......
			<doNotEnforceEncryptedAssertionsSigned>true</doNotEnforceEncryptedAssertionsSigned>
			......
		</protocol>
		......
	</contextConfig>
</FedizConfig>

SP Metadata

Fediz automatically build XML metadatas of the xDM application acting as the SAML Service Provider, from its configuration.

The Metadata Document is available from SAML/Metadata.xml URL, for example https://myhost/semarchy/SAML/Metadata.xml

Known Issues

  • Fediz 1.5.0 release does not support SAML signed tokens without keyinfo in it. a NPE is thrown during SAML token validation.

Sample Configurations

Valid sample fediz_config.xml for ADFS with WS-Federation

Sample fediz_config.xml for ADFS (Active Directory Federation Services) with WS-Federation
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FedizConfig>
    <contextConfig name="/semarchy">
        <audienceUris>
            <audienceItem>https://dev-mdm.mydomain.com/semarchy/</audienceItem>
        </audienceUris>
        <certificateStores>
            <trustManager>
                <keyStore file="/opt/tomcat/.keystore" password="changeit" type="JKS" />
            </trustManager>
        </certificateStores>
        <trustedIssuers>
            <issuer certificateValidation="PeerTrust" />
        </trustedIssuers>
        <protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="federationProtocolType" version="1.2">
            <issuer>https://login.mydomain.com/adfs/ls/</issuer>
			<roleURI>http://schemas.microsoft.com/ws/2008/06/identity/claims/role</roleURI>
        </protocol>
    </contextConfig>
</FedizConfig>

Valid sample fediz_config.xml for samling (Samling is a serverless SAML IDP simulator, probably the easiest way to test a fediz SAML setup as it does not need a SAML server setup) 

Sample fediz_config.xml for samling (SAML)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FedizConfig>
	<contextConfig name="/semarchy">
		<audienceUris>
			<audienceItem>http://localhost:8088/semarchy/</audienceItem>
		</audienceUris>
		<certificateStores>
			<trustManager>
				<!-- not that certificate is in file directly, not imported in keystore, as this is also supported by fediz -->
				<keyStore file="/opt/tomcat/conf/samling.cert" type="PEM" />
			</trustManager>
		</certificateStores>
		<trustedIssuers>
			<issuer certificateValidation="PeerTrust" />
		</trustedIssuers>
		<protocol xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="samlProtocolType" version="2.0">
			<disableDeflateEncoding>true</disableDeflateEncoding>
			<doNotEnforceKnownIssuer>true</doNotEnforceKnownIssuer>
			<issuer>https://fujifish.github.io/samling/samling.html</issuer>
			<roleURI>groups</roleURI>
			<roleDelimiter>,</roleDelimiter>
		</protocol>
		<logoutURL>/sem_check2</logoutURL>
	</contextConfig>
</FedizConfig>

Sample SAML configuration with Pingfederate (Sanofi) Fediz 1.4.6 and com.semarchy.tool.jee.tomcat-8.5.4 at least are required for this configuration:

REST API

Once customers configure authentication in Semarchy, many also are interested in configuring authentication REST API. The REST API has two methods of authentication:

  1. Basic
  2. API tokens
Customers who use open id or LDAP authentication can use basic authentication in the REST API.  For a particular user defined, his credentials (username/password used for form authentication) can be used for REST API authentication (give username/password using preemptive basic authentication). 
Some customers are interested in using token authentication in REST API. This is currently not supported. If users are interested in token authentication, they need use the API keys implemented in Semarchy. 

Troubleshooting

If you see this error in the log:

SAML token not trusted
org.apache.cxf.fediz.core.saml.SAMLTokenValidator.validateAndProcessToken Issuer 'null' not validated in keystore 'conf/ststrust.jks' 
org.apache.cxf.fediz.core.saml.SAMLTokenValidator.validateAndProcessToken Issuer 'https://sts.windows.net/62a9c2c8-8b09-43be-a7fb-9a87875714a9/' not trusted 
org.apache.cxf.fediz.core.handler.SigninHandler.handleRequest Federation processing failed: Security token issuer not trusted 

Logging from org.apache.wss4j logger is necessary to understand the real issue behind this.

Sample error encountered by one Semarchy customer:

Time drift issue
org.apache.wss4j.common.saml.SamlAssertionWrapper.checkIssueInstant SAML Token IssueInstant not met

The preceding error is normally a time drift related issue.
Solution: Synchronize servers through NTP (recommended) so that the clocks match.
Workaround: Use maximumClockSkew parameter as a workaround to allow a sufficient tolerance.


Otherwise possible reason for that is the certificate has either not been imported into the keystore or is not an up to date copy, then a SAML token not trusted error is shown.

Import the certificate with a command such as this:

Import Example
sudo keytool -import -alias customer_saml_cert -file /data/installs/adfs.cer -keystore /opt/tomcat/conf/ststrust.jks

Or if you see this



Filter by label

There are no items with the selected labels at this time.