We are seeing significant interest from our Portal clients in enabling Single Sign-On (SSO) not only within their enterprise, but also with their customers and partners. In some cases, this need is becoming an expectation of our clients’ customers – in other cases, when our clients have their enterprise portal being used by hundreds and even thousands of their customers’ employees, they do not want to take on the overhead of provisioning and managing access for all these external users. This need boils down to Federated SSO, and SAML is a standard that is increasingly gaining traction in this space – among its many new features, Liferay 6.1 Enterprise Edition (EE) now comes with SAML Support.
In this blog post I will show how to configure SAML support in Liferay 6.1 EE with one Liferay instance set up as an Identity Provider (IDP) and another Liferay instance as Service Provider (SP).
Before delving into configuration, let me give a very brief introduction of SAML and what problems/use cases it covers.
Here is some brief introduction of SAML for those who are new to it –
SAML is a set of standards for communicating information on user authentication, entitlement, and attributes – SAML enables sharing of information about who a user is, what his set of attributes are, and gives you a way to grant/deny access to something or even request authentication.
It’s an XML-based framework for exchanging security information.
- XML-encoded security “assertions”
- XML-encoded request/response protocol
It’s an OASIS standard and the current version (as of writing this blog) is SAML 2.0 which was approved in March 2005.
SAML Use Cases
- Single Sign On (SSO)
- Attribute based Authorization Service
- Identity Federation.
- WS-Security.
SAML Operation Modes
- Identity Provider (IdP) – Asserting Party
- Service Provider (SP) – Relying Party
With SAML, you can configure SPs to permit access to resources only when an identity provider (IdP) has authenticated a user, thus enabling SSO between the IdP and the SPs.
For more information on SAML please refer to the following links –
- http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language
- http://www.youtube.com/watch?v=50ogFCF56qE
The below figure illustrate the use case that is considered in this post for configuring one instance of Liferay as the Identity Provider (IdP) and another Liferay instance as Service Provider (SP).
Prerequisites:
- Liferay 6.1 EE
- SAML Plugin Portlet WAR
I will be depicting here the steps that I followed to configure SAML in Liferay 6.1 EE, step by step in more detail.
Setting up Liferay 6.1 EE as an Identity Provider
1. Create a folder called SAML-DEMO and two sub folders idp-bundle and sp-bundle.
2. IdP instance is placed under idp-bundle folder and SP instance under sp-bundle folder.
3. Extract the Liferay 6.1.10 EE ga1 tomcat bundle to idp-bundle
4. IdP instance will be running on port 8080.
For signing the SAML messages IdP needs to have private and public keys.
5. Create keystore with keytool that is available with JDK. The keystore is created in idp-bundle/data/keystore.jks
C:liferaySAML-DEMOidp-bundle>keytool -genkeypair -alias samlidpdemo -keyalg RSA -keysize 2048 -keypass password -storepass password -keystore data/keystore.jks
Note: After executing the above command it will prompt for following information and it needs to be provided while creating the keystore. In this case I have created the keystore named “keystore” in the location idp-bundle/data/keystore.jks, which is a default location for SAML message for finding keys while signing the message.
What is your first and last name?
[Unknown]: naidu jitta
What is the name of your organizational unit?
[Unknown]: portal
What is the name of your organization?
[Unknown]: XTIVIA
What is the name of your City or Locality?
[Unknown]: austin
What is the name of your State or Province?
[Unknown]: tx
What is the two-letter country code for this unit?
[Unknown]: us
Is CN=naidu jitta, OU=portal, O=XTIVIA, L=austin, ST=tx, C=us correct?
[no]: yes
6. Add the SAML configuration to portal-ext.properties
saml.enabled=true
saml.role=idp
saml.entity.id=samlidpdemo
saml.require.ssl=false
saml.sign.metadata=true
saml.idp.authn.request.signature.required=true
saml.keystore.path=${liferay.home}/data/keystore.jks
saml.keystore.password=password
saml.keystore.type=jks
saml.keystore.credential.password[samlidpdemo]=password
Here entity id is the alias of the keystore that you created in the previous step.
7. Deploy the SAML plugin using hot deploy. Copy into idp-bundle/deploy folder
8. Start the Liferay server and look for the saml-portlet to be deployed and available.
9. Open http://localhost:8080/c/portal/saml/metadata. If you have configured everything correctly you should see the meta data similar to this.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="samlidpdemo">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>2Y7wxP3wQmWAiIvxqEzlQZ3rzr0=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
yKb38neJv8uu9rUqwwJWjlikcCU61rVc6PirOEWXQ==
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
AkGA1UE....
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<md:IDPSSODescriptor ID="samlidpdemo" WantAuthnRequestsSigned="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>
NBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJ1czELMAkGA1UE...
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/c/portal/saml/slo_redirect"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8080/c/portal/saml/sso"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8080/c/portal/saml/sso"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>
Setting up Liferay 6.1 EE as a Service Provider
1. Extract the Liferay 6.1.10 EE ga1 tomcat bundle to sp-bundle
2. As I am running the two instances on the same machine, I had to change the port number of my SP server. To do that I performed the following steps
a. Go to <<Tomcat Installation Folder>>/conf
and locate server.xml
b. Change server, HTTP and AJP default ports
i. <Server port="8005" shutdown="SHUTDOWN"> to <Server port="8006" shutdown="SHUTDOWN">
ii. <Connector port="8080" protocol="HTTP/1.1" to <Connector port="8081" protocol="HTTP/1.1"
iii. <Connector port="8009" protocol="AJP/1.3" to <Connector port="8010" protocol="AJP/1.3"
3. Create the keystore using java key tool along with the public and private keys.
keytool -genkeypair -alias samlspdemo -keyalg RSA -keysize 2048 -keypass password -keystore data/keystoresp.jks
4. Add the following SAML SP properties to the portal-ext.properties
saml.enabled=true
saml.role=sp
saml.entity.id=samlspdemo
saml.metadata.paths=http://localhost:8080/c/portal/saml/metadata
# # Keystore #
saml.keystore.type=jks
saml.keystore.path=${liferay.home}/data/keystoresp.jks
saml.keystore.password=password
saml.keystore.credential.password[samlspdemo]=password
# # Service Provider #
saml.sp.default.idp.entity.id=samlidpdemo
saml.sp.sign.authn.request=true
saml.sp.assertion.signature.required=false
saml.sp.clock.skew=3000
saml.sp.session.keepalive.url=http://localhost:8080/c/portal/saml/idp/keepalive
saml.sp.user.attribute.mappings=
5. Deploy the SAML plugin using hot deploy. Copy into sp-bundle/deploy
folder
6. Start the Liferay server and look for the saml-portlet to be deployed and available.
7. Open the SAML SP metadata by entering the url http://localhost:8081/c/portal/saml/metadata and you should see the following XML, which means that the SP is configured correctly. Below is the XML that is generated at Service Provider instance.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="samlspdemo">
<md:SPSSODescriptor AuthnRequestsSigned="true" ID="samlspdemo" WantAssertionsSigned="false" 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>
c5P7jzd7STthPjDJvJGm5hd2WGFMsqYKbTtkBEibuwYgTUqy+lLkKg==
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost:8081/c/portal/saml/slo_redirect"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="http://localhost:8081/c/portal/saml/slo_soap"/>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8081/c/portal/saml/acs" index="1" isDefault="true"/>
</md:SPSSODescriptor>
</md:EntityDescriptor>
8. Copy it to a notepad and save it as local-sp-metadata.xml in the IdP instance under data/saml
9. Now modified the IdP instance portal-ext.properties to let it know about the SP. So added the below properties
saml.metadata.paths=${liferay.home}/data/saml/local-sp-metadata.xml
saml.idp.enabled=true
saml.idp.authn.request.signature.required=true
saml.idp.entity.id=samlidpdemo
saml.idp.session.timeout=3600
saml.idp.session.max.age=0
saml.idp.assertion.lifetime=36000
saml.idp.metadata.attributes.enabled=true
saml.idp.metadata.attributes.enabled[samlspdemo]=true
saml.idp.metadata.attribute.names[samlspdemo]=screenName,firstName,lastName,emailAddress,uuid
saml.idp.metadata.session.keepalive.url[samlspdemo]=http://localhost:8081/c/portal/saml/sp/keepalive
10. Restart both IdP and SP instances.
11. Now go to SP Instance http://localhost:8081 and click on the Sign In at the top right corner. You should be directed to IdP instance http://localhost:8080 for authentication.
12. Enter your credentials (in the IdP instance) it will direct to the SP Instance.
That’s all it is. Isn’t it simple? Happy SAML…