Spring Security Spike

Spike Timebox: 5 days (Mon 11 April 2010 - Friday 16 April 2010)

Purpose

  1. Currently we have an exisiting solution for Authentication and Authorization (see Application Security in Mifos) that still needs to be supported with move to spring security.
  2. We also wanted to investigate the usage of spring expression language as a means for providing more flexible Authorization (e.g. can disburse loans as long as amount <= allowedAmount of user/center/branch etc)

What was learned

  1. Spring Security is flexible enough to provide way of supporting existing implementation
  2. We can use spring expression language (spring 3 feature) for providing more flexible autorization rules (access control) but to make use of this will require fixing up the way we use spring and injected service within the application.
  3. Our current filters (DatabaseInitFilter, LoginFilter) and MifosRequestProcessor (servlet) will become obsolete
  4. MD5 hashing out of box from spring didn't work with current (MD5 hashed) passwords stored as blob in database.
  5. We should re-examine our approach to roles and permissions with respect to the way our customers users use the application.

Supporting Existing Authentication and Authorization

Authentication

Spring security references a schema for using it out of the box with regards authentication. But mifos already uses the PERSONNEL table for storing application user details. So can create a custom AuthenticationManager for use with spring security:

see:

  1. MifosAuthenticationProvider
  2. AuthenticationDaoHibernate
  3. MifosUser -> UserDetails (from spring)
    • NOTE: see MD5 hashing issue for why MifosAuthenticationProvider and MifosUser currently is needed.

So the following was needed to be done or is needed to be done:

  1. Needs to be deployed with correct spring security dependencies - requires spring-security-config (DONE and commited to trunk)
  2. Needs to be configured to load through web.xml file (DONE, not commited to trunk)
  3. Write custom files for enabling authentication with spring security (DONE and commited to trunk)
  4. Configure application to use spring security for login success and failure, logout, session timeout etc (NOT DONE)
  5. When above is done we should remove LoginFilter

Authorization

With the spike approach, authenticated users are given an autorithy of 'ROLE_FULLY_AUTHENTICATED_USER'. Application users must have this authority to access any application URI. We also need to support the current mifos authorization approach which allows adiminstrators to create 'dynamic' roles, each which can be configured with a set of 'permissions' (activities). At various stages within the application, the application users 'permissions' are checked against the task they are carrying out to see if they have authorization.

The following are responsible for achieving this:

  1. MifosRequestProcessor
  2. AuthorizationManager
  3. ActivityMapper

With spring security we can write an AccessDecisionVoter to mimic this authorization approach.

See

  1. DynamicAuthorizationVoter

The intention would be move this authorization down to services away from struts and make use of spring 3s expression language to write more flexible authorization rules.

So the following was needed to be done or is needed to be done:

  1. fully implement voter to take over legacy responsibility (PARTIALLY DONE)
  2. configure custom access decision manager (DONE + COMMITED)
  3. when above is done, should be able to remove need for MifosRequestProcessor

Use out of the box MD5 Hashing

Using the out of box MD5 hashing/encoding did not work with the currently hashed passwords. I believe that this is because they are stored as binary blob and not as a string representation.

As a result I needed to write a custom DaoAuthenticationProvider and override the additionalAuthenticationChecks method so that it used the mifos PasswordHashing for verifing passwords were correct.

I also had to create MifoUser (rather than uses springs User) as when I converted the bytes received from database into string and back into bytes for verification, one byte was being changed from its original state causing password verification to fail so i had to return the bytes from MifoUser instead of converting to String!!!

  1. Use springs MD5 hashing and remove EncryptionService and PasswordHashing

Use expression language for flexible authorization

In order to use spring expression language annonations at method level on services etc, these need to be loaded in the same application context thus

  1. update web.xml file to create webApplicationContext using contextListener
  2. move away from loading spring programmatically using SpringUtil.initialiseSpring() - one problem here might be the support of mifosBeanConfig.custom.xml - need to find out what customers use this and find a solution for not using it.
  3. when (2) is complete, move away from DependencyInjectedServiceLocator by using the WebApplicationContext to get access to all beans within struts BaseAction. - may have to still retain DependencyInjectedServiceLocator to keep struts integration tests passing as struts actions are injected using Spring.
  4. services and hibernate-daos need to be loaded with application context also.

Further Analysis of Roles and Permissions (as used by our customers application users)

We should examine our solution in terms of roles and permissions. By looking at our customers, their business processes and the way they use our application we can come up with roles that better match the way they work. e.g. ROLE_DATA_ENTRY, ROLE_REPORTS_USER, ROLE_ADMIN, ROLE_ACCOUNTS_OFFICER etc

This would help customise the application towards the type of user using it.

We can have a solution that makes use of HIERARCHIAL ROLES and still preserve the flexibility of fine grained permissions per role type. This would allow us to write cleaner authorization rules.

Maybe we should map each current 'activity' or 'permission' to a spring security granted authority and create hierarchial roles to simplify access rules.