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:
- create a Grails application
- install and configure the Spring Security plugin
- configure LDAP parameters
- populate LDAP with groups and users
- create secure page for testing
- start the server
- create security mapping for secure page
- create user in the database corresponding to an LDAP user
- 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 Spring Security plugin
# grails install-plugin acegi
Create the User, Role, and Requestmap domain classes
# grails create-auth-domains User Role Requestmap
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 Captcha, Register, and an Emailer Service
# 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 Comdn: ou=groups,dc=example,dc=com
objectclass: organizationalUnit
ou: groupsdn: 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=comdn: cn=ADMIN,ou=groups,dc=example,dc=com
objectclass: groupOfUniqueNames
cn: ADMIN
uniqueMember: cn=Some Person2,ou=company_name,dc=example,dc=comdn: ou=company_name,dc=example,dc=com
objectclass: organizationalUnit
ou: company_name
description: the name of the companydn: 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: USERdn: 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: ADMINdn: 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
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