Liferay Sync in a portal using Single Sign On

Why SSO?

Using single sign on (SSO) is probably something that more and more systems aim towards. A large benefit is improved user experience, perhaps not so much for publically available sites. These sites generally attach to Facebook, Twitter or Google and await the crowds going 'aaaaw' in appreciation of the the techniques used.
 
No, instead, imagine a portal used internally by an organization. Most probably the users also login to other web applications. Many.
Where I work a typical administrator log into tens of internal web applications each day. They add up quickly: webmail, liferay portal, HR-system to note your working hours etc, etc.
 
This is where SSO really shines.
But lets take a look at the Liferay portal. There are many ways of solving single sign on (like CAS and other plugins in Liferay or by using Shibboleth with the help of proxies filtering Tomcat), the one thing they have in common is: No password is ever stored locally in Liferay.
Well, that's not really true, there has to be a password. But it's not a password used by the user, most probably it is an auto generated field.  The local password isn't really important in the case of authenticating a user logging in to the portal, as long as we trust someone else telling us that the user is authenticated. In CAS this is done by validating a ticket, in shibboleth by looking at extra headers in the request. 
 
But there are some cases where the password plays an important role.
One is when the SSO framework is offline or simply doesn't work. Make sure you have an admin account that DOES have a local password otherwise it might be difficult to administer your portal in these cases! :)
Another is when using remote services generated by service builder, using webdav to access documents stored in your sites or similarly, when using Liferay Sync to replicate your documents to many devices! In these cases a local password is needed.
 

So, what are the options available to you as a developer in these cases?

If there was a way to insert your own authentication then perhaps you could verify the user yourself perhaps by binding towards an ldap or other.
I set out with my debugger trying to find a good extension point for the Liferay Sync method calls. Liferay sync uses the json-webservices for its interaction with the portal and currently uses preemptive basic authentication, which means that the username/password is sent in the request (hopefully over a secure transport layer).
After a lot of trial-and-error hacking with autologins, authenticators and extensions to the servlet filters I found a very easy path to success.
 

Enter UserLocalService.

Since Liferay Sync uses json webservices and basic authentication we will eventually end up in the UserLocalService. There are methods like authenticateByEmailAddress, authenticateByScreenName and authenticateByUserId that are being used (depending on portal-properties setting) to validate the password of a user.
By creating a simple hook-plugin and overriding these methods you're able to provide your own authentication! Perfect, just what we need! By overriding these methods you're also effectively changing the standard (http) login authentication but since Shibboleth intercepts those redirects the users won't be able to trigger your authentication code by logging into the portals web UI.
 

But what to authenticate against?

The SSO-password is of course a much valued resource. If decrypted a hacker would be able to access a large amount of systems. Storing this password on any device is probably not a good idea in the case of the device getting stolen, hacked or similar.
 
My idea was instead to generate tokens to be used per device and also individually revokeable. That way, if you loose your iPhone you can revoke the access for Liferay Sync for that phone only and not have to reset your SSO-password in all systems.
 
I solved this by creating a small portlet displaying all the currently generated tokens (really, just the description. The token itself is only shown to the user once, at creation, then encrypted) with the option to revoke. Then also a possibility to generate a new token with a given description. The token is shown to the user once, then encrypted into an expando value on the User object.
By using this expando value the UserLocalService-hook can authenticate the user thus enabling Liferay Sync to access user documents!
 

Webdav

Very related to Liferay sync is of course webdav. That is, a way to map a folder directly from your desktop (Document and Media Portlet happily informs you of this all the time) from different operating systems. There are a couple of drawbacks with webdav however, for one not all OS'es support the protocol entirely. For instance from a mac you're able to read documents but not upload new. From Windows 7 32bit it kind of works, but in 64 bits it doesn't. Or was it the other way around? Or was it with ipv6? 
Anyway, lots of quirks. And! Authentication over webdav commonly use digest auth for authentication, there's support for this in Liferay but of course much more complex! It could probably be done, at least by copying source code, but given that the OS-support is very limited we're focusing on the Liferay Sync app instead.

 
Blogs
This is a great extension. Just the idea is worth keeping it in my tool belt and dig it out on occasion. Will you publish either the code (e.g. on github) or the app (on marketplace) or both? Or did I miss the link?
If there's a demand I could publish it on github. Right now it sits in our local subversion where our main work is being done, the risk of also publishing it in github is probably that it will become stale. But sharing something is better than nothing! emoticon
(There's not going to be a marketplace plugin)
Hi Marcus,

I lead the Liferay Sync project and I find your implementation very interesting. If I understood what you did correctly, it seems that your solution doesn't actually authenticate with an SSO provider, but actually provides an alternative authentication mechanism. In your opinion, do you think most Adminstrators would be comfortable with this, or do you think they would actually want all applications to authenticate via the SSO product.

I actually like it very much and find it to be more secure.
Hello Michael!

There are a couple of things that probably needs a bit more work, right now I've done this as a POC (however, it works quite well) and with our setup it fits very well. However, depending on which SSO solution you use it might fit worse. In effect what you're doing is creating more passwords to use/hack.

You are correct in that I don't authenticate against the SSO provider. To be honest, because I couldn't even begin to understand how to get all the parts together to get that to work (Shibboleth uses a daemon in an Apache fronting the LR installation and our Shib requires user input, something that couldn't work with the LR Sync). So, the real reason is because I'm lazy and don't have enough knowledge!
However, since we have the same source of user data as the SSO uses available as LDAP service I could easily have authenticated towards that instead. But since we have a requirement that the SSO-password should never be stored locally / cached (even if encrypted) on a device, that option quickly got off the list. So, generating a password per device != master password was indeed a nice solution and arguably - a more secure solution than using SSO-auth (even if you had the know-how).

For us I believe that we and administrators would be comfortable with the solution. There are many benefits. If you could also bind the login token to one application that would be perfect, in my solution I cannot. But since the standard UI-login is redirected to Shib an ordinary user shouldn't be able to use the token to access the portal UI.

There is still one piece left to consider however: when generating a new password one should really require a new login or similar so that new login tokens cannot be generated just because you left your browser open and left the computer.
Marcus,

Thanks for your explanation. We've had many discussions on the Sync team of how to solve this SSO issue, and what you have proposed definitely was one of the options. Thank you for showing us one concrete implementation (it makes perfect sense to me). We were never sure if this would be a solution that Admins would accept, but the more I look at this solution, the more I think that it is superior to the other options we were thinking of. I really like that

- SSO credentials are never stored on the clients
- tokens are revocable
- will work with any SSO provider
- no need to understand the intricacies of every possible SSO provider

One last piece I think that could be valuable is to somehow bind the token to the device it is assigned to in such a way that it can only be used by that device.

Just to let you know, solving this SSO issue is the top priority for us following our revamped Sync 3.0 release (we are skipping 2.0 due to internal reasons).

Thanks again for showing us this possible solution and validating its use.
Hi Marcus, Where is your team with this issue today. We are a CAS shop and very much want to utilize sync and / or webDAV. Is it solved yet? One must go to DXP/v7 to get it?
Sorry - I meant "Michael" above - Michael Young - Where is your team with this issue today? We are a CAS shop and very much want to utilize sync and / or webDAV. Is it solved yet? One must go to DXP/v7 to get it?