Of Directory ACI's, ProxiedAuthorization and SSO
I wanted to share an example which can be used by a developer to integrated LDAP authorization with Sun Java System Directory Server into an application. The application, of course, can then be integrated into a SSO infrastructure such as Sun Java System Access Manager to bridge the gap between authentication, SSO, and application level authorization.
In order to provide a high performance connection to the LDAP server, a connection pool (ouside the scope of this posting) can be used and in order to enforce the LDAP aci's proxied authorization can be used. Since this is not a part of the standard jndi package, the JNDI/LDAP Booster Pack 1.0 can be used for this purpose. The Booster Pack includes a LDAP control, which when added to the jndi configuration will produce the desired behaviour. Description of the control: ProxiedAuthorizationControl - Performs the requested LDAP operation as the specified authorization identity
This is not new, this has been around for many years, but I wanted to share this as a technique to establish an authorization model in an application, then provide a way for SSO to pass the information necessary to enable the application to recognize the current user and enforce their privledges.
In order to test this, we first must setup the LDAP server and the ACI's which will be enforced:
Here is the ACI for a suffix named o=jolt:
dn: o=jolt changetype: modify replace: aci aci: (targetattr = "cn || givenName || uid || TelephoneNumber || sn || givenname || mail || displayName || employeenumber || facsimilietelephonenumber || objectclass || destinationindicator || employeetype")(version 3.0;acl "JOLT Proxy (Anon)";allow (read,compare,search)(userdn = "ldap:///uid=joltadmin,ou=People, o=jolt");) aci: (targetattr = "cn || givenName || uid || TelephoneNumber || sn || givenname || mail || displayName || employeenumber || facsimilietelephonenumber || objectclass || facsimilietelephonenumber || mobile || homephone || destinationindicator || manager || physicaldeliveryofficename || roomnumber || postaladdress || postalcode || st ||street || entryid || l || ou || parentid") (version 3.0;acl "Authenticated users access";allow (read,search,compare)(userdn != "ldap:///uid=joltadmin, ou=People, o=jolt");) aci: (targetattr = "givenName || uid || TelephoneNumber || sn || givenname || mail || displayName || employeenumber || facsimilietelephonenumber || mobile || homephone || objectclass || destinationindicator || manager || physicaldeliveryofficename || roomnumber || postaladdress || postalcode || st || street || entryid || l || ou || parentid") (targetfilter = (employeetype=*))(version 3.0;acl "Sales Group Access";allow (all)(groupdn = "ldap:///cn=Sales Group,ou=Groups,o=jolt");) aci: (targetattr = "*") (version 3.0;acl "JOLTadmin Proxy rights";allow (proxy)(userdn = "ldap:///uid=joltadmin,ou=People,o=jolt");)
This ACI does a few things to demonstrate privledges to different users:
- Proxy (Anon) - This is the default access level for the application which will use this proxy account (userdn = "ldap:///uid=joltadmin,ou=People, o=jolt"), attributes allowed: cn, uid, TelephoneNumber, sn, givenname, mail, displayName, employeenumber, facsimilietelephonenumber, objectclass, destinationindicator, employeetype
- Allow the following user to proxy ldap requests for other users: userdn = "ldap:///uid=joltadmin,ou=People,o=jolt"
- Authenticated users access - This is the ACI that will be enforced for authenticated users (through the proxy), attributes allowed: cn, uid, TelephoneNumber, sn, givenname, mail, displayName, employeenumber, facsimilietelephonenumber, objectclass, destinationindicator, employeetype, manager, physicaldeliveryofficename, roomnumber, postaladdress, postalcode, st, street, entryid, l, ou, parentid
- Sales Group Access - allow even more access if the authenticated user is in the Sales Group, allowed attributes: mobile, homephone
Here is an example of using the command line ldapsearch to login as the user joltadmin, and proxy the request for Robert.Bailey. The -Y is used to identify the use to encorce the ACI's for:
ldapsearch -D uid=joltadmin,ou=People,o=jolt -w joltpassword -Y dn:uid=Robert.Bailey,ou=People,o=jolt -b o=jolt uid=Robert.BaileyIn the whitepages application, this will allow anonymous users (through the joltadmin connection pool) to access a limited set of attributes for users they are looking up.
User who are authenticated (and will be proxied through the joltadmin user) will also be able to view these ldap attributes for records they lookup: physicaldeliveryofficename, roomnumber, postaladdress, postalcode, st, street, entryid, l, ou, parentid
An users who are in the Sales Group (and will be proxied through the joltadmin user), will also be able to view these ldap attributes for records they lookup: mobile, homephone
This can be confirmed with a command line ldapsearch.
The Ldap Booster Pack includes a jar file: ldapbp.jar, which must be added to the classpath.
Here is an example of the relevant snippets of jndi code to test it.
// specify jndi connection information
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=jolt");
env.put(Context.SECURITY_PRINCIPAL, "uid=joltadmin,ou=people,o=jolt");
env.put(Context.SECURITY_CREDENTIALS, "joltpassword");
// create an initial context using the supplied environment properties
LdapContext ctx = new InitialLdapContext(env, null);
// activate the control
ctx.setRequestControls(new Control[] { new ProxiedAuthorizationControl("dn:uid=chuck.boyle,ou=people,o=jolt")});
// Ask for all attributes of the object
Attributes attrs = ctx.getAttributes("uid=chuck.boyle, ou=People");
Now test the configuration to ensure that the Sun Directory ACI's are being enforced by editing the userdn in the ProxiedAuthorizationControl, and adding the user to the Sales group.
Finally, Single Sign on integration with Sun Java System Access Manager can be accomplished by configuring an Access Manager agent to protect the application (and configure Access Manager policies to allow users to access the application) and to insert an http header which is equal to the user dn that the application will extract and pass to the ldap request.
