Monday, November 4, 2013

Federated Authentication using OpenAM Fedlet, and Shibboleth

Summary

Federated access management using two different Identity Providers: OpenAM, and Shibboleth was required.  Towards Proof Of Concept (POC), with the idea that the Security Assertion Mark Language (SAML) compliant Identity Providers can be replaced, OpenAM’s fedlet application was selected.  Following diagram shows the high level architecture used towards the POC:

The simple concept of replacing the Identity Provider (IdP) was described in a couple of blogs, and was even mentioned in OpenAM’s documentation.  The blogs were at best were at a very high level, and was a challenge to follow.  This discussion is aimed at describing the issues encountered, and the resolutions worked during the integration.  The procedure followed is:
  • Securing Fedlet with OpenAM as IdP
  • Securing Fedlet with Shibboleth as IdP

Securing Fedlet with OpenAM as IdP

As a first step created fedlet using OpenAM’s admin console.  OpenAM sorts the list of Circle Of Trust(COT), and picks the first COT from the list while creating fedlet.  In addition OpenAM picks the hosted identity provider already configured (if one exists) as the Identity Provider for the fedlet, without providing any option to select other identity providers already configured within the OpenAM. Name, and Destination URLs are the inputs for creating fedlet as shown below:

While creating fedlet OpenAM creates a remote service provider with the url provided as input.  The fedlet thus created was deployed, configured, and tested.  Federation works successfully without any issues, hiding some of the configuration issues which are described later.  It should be noted that during fedlet creation, fedlet configuration files are copied to –Duser.home/fedlet if specified in catalina.bat, or /<user-home>/fedlet.  With self-explanatory names the files are:
  • A directory by the name debug
  • FederationConfig.properties
  • fedlet.cot
  • idp.xml
  • idp-extended.xml
  • sp.xml
  • sp-extended.xml

After accessing fedlet the first time, examining the debug files revealed some of the error messages.  The file with the name amSecurity containing the message:
ERROR: mapPk2Cert.JKSKeyProvider:
java.io.FileNotFoundException: <. . .>fedlet\keystore.jks,
clearly indicating that the file does not exist.  As a lazy developer with the first instinct, copied the keystore.jks file from OpenAM’s installation directory, and restarted tomcat.
 
Now after testing the the fedlet, FileNotFoundException in amSecurity is replaced with IOException as below:
ERROR: mapPk2Cert.JKSKeyProvider:
java.io.IOException: Keystore was tampered with, or password was incorrect

Again the message is clear that password is incorrect, but does not indicate that the required .keypass, and .storepass files are missing.  Since the keystore.jks was copied from openam directory, copied the .keypass, and .storepass files from the openam directory to fedlet directory.  Since the keystore.jks, .keypass, and .storepass are copied from the same location with the minimum expectation that it should work restarted tomcat, and accessed the fedlet again.  Now the IOException was replaced with JCEEncryption , with clueless error messages in the log files.
ERROR: JCEEncryption:: failed to decrypt data
javax.crypto.BadPaddingException: Given final block not properly padded

Remembering that the default password for the keystore was changeit, modified the passwords in .keypass, and .storepass to changeit.  Restarted tomcat, tested fedlet again.  The file amSDK contained the error message:
ERROR: JCEEncryption:: failed to decrypt data
amSDK:11/03/2013 08:08:14:519 AM EST: Thread[http-bio-18443-exec-3,5,main]
ERROR: JCEEncryption:: Unsupported version: 98

Google did not provide any leads to resolve this issue.  Replacing JCE with the latest version followed by restarting tomcat, and testing fedlet resulted with a minor difference in the error message for the Unsupported version as shown:
ERROR: JCEEncryption:: failed to decrypt data
amSDK:11/03/2013 08:08:14:519 AM EST: Thread[http-bio-18443-exec-3,5,main]
ERROR: JCEEncryption:: Unsupported version: 114

Source code did not provide any help where a comparison for a version value of 1 with some first byte was made.   Could not figure out the root cause of the problem.  While reading documentation on signing, and encrypting fedlet came across the following paragraph:

You must also set up .storepass and .keypass files using the fedletEncode.jsp page, such as http://openam.example.com:8080/fedlet/fedletEncode.jsp, to encode passwords on the Fedlet side. The passwords for the test key store and private key are both changeit.

Based on this paragraph changed passwords in .keypass, and .storepass to the encrypted passwords as suggested, restarted tomcat, accessed fedlet and noted that the log files were free from the error messages, lesson learned that the fedlet uses a different encoding mechanism than OpenAM.

Securing Fedlet with Shibboleth as IdP

Now that the log files are free from error messages, the next adventure is to replace OpenAM IdP with Shibboleth IdP.  Several steps are required for securing fedlet with Shibboleth as Identity Provider
  • Get metadata for Identity Provider
  • Getting entityId of the Identity Provider from Metadata file
  • Fedlet configuration to use new Shibboleth Identity Provider
  • Modify relyingparty.xml of Shibboleth

Get metadata for Identity Provider

/opt/shibboleth-idp/metadata/idp-metadata.xml is the metadata file for Shibboleth.  The same exposed as a URL is: https://sp.shibbolith.local:9443/idp/profile/Metadata/SAML.

Getting entityId of the Identity Provider from Metadata file

The element EntityDescriptor from the metadata file of Shibboleth:
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:shibmd="urn:mace:shibboleth:metadata:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" entityID="https://sp.shibbolith.local:9443/idp/shibboleth">
would provide the entityId of Shibboleth.  This entityId is used while reconfiguring fedlet configuration.

Fedlet configuration to use new Shibboleth Identity Provider

While registering Shibboleth as a Remote Identity Provider is not required, registering remote identity provider, and the reason for manually configuring the fedlet configuration is described.  OpenAM provides two ways to register Remote Identity Provider:
  • Direct registration of Remote Identity Provider
  • Importing an entity
While registering a Remote Identity Provider from OpenAM admin console requires either a URL, or a metadata file, importing an entity requires metadata file, and extended data file.  Since Shibboleth provides a single metadata file with extensions included inside the metadata file the option of importing an entity is ruled out, and we are left with the only option of registering a Remote Identity Provider.
Even after registering as Remote Identity Provider, a new fedlet can not be created with the Remote Identity Provider as the Identity Provider as OpenAM picks the hosted Identity Provider as Identity Provider for a new fedlet.  This rules out the option of creating a new fedlet with the Remote Identity Provider as the Identity Provider, leaving with the only option of modifying the fedlet configuration files to use a different remote identity provider.  

Configuration files used by Fedlet for the identity provider are:
  • fedlet.cot
  • idp.xml
  • idp-extended.xml

Modifications to Fedlet.cot

The entry sun-fm-trusted-providers contains entity ids used in the circle of trust
sun-fm-trusted-providers=<idp entity id>,<sp entity id >
Replace idp entity id with the identity provider's entityId https://sp.shibbolith.local:9443/idp/shibboleth which was obtained as described earlier, and the new entry would be:
sun-fm-trusted-providers=https://sp.shibbolith.local:9443/idp/shibboleth,https://openam-sp.shibbolith.local:18443/fedlet

Modifications to idp.xml

While idp.xml contains the basic Single Sign On related entities such as SingleSignOnService, and others, idp-extended.xml contains extended entities such as certificate information for signing, encrypting, and others.  While it may be trivial to replace the existing information in idp-extended.xml, it is a challenge, and error prone to replace the existing information in idp.xml.  As such the simple way is to remove existing single sign on related elements from idp.xml, and copy the single sign on related entities from Shibboleth's metadata file.

Following are the Single Sign On related entries to be removed: 
<ArtifactResolutionService index="0" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/ArtifactResolver/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://openam-idp.shibbolith.local:17443/openam/IDPSloRedirect/metaAlias/idp" ResponseLocation="https://openam-idp.shibbolith.local:17443/openam/IDPSloRedirect/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://openam-idp.shibbolith.local:17443/openam/IDPSloPOST/metaAlias/idp" ResponseLocation="https://openam-idp.shibbolith.local:17443/openam/IDPSloPOST/metaAlias/idp"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/IDPSloSoap/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://openam-idp.shibbolith.local:17443/openam/IDPMniRedirect/metaAlias/idp" ResponseLocation="https://openam-idp.shibbolith.local:17443/openam/IDPMniRedirect/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://openam-idp.shibbolith.local:17443/openam/IDPMniPOST/metaAlias/idp" ResponseLocation="https://openam-idp.shibbolith.local:17443/openam/IDPMniPOST/metaAlias/idp"/>
<ManageNameIDService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/IDPMniSoap/metaAlias/idp"/>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</NameIDFormat>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://openam-idp.shibbolith.local:17443/openam/SSORedirect/metaAlias/idp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://openam-idp.shibbolith.local:17443/openam/SSOPOST/metaAlias/idp"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/SSOSoap/metaAlias/idp"/>
<NameIDMappingService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/NIMSoap/metaAlias/idp"/>
<AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://openam-idp.shibbolith.local:17443/openam/AIDReqSoap/IDPRole/metaAlias/idp"/>
<AssertionIDRequestService Binding="urn:oasis:names:tc:SAML:2.0:bindings:URI" Location="https://openam-idp.shibbolith.local:17443/openam/AIDReqUri/IDPRole/metaAlias/idp"/>

Following are the Single Sign On related elements to be copied from Shibboleth's metada:
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="https://sp.shibbolith.local:9443/idp/profile/SAML1/SOAP/ArtifactResolution" index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/SOAP/ArtifactResolution" index="2"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/Redirect/SLO" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/POST/SLO" />
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/SOAP/SLO" />
<NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="https://sp.shibbolith.local:9443/idp/profile/Shibboleth/SSO"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/POST/SSO"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/POST-SimpleSign/SSO"/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://sp.shibbolith.local:9443/idp/profile/SAML2/Redirect/SSO"/>


In addition remove the existing element, KeyDescriptor from idp.xml.  Copy the KeyDescriptor element from Shibboleth's metdata file.  Noting slight differences in entities as described by OpenAM, and Shibboleth modify the elements KeyDescriptor, and KeyInfo as copied from Shibboleth's metdata file to read as:

<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">

Without these changes fedlet configuration fails, and can not access the testing link as provided by fedlet.

Modifications to Idp-extended.xml

OpenAM's handling of boolean values for the attribute hosted is confusing.  The default entry for the attribute hosted as configured in idp-extended.xml is a numeric value of "0":
<EntityConfig entityID="https://openam-idp.shibbolith.local:17443/openam" hosted="0" xmlns="urn:sun:fm:SAML:2.0:entityconfig">


Since Shibboleth Identity Provider is a remote Identity Provider, and changing the hosted attribute to a non zero did not work.  After a few iterations, only string value of "false" worked for the hosted attribute:
<EntityConfig entityID="https://openam-idp.shibbolith.local:17443/openam" hosted="false" xmlns="urn:sun:fm:SAML:2.0:entityconfig">

Replace the entityId with Shibboleth's entityID in the EntityDescriptor element:
<EntityDescriptor entityID=" https://sp.shibbolith.local:9443/idp/shibboleth" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"> 

Configuring Shibboleth's relyingparty.xml

Valid enumeration values for signResponses, and signAssertions are "always", "never", and "conditional". 

Remembering that by default during fedlet configuration Service Provider is not configured to use signed authentication requests, and signed assertions as seen from the SPSSODescriptor element of sp.xml:
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
started with the simple case of no response signing, and no encryption as shown below: 
<rp:ProfileConfiguration xsi:type="saml:SAML2SSOProfile" includeAttributeStatement="true"
                                 assertionLifetime="PT1M" assertionProxyCount="0"
                                 signResponses="never" signAssertions="never"
                                 encryptAssertions="never" encryptNameIds="never"
                                 includeConditionsNotBefore="true"/>

When all changes as described earlier were made, fedlet testing resulted in redirecting the user to Shibboleth's(CAS) login page indicating that the Fedlet is using Shibboleth as the Identity Provider.  When valid credentials were entered following error message was displayed:
HTTP Status 500 - The signature on Assertion is not valid.
type: Status report
message: The signature on Assertion is not valid.
description: The server encountered an internal error that prevented it from fulfilling this request.

Based on the above error message changed the attributes signResponses, and signAssertions to conditional:
<rp:ProfileConfiguration xsi:type="saml:SAML2SSOProfile" includeAttributeStatement="true"
                                 assertionLifetime="PT1M" assertionProxyCount="0"
                                 signResponses="conditional" signAssertions="conditional"
                                 encryptAssertions="never" encryptNameIds="never"
                                 includeConditionsNotBefore="true"/>
  
Fedlet testing resulted in the following error message:
HTTP Status 500 - Failed to process single sign-on response.
type: Status report
message: Failed to process single sign-on response.
description: The server encountered an internal error that prevented it from fulfilling this request.

Since the signResponses, and signAssertions are not in synch between the Service Provider, and IdentityProvider, synchronized the attributes by changing the attributes AuthnRequestsSigned, and WantAssertionsSigned to true in sp.xml
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> 

Manual editing of sp.xml in fedlet configuration directory would not synchronize the same in OpenAM, and the service provider configuration would not be updated on Shibboleth.  Using OpenAM's admin console check AuthnRequestsSigned, and Want AssertionsSigned flags of Service Provider.  Restart tomcat hosting Shibboleth to synchronize with the Service provider configuration. 
Also restart tomcat hosting fedlet.

Alternate, and better ways are always possible.  But just for simplicity used this approach.

After all troubleshooting described above, fedlet worked successfully demonstrating the federated authentication between two SAML compliant service provider(OpenAM Fedlet) and identity providers(Shibboleth).

As a note following error message was received:  
ERROR: FMSigProvider.verify: The cert contained in the document is NOT the same as the one being passed in.
when the signing certificates in Shibboleth's idp-metadata.xml, and idp.xml were not in synch.
    

1 comment:

  1. Hi

    I have developed an application as SP using OpenAM fedlet. Single Sign on is working fine and Single Sign out also happening from Idp (Idp is

    SimpleSAMLPHP).

    But Im facing one issue, when I have connected two SP's and do single sign out its successfully signed out from Idp but the local session for second SP

    still exists and able to access the site even after logged out of Idp.

    I assume that for each request in SP should validate whether valid session exists in Idp, but I'm unable to find how to do with OpenAM fedlet.

    Can you please give me some valuable input to signout local session of SP when signout is happened from any other SP.

    Regards
    Arjun S

    ReplyDelete