Tuesday, January 12, 2010

Piggyback Acegi on external user/role management

For a variety of reasons, we need to store our users and roles in a different database schema and structure than comes with Grails... but we definitely want to use the Acegi plugin. Also, there is no LDAP or SSO so the goal was to make Role and Person use tables in another schema in the same database (managed by a different web app.)

The approach is to map the Role, Person and RolePerson (implicit) entities to views. Using a view to select from the other tables, makes one-way synchronization trivial.

1. Create a view called ROLE_VW which selects from the roles table and maps the columns to what Role.groovy expects. I appended 'ROLE_' to the Authority so that Acegi will respect it as a role. The actual role names in the other schema don't include it and are named like: "Administrator." I also did an "upper" just to follow an all-caps convention in the annotation based @Secured in the controllers. "Participant" is the table name in the other schema (from the existing app with user mgmt capability).

create view role_vw as
select OID as ID,
'ROLE_'||upper(id) AS AUTHORITY,
0 as VERSION,
id as DESCRIPTION
from otherapp.participant
/

create view people_vw as
select
oid as id,
account as USERNAME,
firstname||' '||lastname as USER_REAL_NAME,
password as PASSWD,
email as EMAIL,
1 as EMAIL_SHOW,
1 as ENABLED,
0 as VERSION,
description as DESCRIPTION
from otherapp.workflowuser
/

create view people_to_role_vw as
select ID as ROLE_ID,
up.WORKFLOWUSER AS PERSON_ID
from otherapp.user_participant up, otherapp.participant p
where up.participant = p.oid
/

Then update the groovy classes to use these:

Role.groovy:
static mapping = {
// mapping to a view because info is maintained in a separate schema
table 'role_vw'
people joinTable:[name:'PEOPLE_TO_ROLE_VW']
}
Person.groovy
static mapping = {
// mapping to a view because info is maintained in a separate schema
table 'people_vw'
authorities joinTable:[name:'PEOPLE_TO_ROLE_VW']
}

Lastly, the passwords stored by the other app are unencrypted. Therefore, to disable encryption place this snippet in the ./conf/spring/resources.groovy:

beans = {
passwordEncoder (org.springframework.security.providers.encoding.PlaintextPasswordEncoder)
}
-Ben Hidalgo

No comments:

Post a Comment