Tag: Central Authentication Service

Deciding where to handle authorization in a setup where Alfresco’s authentication is handled by CAS which itself authenticates against LDAP may not be as easy as it sounds. This post goes through some of the possibilities and one solution.

LDAP Authentication with an Expiration Date Attribute

On Alfresco version 2.x we extended the LDAPAuthenticationComponentImpl class to be able to evaluate an LDAP filter string, configurable via spring, which was used primarily for the purpose of determining whether the user’s access to Alfresco had expired, with the expiration date being stored as an LDAP attribute. So our ldap-authenication.properties file would contain something like:

Once the expiration date was reached the user was denied access to the application.

Moving to Single Sign On

We’re now migrating to Alfresco 3.x and also have the need to move to a single sign on solution. Jasig’s Central Authentication Service (CAS) was chosen as the implementation, requiring some changes to our expiration strategy.

In our previous configuration, authentication (is this user who they say they are) and authorization (is this user allowed to do x) were intertwined in our single custom LDAPAuthenticationComponentImpl class. Any other applications authenticating against the same LDAP server could implement their own authentication/authorization methods.

CAS however is only concerned with authentication, not authorization, and applications utilizing it need to be able to decouple those functions, which is a better architecture in most cases anyway.

Our task then is to determine where in the authentication/authorization strategy we should handle this expiration authorization.

Choosing Where to Handle Authorization

Customize the CAS Server?

Modifying the CAS LDAP authentication handler wouldn’t be an appropriate place for our expiration authorization since all CAS services share the same authentication handler and other applications that have no notion of the Alfresco service or its expiration could be denied authentication.

We could try implementing a CAS authorizing serviceRegistryDao which would in theory allow the CAS server to determine if the user were authorized to use the service requested beyond just the Enabled and SSO Participant settings. An authorization component could be defined that would make the authorization decision based on the service being requested and the user requesting it. Each service could choose its authorization component as an option during setup in the CAS Service Management application.

CAS really wants the client/application to handle authorization though, so customizing the server doesn’t look like a recommended approach.

Customize Alfresco?

We could setup Alfresco’s authentication chain to talk to CAS, but in version 3.2 Alfresco has changed its authentication configuration to use the notion of Authentication Subsystems (which seems nicely implemented) and most documentation indicates that integration with something like CAS is best achieved by using mod_cas or mod_auth_cas in Apache web server, and since we’re already using Apache in front of Tomcat with mod_proxy_ajp that approach seems like a good fit.

Wait, Can a Hacker Just Spoof HTTP Headers?

It looks like AJP between Tomcat and the web server is responsible for parsing these protocol specific (non-HTTP) headers to find the remote user value and set that in Tomcat’s HttpServletRequest, so a hacker can’t just modify the headers in their browser and have that be translated into an authenticated user.

However, it is extremely important that your Tomcat connector be behind a firewall and only accept connections from known web servers. Otherwise a hacker could set up their own web server with a bogus authentication mechanism which would add an authenticated user header in the AJP message, which in turn would translate to that user being signed in to a protected application.

mod_cas or mod_auth_cas?

With proper security in place we should be OK to use an Apache CAS module for authentication, but which one?

mod_cas:

hasn’t been maintained in quite a while

has missing links all over the site

the documentation incorrectly states that “CAS stands for Common Authorization Service”

Option 1: Extend Alfresco’s Request Authn to Grab CAS Attribute

The CAS server can return attributes to the client and if mod_auth_cas passes those attributes through mod_proxy_ajp to Tomcat and Alfresco then we may be able to modify the component which checks that header for the authenticated username, HTTPRequestAuthenticationFilter, to also look for the expiration date attribute and authorize or deny the user.

After modifying Tomcat’s example snoop application to show all headers and attributes:

it doesn’t look like the additional attributes defined to be available to the CAS service are passed through mod_auth_cas and mod_proxy_ajp to the secured application. We might be able to pass the data through SAML attributes but it seems that would require POST requests.

Option 2: Extend Alfresco’s Request Authn to query LDAP directly

If we can’t get the expiration date attribute from the request headers we still may be able to modify the request authentication filter to make a trip directly to the LDAP server to query for the attribute and confirm or deny authorization, but maybe we can do everything at the web server.

Option 3: Handle Authorization at Apache

The ‘auth’ in mod_auth_cas appears to only include authentication but there may be hope in allowing mod_auth_cas to handle just the authentication part then using mod_authnz_ldap or the third-party mod_authz_ldap module to handle the authorization side.

mod_authnz_ldap’s Require ldap-filter looks promising, but we would need to insert a dynamic date (today’s) for comparison to the user’s expiration date. LDAP syntax doesn’t seem to have any keyword for the current date to be handled on the server side and it doesn’t look like mod_authnz_ldap has any special tags for injecting it in the filter string so the source code would have to be modified.

Unfortunately, upon further investigation mod_authz_ldap does not support secure SSL/TLS communication with the LDAP server and hasn’t been maintained in a quite a while, so that won’t work.

Dare I try modifying the mod_authnz_ldap source to allow for a dynamic replace of a date tag? Sure, why not?

The last time I wrote C code it was probably on a machine running Mac OS 7.6, but after several hours and as many espressos I’ve taken the relevant code from mod_authz_ldap’s source, tweaked it a bit, and found the appropriate place to inject it in mod_authnz_ldap’s authn_ldap_build_filter.

You can compile and install a single module on the server with:

apxs -i -a -c mod_authnz_ldap.c

then add the appropriate config to your location directive. So we have CAS performing authentication and a modified mod_authnz_ldap performing authorization on our Tomcat examples app: