
OpenAM Policy Agent Integration
The purpose of this document is to give a step by step tutorial to authenticate users against OpenAM / OpenSSO with Liferay behind a Policy Agent. We assume that you have OpenAM up and running with Policy Agent available. I won't discuss how to set them up here, I'll just give the Policy Agent configuration necessary to make it all work.
Architecture Overview #
VERY IMPORTANT SECURITY COMMENT
As our system entirely relies on trusting HTTP_HEADERS incoming from the Policy Agent, it is mandatory to protect Liferay and its application server against direct HTTP connection that would bypass the Policy Agent. You can use whatever technique you want to avoid this, including AS Binding or VLANs.
How to ? #
Configuring OpenAM / OpenSSO Policy Agent #
Not enforced URLs #
We will configure the Policy Agent so that it lets public pages available without auth. This implies not ot enforce /web, themes, the company logo, login and logout URLs. The agent configuration shall look as follows :
com.sun.identity.agents.config.notenforced.url[0] = https://liferay.starbuck.localdomain:443/web/* com.sun.identity.agents.config.notenforced.url[1] = https://liferay.starbuck.localdomain:443/html/* com.sun.identity.agents.config.notenforced.url[2] = https://liferay.starbuck.localdomain:443 com.sun.identity.agents.config.notenforced.url[3] = https://liferay.starbuck.localdomain:443/combo/* com.sun.identity.agents.config.notenforced.url[4] = https://liferay.starbuck.localdomain:443/image/company_logo* com.sun.identity.agents.config.notenforced.url[5] = https://liferay.starbuck.localdomain:443/ com.sun.identity.agents.config.notenforced.url[6] = https://liferay.starbuck.localdomain:443/c/portal/login* com.sun.identity.agents.config.notenforced.url[7] = https://liferay.starbuck.localdomain:443/c/portal/logout* com.sun.identity.agents.config.notenforced.url.invert = false com.sun.identity.agents.config.notenforced.url.attributes.enable = true com.sun.identity.agents.config.notenforced.ip[0] =
Note that com.sun.identity.agents.config.notenforced.url.attributes.enable has been set to true, so that an already identified user landing on a not enforced URL page could still be authenticated onto Liferay.
Configuring headers #
In this case, we will authenticate the user against Liferay throught its EMail Address. Thus, OpenAM's Policy Agent is configured that way :
com.sun.identity.agents.config.response.attribute.fetch.mode = HTTP_HEADER com.sun.identity.agents.config.response.attribute.mapping[mail] = HTTP_MAIL
In this case, we've chosen to use Session Attributes to fill up Headers. We also use other headers (cn, sn, givenName), but they're not relevant for Liferay auth.
Configuring Liferay #
Considering Liferay, we will have to go through the following steps :
- Enable SiteMinder auth
- Enable OpenSSO auth
- Enable LDAP sync
- Tune autologin hooks order
And as promised, everything's happening inside portal-ext.properties !
Enable SiteMinder auth #
siteminder.auth.enabled=true siteminder.import.from.ldap=true siteminder.user.header=HTTP_MAIL
As you can see, the value of siteminder.user.header corresponds to the Policy Agent configuration key com.sun.identity.agents.config.response.attribute.mapping[mail]. Don't forget to fill in with what reflects your configuration :)
Enable OpenSSO auth #
open.sso.auth.enabled=true open.sso.login.url=https://openam.starbuck.localdomain:443/opensso/UI/Login?realm=/starbuck&goto=https://liferay.starbuck.localdomain open.sso.logout.url=https://openam.starbuck.localdomain:443/opensso/UI/Logout?goto=https://liferay.starbuck.localdomain open.sso.service.url=https://openam.starbuck.localdomain:443/opensso open.sso.screen.name.attr=uid open.sso.email.address.attr=mail open.sso.first.name.attr=givenname open.sso.last.name.attr=sn open.sso.logout.on.session.expiration=false
We activate OpenSSO auth here, but we will not use it at all. We just want to use an out of the box way to tune the actions behind the "Sign In" and "Sign Out" buttons in Liferay.
open.sso.login.url takes two important arguments :
- realm : the realm you want your users to identify to. If you're using / as realm, you can just get rid of this parameter. Note that specifying realm seems to become optional in the upcoming 10.0 OpenAM release.
- goto : this is a very important argument as it's the callback URL OpenAM will redirect the user to after successfull login. Please see Liferay's OpenSSO auth documentation for further details.
open.sso.logout.on.session.expiration has been set to false as we want OpenAM to be the reference for the session's duration.
Enable LDAP Sync #
ldap.base.provider.url.0=ldap://openam.starbuck.localdomain:389/ ldap.base.dn.0=dc=starbuck,dc=localdomain ldap.security.principal.0=cn=Directory Manager ldap.security.credentials.0=changeit ldap.auth.enabled=false ldap.import.enabled=true ldap.export.enabled=true ldap.import.method=user ldap.import.interval=10 ldap.import.on.startup=true ldap.auth.search.filter.0=(mail=@email_address@) ldap.users.dn.0=ou=people,dc=starbuck,dc=localdomain ldap.groups.dn.0=ou=groups,dc=starbuck,dc=localdomain ldap.user.mappings.0=screenName=uid\npassword=userPassword\nemailAddress=mail\nfirstName=givenName\nlastName=sn\njobTitle=title\ngroup=groupMembership ldap.user.custom.mappings.0= ldap.contact.mappings.0= ldap.contact.custom.mappings.0= ldap.group.mappings.0=groupName=cn\ndescription=description\nuser=uniqueMember ldap.import.user.search.filter.0=(objectClass=iplanet-am-auth-configuration-service,sunIdentityServerLibertyPPService,sunAMAuthAccountLockout,sunFederationManagerDataStore,iplanet-am-managed-person,iPlanetPreferences,sunFMSAML2NameIdentifier,person,inetorgperson,organizationalperson,inetuser,iplanet-am-user-service,top) ldap.import.group.search.filter.0=(objectClass=groupOfUniqueNames) ldap.import.user.password.enabled=false ldap.import.user.password.autogenerated=true users.reminder.queries.enabled=false users.reminder.queries.custom.question.enabled=false
Nothing very specific here : LDAP auth is disabled, LDAP sync is on and set. In this case, LDAP connection is made without any encryption (and a dummy password :)) since this configuration has been done on a test environment :)
Things to notice :
- The configuration is pointing at OpenAM's underlying OpenDJ LDAP Server
- ldap.import.user.search.filter.0 has been set to all the values required by OpenAM
- No password import since we don't need it
- A few lines have been added to disable user reminder queries as authentication and account management is the purpose of OpenAM.
Tune autologin hooks order #
auto.login.hooks=com.liferay.portal.security.auth.SiteMinderAutoLogin,com.liferay.portal.security.auth.OpenSSOAutoLogin
In Liferay's default configuration, OpenSSOAutoLogin is fired before SiteMinder's auth. In our case, this would make Liferay always use iPlanetDirectoryPro token to login and never use HTTP_HEADERS, which is not our goal. Thus, we set the order to first use SiteMinderAutoLogin, which will fail in case there is no OpenAM session opened and take precedence over OpenSSOAutoLogin in case OpenAM's session is opened.
Why this page ? #
There are already very good tutorials dealing with Liferay's integration with OpenSSO / OpenAM. Yet, those only cover dealing with the iPlanetDirectoryPro token. The cycle is simple : retrieve the token if it's not available by redirecting to OpenAM's login page. Then back to Liferay, get iPlanetDirectoryPro, send it to OpenAM to retrieve the user's attribute list, then authenticate. This works like a charm but forces Liferay/Apache to send two HTTP requests to OpenAM's server. The aforementioned architecture makes Liferay rely on HTTP Headers, which needs at most one back and forth with OpenAM Server.
SiteMinder already provides Liferay with an authentication scheme that allows authentication through HTTP_HEADERS. With SiteMinder auth, you can set the HTTP header Liferay will rely on (and even import from LDAP). Unfortunately, using the sole SiteMinder authentication makes "Sign Out" unavailable. It fires Liferay's internal session kill then redirects the user onto Liferay with its OpenAM session still active which makes Liferay reauthenticate. Second point is that, if you allow unauthenticated access to Liferay's public pages (/web/guest/home for example), then, the "Sign In" button will not redirect you to OpenAM's login page.
The central position of a portal makes having the "(Single) Sign Out" button on its pages have sense. Moreover, most public portals have pages that shall be rendered without authentication which is only needed to access protected resources or premium services. The method depicted in this page makes the most of both worlds. It enables HTTP_HEADERS based auth and enables "Sign In" and "Sign Out" buttons. This method is a mix of SiteMinder auth and OpenSSO auth that makes everything possible without developing a hook or anything else, just a little configuration.