LdapExtLoginModule

Version 30

    LdapExtLoginModule

    The org.jboss.security.auth.spi.LdapExtLoginModule, added in jboss-4.0.3, is an alternate ldap login module implementation that uses searches for locating both the user to bind as for authentication as well as the associated roles. The roles query will recursively follow distinguished names (DNs) to navigate a hierarchical role structure.

     

    The LoginModule options include whatever options your LDAP JNDI provider supports. Examples of standard property names are:

     

    • Context.INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial"

    • Context.SECURITY_PROTOCOL = "java.naming.security.protocol"

    • Context.PROVIDER_URL = "java.naming.provider.url"

    • Context.SECURITY_AUTHENTICATION = "java.naming.security.authentication"

    • Context.REFERRAL = "java.naming.referral"

     

    The authentication happens in 2 steps:

    1. An initial bind to the ldap server is done using the bindDN and bindCredential options. The bindDN is some user with the ability to search both the baseCtxDN and rolesCtxDN trees for the user and roles. The user DN to authenticate against is queried using the filter specified by the baseFilter attribute (see the baseFilter option description for its syntax).

    2. The resulting user DN is then authenticated by binding to ldap server using the user DN as the InitialLdapContext environment Context.SECURITY_PRINCIPAL. The

    Context.SECURITY_CREDENTIALS property is either set to the String password obtained by the callback handler.

     

    If this is successful, the associated user roles are queried using the rolesCtxDN, roleAttributeID, roleAttributeIsDN, roleNameAttributeID, and roleFilter options.

     

    The full module properties include:

    • baseCtxDN : The fixed DN of the context to start the user search from.

    • bindDN : The DN used to bind against the ldap server for the user and roles queries. This is some DN with read/search permissions on the baseCtxDN and rolesCtxDN values.

    • bindCredential : The password for the bindDN. This can be encrypted if the jaasSecurityDomain is specified. Starting in EAP 4.2 CP08, EAP 4.3 CP06 and AS 5.2 Beta this option allows an external command to read the password. For example {EXT}cat file_with_password.

    • jaasSecurityDomain : The JMX ObjectName of the JaasSecurityDomain to use to decrypt the java.naming.security.principal. The encrypted form of the password is that returned by the JaasSecurityDomainencrypt64(byte[]) method. The org.jboss.security.plugins.PBEUtils can also be used to generate the encrypted form.  See the following Workthrough to see how this can be used.

    • baseFilter : A search filter used to locate the context of the user to authenticate. The input username/userDN as obtained from the login module callback will be substituted into the filter anywhere a "{0}" expression is seen. This substitution behavior comes from the standard DirContext.search(Name, String, Object[], SearchControls cons) method. An common example search filter is "(uid={0})".

    • rolesCtxDN : The fixed DN of the context to search for user roles. Consider that this is not the Distinguished Name of where the actual roles are; rather, this is the DN of where the objects containing the user roles are (e.g. for active directory, this is the DN where the user account is)

    • roleFilter : A search filter used to locate the roles associated with the authenticated user. The input username/userDN as obtained from the login module callback will be substituted into the filter anywhere a "{0}" expression is seen. The authenticated userDN will be substituted into the filter anywhere a "{1}" is seen.  An example search filter that matches on the input username is: "(member={0})". An alternative that matches on the authenticated userDN is: "(member={1})".

    • roleAttributeIsDN : A flag indicating whether the user's role attribute contains the fully distinguished name of a role object, or the users's role attribute contains the role name. If false, the role name is taken from the value of the user's role attribute. If true, the role attribute represents the distinguished name of a role object.  The role name is taken from the value of the roleNameAttributeId` attribute of the corresponding object.  In certain directory schemas (e.g., Microsoft Active Directory), role (group)attributes in the user object are stored as DNs to role objects instead of as simple names, in which case, this property should be set to true. The default value of this property is false.

    • roleAttributeID : The name of the role attribute of the context which corresponds to the name of the role. If the roleAttributeIsDN property is set to true, this property is the DN of the context to query for the roleNameAttributeID attribute. If the roleAttributeIsDN property is set to false, this property is the attribute name of the role name.

    • roleNameAttributeID : The name of the role attribute of the context which corresponds to the name of the role.  If the roleAttributeIsDN property is set to true, this property is used to find the role object's name attribute. If the roleAttributeIsDN property is set to false, this property is ignored.

    • roleRecursion : How deep the role search will go below a given matching context. Disable with 0, which is the default.

    • searchTimeLimit : The timeout in milliseconds for the user/role searches. Defaults to 10000 (10 seconds).

    • searchScope : Sets the search scope to one of the strings. The default is SUBTREE_SCOPE.

      • OBJECT_SCOPE : only search the named roles context.

      • ONELEVEL_SCOPE : search directly under the named roles context.

      • SUBTREE_SCOPE :  If the roles context is not a DirContext, search only the object. If the roles context is a DirContext, search the subtree rooted at the named object, including the named object itself

    • allowEmptyPasswords : A flag indicating if empty(length==0) passwords should be passed to the ldap server. An empty password is treated as an anonymous login by some ldap servers and this may not be a desirable feature. Set this to false to reject empty passwords, true to have the ldap server validate the empty password. The default is true.

                   NOTE: ActiveDirectory appears to require this setting. Without it an login for a user is successful with a empty password.
    • defaultRole : A role that will be included for all authenticated users.

     

     

    Figure 1, LDAP Examples Structure Overview

     

    Figure 1.1, Example1 LDIF

    dn: dc=jboss,dc=org
    objectclass: top
    objectclass: dcObject
    objectclass: organization
    dc: jboss
    o: JBoss
    
    dn: ou=People,dc=jboss,dc=org
    objectclass: top
    objectclass: organizationalUnit
    ou: People
    
    dn: uid=jduke,ou=People,dc=jboss,dc=org
    objectclass: top
    objectclass: uidObject
    objectclass: person
    uid: jduke
    cn: Java Duke
    sn: Duke
    userPassword: theduke
    
    dn: ou=Roles,dc=jboss,dc=org
    objectclass: top
    objectclass: organizationalUnit
    ou: Roles
    
    dn: cn=Echo,ou=Roles,dc=jboss,dc=org
    objectClass: top
    objectClass: groupOfNames
    cn: Echo
    description: the JBossAdmin group
    member: uid=jduke,ou=People,dc=jboss,dc=org
    
    dn: cn=TheDuke,ou=Roles,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: TheDuke
    description: TheDuke role context
    member: uid=jduke,ou=People,dc=jboss,dc=org
    

     

    Figure 1.2, Example2 LDIF

    version: 1
    dn: o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: dcObject
    objectClass: organization
    dc: jboss
    o: JBoss
    
    dn: ou=People,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: organizationalUnit
    ou: People
    
    dn: uid=jduke,ou=People,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: uidObject
    objectClass: person
    objectClass: inetOrgPerson
    cn: Java Duke
    employeeNumber: judke-123
    sn: Duke
    uid: jduke
    userPassword:: dGhlZHVrZQ==
    
    dn: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: uidObject
    objectClass: person
    objectClass: inetOrgPerson
    cn: Java Duke2
    employeeNumber: judke2-123
    sn: Duke2
    uid: jduke2
    userPassword:: dGhlZHVrZTI=
    
    dn: ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: organizationalUnit
    ou: Roles
    
    dn: uid=jduke,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: groupUserEx
    memberOf: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org
    memberOf: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org
    uid: jduke
    
    dn: uid=jduke2,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: groupUserEx
    memberOf: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org
    memberOf: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org
    uid: jduke2
    
    dn: cn=Echo,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: groupOfNames
    cn: Echo
    description: the echo role
    member: uid=jduke,ou=People,dc=jboss,dc=org
    
    dn: cn=TheDuke,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: TheDuke
    description: the duke role
    member: uid=jduke,ou=People,o=example2,dc=jboss,dc=org
    
    dn: cn=Echo2,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: groupOfNames
    cn: Echo2
    description: the Echo2 role
    member: uid=jduke2,ou=People,dc=jboss,dc=org
    
    dn: cn=TheDuke2,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: TheDuke2
    description: the duke2 role
    member: uid=jduke2,ou=People,o=example2,dc=jboss,dc=org
    
    dn: cn=JBossAdmin,ou=Roles,o=example2,dc=jboss,dc=org
    objectClass: top
    objectClass: groupOfNames
    cn: JBossAdmin
    description: the JBossAdmin group
    member: uid=jduke,ou=People,dc=jboss,dc=org
    

     

    Figure 1.3, Example3 LDIF

    dn: o=example3,dc=jboss,dc=org
    objectclass: top
    objectclass: dcObject
    objectclass: organization
    dc: jboss
    o: JBoss
    
    dn: ou=People,o=example3,dc=jboss,dc=org
    objectclass: top
    objectclass: organizationalUnit
    ou: People
    
    dn: uid=jduke,ou=People,o=example3,dc=jboss,dc=org
    objectclass: top
    objectclass: uidObject
    objectclass: person
    objectClass: inetOrgPerson
    uid: jduke
    employeeNumber: judke-123
    cn: Java Duke
    sn: Duke
    userPassword: theduke
    
    dn: ou=Roles,o=example3,dc=jboss,dc=org
    objectClass: top
    objectClass: organizationalUnit
    ou: Roles
    
    dn: uid=jduke,ou=Roles,o=example3,dc=jboss,dc=org
    objectClass: top
    objectClass: groupUserEx
    memberOf: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org
    memberOf: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org
    uid: jduke
    
    dn: cn=Echo,ou=Roles,o=example3,dc=jboss,dc=org
    objectClass: top
    objectClass: groupOfNames
    cn: Echo
    description: the JBossAdmin group
    member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org
    
    dn: cn=TheDuke,ou=Roles,o=example3,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: TheDuke
    member: uid=jduke,ou=People,o=example3,dc=jboss,dc=org
    

     

    Figure 1.4, Example4 LDIF

    dn: o=example4,dc=jboss,dc=org
    objectclass: top
    objectclass: dcObject
    objectclass: organization
    dc: jboss
    o: JBoss
    
    dn: ou=People,o=example4,dc=jboss,dc=org
    objectclass: top
    objectclass: organizationalUnit
    ou: People
    
    dn: uid=jduke,ou=People,o=example4,dc=jboss,dc=org
    objectClass: top
    objectClass: uidObject
    objectClass: person
    objectClass: inetOrgPerson
    cn: Java Duke
    employeeNumber: jduke-123
    sn: Duke
    uid: jduke
    userPassword:: dGhlZHVrZQ==
    
    dn: ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: top
    objectClass: organizationalUnit
    ou: Roles
    
    dn: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: RG1
    member: cn=empty
    
    dn: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: RG2
    member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org
    
    dn: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: RG3
    member: cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    
    dn: cn=R1,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: R1
    member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    
    dn: cn=R2,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: R2
    member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    
    dn: cn=R3,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: R3
    member: cn=RG2,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    
    dn: cn=R4,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: R4
    member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    
    dn: cn=R5,ou=Roles,o=example4,dc=jboss,dc=org
    objectClass: groupOfNames
    objectClass: top
    cn: R5
    member: cn=RG3,cn=RG1,ou=Roles,o=example4,dc=jboss,dc=org
    member: uid=jduke,ou=People,o=example4,dc=jboss,dc=org
    

     

    Figure 2.1, Module Config for Example1 LDIF      testLdapExample21 {

             org.jboss.security.auth.spi.LdapExtLoginModule
                java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
                java.naming.provider.url="ldap://lamia/"
                java.naming.security.authentication=simple
                bindDN="cn=Root,dc=jboss,dc=org"
                bindCredential=secret1
                baseCtxDN="ou=People,dc=jboss,dc=org"
                baseFilter="(uid={0})"
                rolesCtxDN="ou=Roles,dc=jboss,dc=org";
                roleFilter="(member={1})"
                roleAttributeID="cn"
          };
    

     

    Figure 2.2, Module Config for Example2 LDIF

          testLdapExample22 {
             org.jboss.security.auth.spi.LdapExtLoginModule
                java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
                java.naming.provider.url="ldap://lamia/"
                java.naming.security.authentication=simple
                bindDN="cn=Root,dc=jboss,dc=org"
                bindCredential=secret1
                baseCtxDN="ou=People,o=example2,dc=jboss,dc=org"
                baseFilter="(uid={0})"
                rolesCtxDN="ou=Roles,o=example2,dc=jboss,dc=org";
                roleFilter="(uid={0})"
                roleAttributeIsDN="true"
                roleAttributeID="memberOf"
                roleNameAttributeID="cn"
          };
    

     

    Figure 2.3, Module Config for Example3 LDIF

          testLdapExample23 {
             org.jboss.security.auth.spi.LdapExtLoginModule
                java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
                java.naming.provider.url="ldap://lamia/"
                java.naming.security.authentication=simple
                bindDN="cn=Root,dc=jboss,dc=org"
                bindCredential=secret1
                baseCtxDN="ou=People,o=example3,dc=jboss,dc=org"
                baseFilter="(cn={0})"
                rolesCtxDN="ou=Roles,o=example3,dc=jboss,dc=org";
                roleFilter="(member={1})"
                roleAttributeID="cn"
          };
    

    Figure 2.4, Module Config for Example4 LDIF

          testLdapExample24 {
             org.jboss.security.auth.spi.LdapExtLoginModule
                java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
                java.naming.provider.url="ldap://lamia/"
                java.naming.security.authentication=simple
                bindDN="cn=Root,dc=jboss,dc=org"
                bindCredential=secret1
                baseCtxDN="ou=People,o=example4,dc=jboss,dc=org"
                baseFilter="(cn={0})"
                rolesCtxDN="ou=Roles,o=example4,dc=jboss,dc=org";
                roleFilter="(member={1})"
                roleAttributeID="memberOf"
          };
    

     

    Junit Testcase

    The attached LoginModulesTestCase.java junit testcase illustates the example configurations and expected results.

     

    ActiveDirectory Configuration

    This configuration works for an out of the box ActiveDirectory

    <application-policy name="raider">
        <authentication>
            <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required" >
                <!--
                    Some AD configurations may require searching against
                    the Global Catalog on port 3268 instead of the usual
                    port 389.  This is most likely when the AD forest
                    includes multiple domains.
                -->
                <module-option name="java.naming.provider.url">ldap://ldap.jboss.org:389</module-option>
                <module-option name="bindDN">JBOSS\someadmin</module-option>
                <module-option name="bindCredential">password</module-option>
                <module-option name="baseCtxDN">cn=Users,dc=jboss,dc=org</module-option>
                <module-option name="baseFilter">(sAMAccountName={0})</module-option>
    
                <module-option name="rolesCtxDN">cn=Users,dc=jboss,dc=org</module-option>
                <module-option name="roleFilter">(sAMAccountName={0})</module-option>
                <module-option name="roleAttributeID">memberOf</module-option>
                <module-option name="roleAttributeIsDN">true</module-option>
                <module-option name="roleNameAttributeID">cn</module-option>
    
                <module-option name="searchScope">ONELEVEL_SCOPE</module-option>
    
                <module-option name="allowEmptyPasswords">false</module-option>
            </login-module>
        </authentication>
    </application-policy>
    

     

    See UsingAnLDAPSourceForPortalAuthentication how to integrate LDAP with jboss-portal.


    The following configuration is an example which enables a recursive search of roles within Active Directory.

    <application-policy name="raider">
        <authentication>
            <login-module code="org.jboss.security.auth.spi.LdapExtLoginModule" flag="required" > 
              <module-option name="java.naming.provider.url">ldap://ad.jboss.org:389</module-option>
              <module-option name="bindDN">JBOSS\searchuser</module-option>
              <module-option name="bindCredential">password</module-option>
              <module-option name="baseCtxDN">CN=Users,DC=jboss,DC=org</module-option>
              <module-option name="baseFilter">(sAMAccountName={0})</module-option>
    
              <module-option name="rolesCtxDN">CN=Users,DC=jboss,DC=org</module-option>
              <module-option name="roleFilter">(member={1})</module-option>
              <module-option name="roleAttributeID">cn</module-option>
              <module-option name="roleAttributeIsDN">false</module-option>
    
              <module-option name="roleRecursion">2</module-option>
              <module-option name="searchScope">ONELEVEL_SCOPE</module-option>
    
              <module-option name="allowEmptyPasswords">false</module-option>
            </login-module>
        </authentication>
    </application-policy>
    

     

    The key here is that the role search has been replaced to search the member attribute using the dn of the user, this then uses the dn of the role to find groups that the group is a member of.

     

     

    Referenced by:

     

     

     

     

    Referenced by: