[ControlTier] Caching Login Module

34 views
Skip to first unread message

Noah Campbell

unread,
May 3, 2010, 8:01:28 PM5/3/10
to contr...@googlegroups.com
I wrote a caching LoginModule for Jetty that should speed up many operations when using Active Directory or any Ldap based directory service.

If you're interested, I'm happy to contribute it to the ControlTier project.

-Noah

--
You received this message because you are subscribed to the Google Groups "ControlTier" group.
To post to this group, send email to contr...@googlegroups.com
To unsubscribe from this group, send email to controltier...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/controltier?hl=en
http://wiki.controltier.org

Greg Schueler

unread,
May 3, 2010, 8:44:48 PM5/3/10
to contr...@googlegroups.com
Hi Noah,

Thank you, that would be very useful. Can you submit a feature
request and attach the code to the tracker item? That way we can get
it rolled into the source with appropriate attribution.

Noah Campbell

unread,
May 3, 2010, 8:54:23 PM5/3/10
to contr...@googlegroups.com

Anthony Shortland

unread,
May 7, 2010, 3:04:02 PM5/7/10
to contr...@googlegroups.com
Thanks, Noah.

Here are my notes from getting this working in against our standard OpenLDAP setup (http://controltier.org/wiki/Setting_up_an_OpenLDAP_instance_to_support_ControlTier) using 3.4.11.



[user3@centos54 tmp]$ pwd
/home/user3/tmp
[user3@centos54 tmp]$ ls
ctldapmodule.tar.gz
[user3@centos54 tmp]$ mkdir ctldapmodule
[user3@centos54 tmp]$ cd ctldapmodule
[user3@centos54 ctldapmodule]$ tar zxf ../ctldapmodule.tar.gz 
[user3@centos54 ctldapmodule]$ ls
build.xml  examples  README  src

  • Built the custom login module against my 3.4.11 install per the instructions in the README:

[user3@centos54 ctldapmodule]$ echo $JETTY_HOME 
/home/user3/ctier/pkgs/jetty-6.1.14
[user3@centos54 ctldapmodule]$ . $CTL_BASE/etc/profile
[user3@centos54 ctldapmodule]$ $ANT_HOME/bin/ant 
Buildfile: build.xml

init:
    [mkdir] Created dir: /home/user3/tmp/ctldapmodule/build

compile:
    [javac] Compiling 1 source file to /home/user3/tmp/ctldapmodule/build

dist:
    [mkdir] Created dir: /home/user3/tmp/ctldapmodule/dist/lib
      [jar] Building jar: /home/user3/tmp/ctldapmodule/dist/lib/ctsec-20100507.jar

BUILD SUCCESSFUL
Total time: 7 seconds

  • Copied the Jar into the Jetty installation:

[user3@centos54 ctldapmodule]$ cp dist/lib/ctsec-20100507.jar $JETTY_HOME/lib

  • Updated the LDAP login module configuration file (from the Wiki) to use the custom class:

[user3@centos54 etc]$ diff ldap-loginModule.conf ldap-loginModule.conf.orig 
2c2
<     org.controltier.security.authorization.ControlTierLdapLoginModule required
---
>     org.mortbay.jetty.plus.jaas.spi.LdapLoginModule required
20,22d19
<     rolePrefix=""
<     cacheDurationMillis="10000"
<     reportStatistics="true";

[user3@centos54 etc]$ cat ldap-loginModule.conf
ldaploginmodule {
    org.controltier.security.authorization.ControlTierLdapLoginModule required
    debug="true"
    contextFactory="com.sun.jndi.ldap.LdapCtxFactory"
    hostname="localhost"
    port="389"
    bindDn="cn=Manager,dc=controltier,dc=com"
    bindPassword="secret"
    authenticationMethod="simple"
    forceBindingLogin="false"
    userBaseDn="ou=users,dc=controltier,dc=com"
    userRdnAttribute="cn"
    userIdAttribute="cn"
    userPasswordAttribute="userPassword"
    userObjectClass="person"
    roleBaseDn="ou=roles,dc=controltier,dc=com"
    roleNameAttribute="cn"
    roleMemberAttribute="uniqueMember"
    roleObjectClass="groupOfUniqueNames"
    rolePrefix=""
    cacheDurationMillis="10000"
    reportStatistics="true";
    };

  • Restarted Jetty and logged in. Here's the Jetty log output:

2010-05-07 10:16:22.269::WARN:  No CallbackHandler configured: using DefaultCallbackHandler
2010-05-07 10:16:22.299::INFO:  Login attempts: 1, Hits: 0, Ratio: 0%.

... the last line confirms that we hit the custom login module ... sweet!

OK. Now to experiment with the role prefix functionality:

  • Deleted the standard roles from LDAP:

[anthony@centos54 tmp]$ ldapdelete -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret "cn=architect, ou=roles,dc=controltier,dc=com"
[anthony@centos54 tmp]$ ldapdelete -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret "cn=admin, ou=roles,dc=controltier,dc=com"
[anthony@centos54 tmp]$ ldapdelete -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret "cn=user, ou=roles,dc=controltier,dc=com"
[anthony@centos54 tmp]$ ldapdelete -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret "cn=build, ou=roles,dc=controltier,dc=com"
[anthony@centos54 tmp]$ ldapdelete -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret "cn=deploy, ou=roles,dc=controltier,dc=com
"

  • Setup a new set of roles prefixed by "ctier." (based on the standard ldif file):

[anthony@centos54 tmp]$ ldapadd -c -x -H ldap://localhost:389/ -D "cn=Manager,dc=controltier,dc=com" -w secret -f prefix.ldif
adding new entry "dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "ou=users,dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "cn=default, ou=users,dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "cn=build, ou=users,dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "cn=deploy, ou=users,dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "ou=roles, dc=controltier,dc=com"
ldapadd: Already exists (68)

adding new entry "cn=ctier.architect, ou=roles,dc=controltier,dc=com"

adding new entry "cn=ctier.admin, ou=roles,dc=controltier,dc=com"

adding new entry "cn=ctier.user, ou=roles,dc=controltier,dc=com"

adding new entry "cn=ctier.build, ou=roles,dc=controltier,dc=com"

adding new entry "cn=ctier.deploy, ou=roles,dc=controltier,dc=com"

  • Added the prefix to the LDAP login module configuration file:

[user3@centos54 etc]$ diff ldap-loginModule.conf ldap-loginModule.conf.orig 
2c2
<     org.controltier.security.authorization.ControlTierLdapLoginModule required
---
>     org.mortbay.jetty.plus.jaas.spi.LdapLoginModule required
19,22c19
<     roleObjectClass="groupOfUniqueNames"
<     rolePrefix="ctier."
<     cacheDurationMillis="10000"
<     reportStatistics="true";
---
>     roleObjectClass="groupOfUniqueNames";

  • Restarted Jetty and tested a login:

2010-05-07 10:57:47.104::WARN:  No CallbackHandler configured: using DefaultCallbackHandler
2010-05-07 10:57:47.223::INFO:  Login attempts: 3, Hits: 0, Ratio: 0%.
2010-05-07 10:57:47.234::INFO:  Role for default: ctier.architect
2010-05-07 10:57:47.235::INFO:  Role for default: ctier.admin
2010-05-07 10:57:47.235::INFO:  Role for default: ctier.user
2010-05-07 10:57:47.235::INFO:  Role for default: ctier.build
2010-05-07 10:57:47.235::INFO:  Role for default: ctier.deploy

... (I'd put in a little logging to confirm which roles are configured for the user).

Cool. 

Anthony.

Anthony Shortland

unread,
May 7, 2010, 3:38:29 PM5/7/10
to ControlTier Accounting
Hi Noah,

OK. Seems there was a restriction in that the prefix filtering only worked if you set "forceBindingLogin=false" ... however the AD use case I have in mind demands both filtering and forcing binding logins.

With this in mind I fixed ControlTierLdapLoginModule.java as follows:

[user3@centos54 ctldapmodule]$ diff src/java/org/controltier/security/authorization/ControlTierLdapLoginModule.java src/java/org/controltier/security/authorization/ControlTierLdapLoginModule.java.orig
232a233,244
>         if (_rolePrefix != null && !"".equalsIgnoreCase(_rolePrefix)) {
>             List<String> newRoles = new ArrayList<String>();

>             for (Object roleObj : roles) {
>                 String role = (String) roleObj;
> Log.info("Role for user " + username + ": " + role);
>                 newRoles.add(role.replace(_rolePrefix, ""));
>             }

>             roles.addAll(newRoles);
>         }

375,382c387
<                 if (_rolePrefix != null && !"".equalsIgnoreCase(_rolePrefix)) {
<                    String role = (String) roles.next();
< Log.info("Role for user " + userDn + ": " + role);
<                    roleList.add(role.replace(_rolePrefix, ""));
<                 }
<                 else {
<                    roleList.add(roles.next());
<                 }
---
>                 roleList.add(roles.next());

... switching the filtering to the getUserRolesByDn method.

With this enhancement, we have an excellent contribution to the project that'll hopefully make it for 3.4.12. 

Thanks for you effort,

Anthony.
Reply all
Reply to author
Forward
0 new messages