Tuesday, October 13, 2015

Authenticating an IBM BlueMix app using IBM Connections

Maybe because I asked a few questions around authentication during an app dev session at IBM Leadership Alliance, I got a few people coming to me and asking how authentication can be achieved using IBM Connections Cloud. In particular, how can you get your IBM Bluemix app run under a user identity provided by IBM Smartcloud. I'm not going to talk how IBM Connections Cloud can leverage your own directory to authenticated user, using SAML, but the other way.

Let's talk about a Java app running in a J2EE container. The way you would normally authenticate users is by making the application server point to a directory server, generally LDAP based. In TOMCAT, you would configure server.xml. In IBM WebSphere, you do that through the admin UI. But unfortunately, IBM does not expose an LDAP directory to external applications, nor a service these application servers can point to.

What IBM provides us is a REST API that returns the authenticated user profile document:
The old, now deprecated but still working API, is:

If you hit this URL from your browser, you'll be prompted for authentication and then you'll get your personal profile document.

This can of course be called programmatically, by either using pre-emptive basic authentication with a user/password, or by running the OAuth dance and connect with an OAuth token. The later is what we are actually doing in ProjExec. Note that the whole OAuth process can be nicely handled for you by the IBM Social Business Toolkit. You need to get your app registered in your org, and voila. The IBM SBT provides server side Java code.

The next question is ok, I know who is the current user. But what can I do with that, because this is not known by the application server. The servlet API does not provide a setPrincipal() method you can use to force the user. So, unless you want to target a specific web app server and implement their internal APIs (TOMCAT allows custom Realm to be implemented), then you cannot use the built-in J2EE security features of the application server. Furthermore, there is no easy way to get this deployed and attached to an IBM Bluemix server, at least when you create the server using the standard buildpack.

The pure J2EE solution is to use a filter. You can create your own, which we did, or use a library like Apache Shiro. You would probably be more effective by creating your own, if you're only interested by IBM Connections Cloud.
What the filter does is pretty simple:
- It looks in the J2EE session for a "conn_user" attribute, holding the current user id
-> if it does not exist, then it starts the OAuth dance with the browser, grabs the user identity from the URL mentioned above, and then it stores this identity in the session as "conn_user".
- It uses the "conn_user" id to allow, or not, access to the URL. We externalized the definition of the authorization in an XML file that is read by the filter.

Another implementation of the filter do not use the session but passes the identity as a transient, http only cookie. This cookie contains an encrypted version of the user identity, with an expiration timestamp, so it gets invalidated after a while. The cookie changes after every request, with a new expiration date included.

If you want to connect to IBM Connections using basic authentication (which I do not advise), then your filter can prompt the user with a form where the user can enter its name/password. This is like form based authentication for your app, and reusing the user/password to connect to Connections. But be very careful with such a solution, as you can compromise the IBM userid/password of your user. Better for you to not even know the password!