Implementing remember me functionality – part 2

In my last post we were trying to use the built-in persistent cookie mechanisms to implement remember me functionality. This post tries to go beyond that, so we are going to implement our own persistent cookie solution using a custom authentication module and a post authentication processing hook. We need these hooks, because:

  • The authentication module verifies that the value of the persistent cookie is correct and figures out the username that the session should be created with.
  • The post authentication processing class makes sure that when an authentication attempt was successful a persistent cookie is created. Also it will clear the persistent cookie, when the user logs out.

In order to demonstrate this implementation, I’ve created a sample project on Github, so it’s easier to explain, the full source is available at:
https://github.com/aldaris/openam-extensions/tree/master/rememberme-auth-module
You most likely want to open up the source files as I’m going through them in order to see what I’m referring to. ;)

Let’s start with the Post Authentication Processing (PAP) class, as that is the one that actually creates the persistent cookie. In the PAP onLoginSuccess method, I’m checking first whether the request is available (for REST/ClientSDK authentications it might not be!), then I try to retrieve the “pCookie” cookie from the request. If the cookie is not present in the request, then I start to create a string, that holds the following informations:

  • username – good to know who the user actually is
  • realm – in which realm did the user actually authenticate (to prevent accepting persistence cookies created for users in other realms)
  • current time – the current timestamp to make the content a bit more dynamic, and also it gives a mean to make sure that an expired cookie cannot be used to reauthenticate

After constructing such a cookie (separator is ‘%’), I encrypt the whole content using OpenAM’s symmetric key and create the cookie for all the configured domains. The created cookie will follow the cookie security settings, so if you’ve enabled Secure/HttpOnly cookies, then the created cookie will adhere these settings as well.
In the onLogout method of the PAP I make sure that the persistent cookie gets cleared, so this way logged out users will truly get logged out.

On the other hand the authentication module’s job is to figure out whether the incoming request contains an already existing “pCookie”, and if yes, whether the value is valid. In order to do that, again, we check whether the request is available, then try to retrieve the cookie. If there is no cookie, then there is nothing to talk about, otherwise we will decrypt the cookie value using OpenAM’s symmetric key.
The decrypted value then will be tokenized based on the “%” character, then we first check whether the current realm matches with the cookie’s realm. If yes, then we check for the validity interval and the stored timestamp. If things don’t add up, then this is still a failed authentication attempt. However if everything is alright, then we can safely say that the user is authenticated, and the username is coming from the decrypted content.
In case there was some issue with the cookie, then we will just simply remove the “pCookie”, so hopefully we won’t run into it again.

Limitations

There are a couple of limitations with this example module though:

  • when the PAP is part of the authentication process, it will always create a persistent cookie for every single user (but only when the cookie don’t already exist).
  • the validity interval and the cookie name is hardcoded, moreover every single realm will use the same cookie, that can be a problem in certain deployments.

If you are looking for installation details, then check out the Github project README ;)

Implementing remember me functionality – part 1

It’s quite common requirement to have long running sessions within OpenAM, so I’m going to try to enumerate the different ways to achieve “persistent” sessions and provide some comparison.
There is two main way to achieve long running sessions:

  • Using built-in functionality
  • Implementing custom authentication module + post processing class

Today we are only going to deal with the built-in persistent cookie features, the next article will describe the more user-specific solution.

Setting Expires attribute on session cookie

By default OpenAM issues session cookies without Expires attribute, meaning the cookie is only stored until the browser is stopped/restarted. This solution is especially handy if you have large session timeout values set, because in any other cases your session cookie would be saved in the browser for a good while, but the underlying session could have already time out.
Now there are two ways to enable this mode:

  • Enable persistent cookies globally for all sessions:
    Go to Configuration -> Servers and Sites -> Default Server Config -> Advanced tab, then add the following properties:

    openam.session.persist_am_cookie=true
    com.iplanet.am.cookie.timeToLive=100
    
  • After doing so you will probably need to restart the container for the changes to take effect. Any new sessions created afterwards will set the Expires attribute on the session cookie.
    When using DAS you need to set these properties in the DAS configuration file instead.

  • Allow to have persistent sessions on-demand:
    Go to Configuration -> Servers and Sites -> Default Server Config -> Advanced tab, then add the following properties:

    openam.session.allow_persist_am_cookie=true
    com.iplanet.am.cookie.timeToLive=100
    

    In this case to get a persistent cookie you need to include the openam.session.persist_am_cookie=true parameter on the Login URL (so you can’t actually put this on the Login form unfortunately)

  • When using DAS you need to set these properties in the DAS configuration file instead.

NOTE: the timeToLive value is in minutes.
NOTE 2: these properties only fully work on the core servers if you have OPENAM-1280 integrated, but if you use DAS these should work just fine.
NOTE 3: the timeToLive value only tells how long the cookie should be stored by the browser, it has absolutely NO influence to the actual session timeout intervals.

Creating a long living non-session cookie

When using this option OpenAM will create a second “DProPCookie” cookie next to the iPlanetDirectoryPro cookie with an encrypted content. This encrypted cookie stores a set of informations that are necessary to “recreate” a session when a user goes to OpenAM without a valid session cookie, but with a valid persistent cookie. OpenAM then decrypts the cookie and based on the stored information, it will create a new session.
In order to enable this persistent cookie mode you need to go to Access Control -> realm -> Authentication -> All Core Settings page and do the followings:

  • Enable the “Persistent Cookie Mode” option
  • Set “Persistent Cookie Maximum Time” option

After this when you include the “iPSPCookie=Yes” parameter on the login URL, or you have an actual checkbox on your Login.jsp submitting the exact same parameter during login, OpenAM will issue the DProPCookie persistent cookie with the configured timeout.
This method does not seem to be implemented for DAS.
NOTE: OpenAM will delete the persistent cookie as well, when the user logs out.
NOTE 2: due to a possible bug (OPENAM-1777) OpenAM may not invoke Post Authentication Processing classes when it recreates the user session.

Conclusion

As you probably noticed, the Expires on session cookie method is only really useful when you have large timeouts, also it is a global option, meaning that once you enable it, it will be set for all the different realms.
On the other hand DProPCookie is configurable per realm, but it does not seem to work when using DAS.

That’s all folks, this is how the built-in persistent cookies work, if these do not seem to match your requirements, then stay tuned for the next post.

Rotating debug logs

Since OpenAM 10.0.0 it is possible to enable time based debug log rotation in order to make your log files a bit more managable. Time based as in the logs will be rotated periodically after a configurable amount of time has passed.
Now the problem with debug logs is that they get written to in the very early phase of the startup process: just think about the fact that an error can occur already while trying to connect to the configuration store. This means that to store the rotation config, we can’t actually use the service config system, as by the time those settings get loaded, files are already written. To overcome this problem, instead, you need to modify/create files in the WAR file to make these configurations accessible for startup as well.
To enable debug log rotation, you need to create/modify the WEB-INF/classes/debugconfig.properties file:

org.forgerock.openam.debug.prefix=mylogs-
org.forgerock.openam.debug.suffix=-MM.dd.yyyy-kk.mm
org.forgerock.openam.debug.rotation=

The properties in detail:

  • org.forgerock.openam.debug.prefix (optional): an arbitrary string that will be used as a filename prefix for every debug log
  • org.forgerock.openam.debug.suffix (optional): a valid Java dateformat string. Please note that if you set up rotation for every 5 minutes and you don’t include minutes in the format string, then you won’t really rotate the debug log every 5 minutes (the logs won’t get overwritten, you’ll just have one log file with all the content).
  • org.forgerock.openam.debug.rotation: rotation interval for the debug logs in minutes. If rotation interval is higher than 0, then rotation is enabled

Since this has been implemented in the shared Debug class, this also means, that you can put this properties file on ClassPath for any OpenAM component that is using the ClientSDK, so things like DAS and Java EE agents too.
Obviously after creating/modifying the properties file, you have to restart the container for the changes to take effect.

Let’s revive this blog ;)

I know, I know… It’s been a while… Believe me I feel the guilt… I should really share more with the community, so here I am begging for your mercy, and also for your help.
Recently I often find myself a bit clueless, as I don’t know what to write about any more, there are just too many subjects about OpenAM. :)
So I think the best way to resolve this issue is probably to ask the readers themselves: what would you like to read about? Are there any areas where the documentation could be enhanced? Tell me. I’ve created a very simple Google Form here:
https://docs.google.com/spreadsheet/viewform?formkey=dGVXeDZ2SlQxbmtIS1dpT3ZZb1F5QlE6MQ.

By filling this out you can help me to figure out:
* what subjects are people most interested in
* how many active readers I might have :)

Guaranteed to take less than 5 minutes!

Thanks in advance.

How to use Certificate module with DAS

Previously I have described how to install the DAS properly. Today’s entry is all about using the Certificate authentication module in a deployment where you have a DAS instance. So here are the steps required to make this work:

  • Follow the DAS install guide, but with the only difference being that you install the DAS on a HTTPS URL (OpenAM can keep running on HTTP). Since you are now using HTTPS, you need to make sure that the OpenAM server trusts the DAS’s certificate, otherwise OpenAM won’t be able to send notifications to the DAS, which could result in strange situations when a given session remains valid for a short period of time even though the user has logged out on a different DAS instance.
  • Go to Access Control – realm – Authentication page and Add a new Module Instance called cert with type Certificate
  • Open the Certificate module configuration, and change the followings:
    • Set the LDAP Server Authentication User/Password to correct values
    • For evaluation purposes set the Trusted Remote Hosts to “all”
  • Generate a new self signed certificate by following this guide, but make sure that in the CSR you set the CN to “demo”.
  • Create PKCS#12 keystore for the freshly generated private key and certificate:
    openssl pkcs12 -export -inkey server.key.org -in server.crt -out server.p12
  • Install the PKCS#12 keystore in your browser (Guide for Firefox)
  • Enable Client Authentication on the DAS’s container. For example on GlassFish 3.1.2 Admin Console you would have to go to Configurationsserver-configHTTP serviceHttp Listenershttp-listener-2 then open the SSL tab and check the Client Authentication option.
  • Install the public certificate into the container’s truststore, so the container will actually trust your certificate:
    keytool -import -keystore glassfish3/glassfish/domains/domain2/config/cacerts.jks -file server.crt -alias mycert

    You need to make sure that you install the certificate to the actually used truststore, some containers may use the JVM’s truststore instead having one on their own.

  • On the DAS enable the Request/Response serialization by setting the following property in the ~/FAMDistAuth/*.properties file:
    openam.remoteauth.include.reqres=true
  • Restart the DAS’s container
  • Open /auth/UI/Login?module=cert and choose your certificate
  • Profit

Federation with Shibboleth SP (Apache module)

When you want to achieve Federation between different organizations, you often find yourself in a situation where the products used by the parties are different. Before we go any further I should make the terminology clear:
Identity Provider (IdP): The IdP holds all information about the user (for example in LDAP), and also it is the IdP’s job to authenticate the users, and decide on what kind of informations it shares about the users with other providers.
Service Provider (SP): The easiest way to think about the SP as an extra layer in front of the webapplication. The SP’s job is to authorize pagerequests, and if there is no authenticated session at the SP, initiate an authentication request to the IdP.

Today the goal is to achieve SSO between an OpenAM IdP and a Shibboleth SP with the simplest settings as possible.
This tutorial assumes that you already have a configured OpenAM instance running under idp.example.com.

Configure the IdP

  • Log in to the admin console and on the Common Tasks pane click on the Create Hosted Identity Provider link.
  • Select No for Do you have metadata for this provider
  • Use http://idp.example.com:8080/openam as Name
  • Select the default test Signing Key
  • Use cot as the name of the New Circle of Trust
  • Leave the Attribute mapping table empty
  • Press the Configure then the Finish button

Install and configure Shibboleth SP (on Ubuntu)

This tutorial was done with Ubuntu 11.04. If you have other OS/version it’s possible that the paths/steps will be different for you.

  • Install the Shibboleth SP Apache module:
    apt-get install libapache2-mod-shib2
  • Open the /etc/shibboleth/shibboleth2.xml configuration file using a text editor
  • In SPConfig -> InProcess -> ISAPI -> change the Site tag to:
    <Site id="1" name="sp.example.com"/>
    
  • In SPConfig -> RequestMapper -> RequestMap change the Host tag to:
    <Host name="sp.example.com" applicationId="sp.example.com" />
    
  • In SPConfig change the ApplicationDefaults opening tag to:
    <ApplicationDefaults id="default" policyId="default" 
    entityID="http://sp.example.com/shibboleth" 
    REMOTE_USER="eppn persistent-id targeted-id" 
    signing="false" encryption="false">
    
  • In SPConfig -> ApplicationDefaults -> Sessions change the /Login SessionInitiator‘s opening tag to:
    <SessionInitiator type="Chaining" Location="/Login" 
    isDefault="true" id="Intranet" relayState="cookie" 
    entityID="http://idp.example.com:8080/openam">
    
  • In SPConfig -> ApplicationDefaults -> MetadataProvider create a MetadataProvider:
    <MetadataProvider type="XML" file="idp.xml" />
    
  • In SPConfig -> ApplicationDefaults create an ApplicationOverride:
    <ApplicationOverride id="sp.example.com" 
    entityID="http://sp.example.com/shibboleth" /> 
  • Save the configuration file
  • Make sure that the files referred in SPConfig -> ApplicationDefaults -> CredentialResolver actually exist, and if necessary, generate a self signed certificate (using this guide for example).
  • Open http://idp.example.com:8080/openam/saml2/jsp/exportmetadata.jsp in your browser and save the XML as /etc/shibboleth/idp.xml (as configured in the MetadataProvider tag). (See this post for more information about exporting metadata.)
  • Open the /etc/shibboleth/attribute-map.xml config file and add the following line:
    <Attribute name="urn:oid:0.9.2342.19200300.100.1.1" id="HTTP_UID"/>
    

Prepare the Apache configuration

You need to configure Apache as well to make this setup work:

  • Make sure, that there is an sp.example.com VirtualHost in your Apache config
  • If you want to use .htaccess you need to enable the AllowOverride AuthConfig in the VirtualHost config
  • Create an index.php file in your docroot containing:
    <?php
    phpinfo();
    ?>
    
  • Create a .htaccess file in your docroot containing:
    AuthType shibboleth
    ShibRequireSession On
    require shibboleth
    
  • Enable the Apache Shibboleth module:
    a2enmod shib2
    
  • Restart Apache:
    /etc/init.d/apache2 restart
    

Registering the SP at the IdP

If you’ve done everything right so far, then you can access your Shibboleth SP Metadata at http://sp.example.com/Shibboleth.sso/Metadata. In case the Metadata does not contain a certificate check the logs at /var/log/shibboleth/shibd.log, also please remember that whenever you change the Shibboleth config you need to restart the Shibboleth service:

/etc/init.d/shibd restart

NOTE: OPENAM-792 can cause you troubles while importing the metadata. Make sure you either have the fix for this issue, or you have removed the Extensions tag from the Metadata before uploading it.

If everything is OK with your Metadata open the OpenAM admin console and click on the Register Remote Service Provider link on the Common Tasks pane.

  • You can either upload the Metadata or provide the URL on the config page.
  • Leave the attribute mapping empty
  • Click on the Configure button
  • Go to the Federation page then open the SP’s page in the Entity Providers table
  • Go to the Assertion Processing tab
  • In the Attribute Map list add the following value:
    urn:oasis:names:tc:SAML:2.0:attrname-format:uri|
    urn:oid:0.9.2342.19200300.100.1.1=uid
    
  • Save the configuration and log out

How to test

You just need to open a random URL under sp.example.com, and the htaccess config you created will make sure that the user is authenticated at the IdP. Opening such URLs should result in a redirect to the IdP presenting a login screen for you. After submitting the valid credentials you should be redirected back to the SP application to the originally requested URL. On the phpinfo page you should see the HTTP_UID server variable holding the user’s name.

In case you want to use the REMOTE_USER CGI variable in your applications, you can achieve that by modifying the Shibboleth configuration: in SPConfig -> ApplicationDefaults add HTTP_UID to the beginning of the REMOTE_USER attribute.