AcegiSecurity Plugin - LDAP Tutorial

LDAP configuration is beyond the scope of this document as there are many possible ways to configure an LDAP repository. I'll assume that you have the following server configuration:

Name Value
directory base
dc=example,dc=com
repository admin DN cn=admin,dc=example,dc=com
repository admin password secret
server address
ldapserver
server port
389

Summary of steps:

  1. create a Grails application
  2. install and configure the Spring Security plugin
  3. configure LDAP parameters
  4. populate LDAP with groups and users
  5. create secure page for testing
  6. start the server
  7. create security mapping for secure page
  8. create user in the database corresponding to an LDAP user
  9. test
    These steps are very similar to the ones in the basic tutorial - check out that page for more details.

Create your Grails application

# grails create-app bookstore
# cd bookstore

Install the Acegi plugin

# grails install-plugin acegi

Create the User, Role, and Requestmap domain classes

# grails create-auth-domains User Role

Edit User.groovy and change the passwd constraint from 'passwd(blank: false)' to 'passwd(nullable: true)' since passwords are stored in LDAP

Optional - create controllers and GSPs for User, Role, and Requestmap domain classes

# grails generate-manager

Optional - create controllers and GSPs for User, Role, and Requestmap domain classes

# grails generate-registration

Create a controller that will be restricted by role

# grails create-controller Secure

This will create grails-app/controllers/SecureController.groovy - add some output so we can verify that things are working:

class SecureController {

   def index = {
      render 'Secure access only'
   }
}

Configure Parameters

Security parameters are kept in grails-app/conf/SecurityConfig.groovy; the default values and the new values are summarized in this table:

Name Default New Value
useLdap
false true
ldapSearchSubtree true unchanged
ldapGroupRoleAttribute
'cn' unchanged
ldapServer null 'ldap://ldapserver:389'
ldapManagerDn
null 'cn=admin,dc=example,dc=com'
ldapManagerPassword
null 'secret'
ldapSearchBase
null 'dc=example,dc=com'
ldapSearchFilter
null
'(uid={0})'
ldapGroupSearchBase
null 'ou=groups,dc=example,dc=com'
ldapGroupSearchFilter
null 'uniquemember={0}'
ldapRetrieveGroupRoles true false if you don't want to convert LDAP groups to Roles
ldapRetrieveDatabaseRoles false true if you want to access Roles from your database

so the corresponding config file entries would look like:

security {

   active = true
...
   useLdap = true
   ldapRetrieveDatabaseRoles = false
   ldapRetrieveGroupRoles = true
   ldapServer = 'ldap://ldapserver:389'
   ldapManagerDn = 'cn=admin,dc=example,dc=com'
   ldapManagerPassword = 'secret'
   ldapSearchBase = 'dc=example,dc=com'
   ldapSearchFilter = '(uid=\{0\})'
   ldapGroupSearchBase = 'ou=groups,dc=example,dc=com'
   ldapGroupSearchFilter = 'uniquemember=\{0\}'
}

Populate LDAP with groups and users

If you don't have LDAP users and groups already, configure an LDAP server and use these entries for testing:

dn: dc=example,dc=com
objectClass: dcObject
objectClass: organizationalUnit
dc: example
ou: Example Dot Com

dn: ou=groups,dc=example,dc=com
objectclass: organizationalUnit
ou: groups

dn: cn=USER,ou=groups,dc=example,dc=com
objectclass: groupOfUniqueNames
cn: USER
uniqueMember: cn=Some Person,ou=company_name,dc=example,dc=com
uniqueMember: cn=Some Person2,ou=company_name,dc=example,dc=com
uniqueMember: cn=Some Person3,ou=company_name,dc=example,dc=com

dn: cn=ADMIN,ou=groups,dc=example,dc=com
objectclass: groupOfUniqueNames
cn: ADMIN
uniqueMember: cn=Some Person2,ou=company_name,dc=example,dc=com

dn: ou=company_name,dc=example,dc=com
objectclass: organizationalUnit
ou: company_name
description: the name of the company

dn: cn=Some Person,ou=company_name,dc=example,dc=com
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person
userPassword: {SHA}44rSFJQ9qtHWTBAvrsKd5K/p2j0=
cn: Some Person
sn: Person
description: USER

dn: cn=Some Person2,ou=company_name,dc=example,dc=com
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person2
userPassword: {SHA}KqYKj/f81HPTIeAUav2eJt85UUc=
cn: Some Person2
sn: Person2
description: USER
description: ADMIN

dn: cn=Some Person3,ou=company_name,dc=example,dc=com
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: some.person3
userPassword: {SHA}ERnP037iRzV+A0oI2ETuol9v0g8=
cn: Some Person3
sn: Person3
description: USER

This will create the following users:

username password roles
some.person1 password1 ROLE_USER
some.person2 password2 ROLE_USER, ROLE_ADMIN
some.person3 password3 ROLE_USER

Start the server

# grails run-app

Navigate to http://localhost:8080/bookstore/requestmap/create and create the mapping for SecureController:

and navigate to http://localhost:8080/bookstore/user/create (or http://localhost:8080/bookstore/register) to create a test user (leave the password blank or remove the entire field from the GSP since they're stored in LDAP):
Now navigate to http://localhost:8080/bookstore/secure and you should be presented with the login page:

Log in with the username you used for the test user and the password that's stored in LDAP, and you should again be able to see the secure page:

If you prefer to store your url/role mapping statically instead of in the database, skip the Requestmap step and instead make these changes in grails-app/conf/SecurityConfig.groovy:

  • change the 'useRequestMapDomainClass' property to false
  • uncomment the 'requestMapString' property and change its value to:
requestMapString = """
   CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
   PATTERN_TYPE_APACHE_ANT

   /secure/**=ROLE_ADMIN
   /**=IS_AUTHENTICATED_ANONYMOUSLY
"""

Notes

  • By default LDAP group memberships will be converted to Spring Security roles. For example, if a user belongs to the 'Administrator' and 'Manager' groups, these will be converted to ROLE_ADMINISTRATOR and ROLE_MANAGER Roles. You can disable this lookup by setting the 'ldapRetrieveGroupRoles' attribute to false. In this case you'd want to store Roles in your database and access them via your Role domain class and GORM - set the 'ldapRetrieveDatabaseRoles' attribute to true and configure Users' roles just as you would for a regular database-backed authentication store. If both attributes are true, both stores will be searched for Roles.
  • Spring LDAP assumes that passwords are SHA-encoded
  • It may seem redundant to have a User class in the database and also store user-data in LDAP, but this allows more flexibility since you'd want to store application-specific information in the database but shared data in LDAP

Labels

 
(None)