Chapter 4. Configuring a Security Domain to use LDAP

Security domains can be configured to use an LDAP server for authentication and authorization by using a login module. The basics of security domains and login modules are covered in the Red Hat JBoss Enterprise Application Platform 6 Security Architecture guide. LdapExtended is the preferred login module for integrating with LDAP servers (including Active Directory), but there are several other LDAP login modules that can be used as well. Specifically, the Ldap, AdvancedLdap, and AdvancedAdLdap can also be used to configure a security domain to use LDAP. This section uses the LdapExtended login module to illustrate how to create a security domain that uses an LDAP for authentication and authorization, but the other LDAP login modules may be used as well. For more details on the other LDAP login modules, please see the Red Hat JBoss Enterprise Application Platform 6 Security Guide.

4.1. LdapExtended Login Module

The LdapExtended (org.jboss.security.auth.spi.LdapExtLoginModule) is a login module implementation that uses searches to locate the bind user and associated roles on LDAP server. The roles query recursively follows DNs to navigate a hierarchical role structure. For the vast majority of cases when using LDAP with security domains, the LdapExtedned login module should be used, especially with LDAP implementations that are not Active Directory.

Table 4.1. Complete LdapExtended Login Module Configuration Options

OptionTypeDefaultDescription

java.naming.factory.initial

class name

com.sun.jndi.ldap.LdapCtxFactory

InitialContextFactory implementation class name.

java.naming.provider.url

ldap:// URL

If the value of java.naming.security.protocol is SSL, ldap://localhost:636, otherwise ldap://localhost:389

URL for the LDAP server.

java.naming.security.authentication

none, simple, or the name of a SASL mechanism

The default is simple. If the property is explicitly undefined, the behavior is determined by the service provider.

The security level to use to bind to the LDAP server.

java.naming.security.protocol

transport protocol

If unspecified, determined by the provider.

The transport protocol to use for secure access, such as SSL.

baseCtxDN

fully-qualified DN

none

The fixed DN of the top-level context to begin the user search.

bindCredential

string, optionally encrypted

none

Used to store the credentials for the DN.

bindDN

fully-qualified DN

none

The DN used to bind against the LDAP server for the user and roles queries. This DN needs read and search permissions on the baseCtxDN and rolesCtxDN values.

baseFilter

LDAP filter string

none

A search filter used to locate the context of the user to authenticate. The input username or userDN obtained from the login module callback is substituted into the filter anywhere a {0} expression is used. A common example for the search filter is (uid={0}).

rolesCtxDN

fully-qualified DN

none

The fixed DN of the context to search for user roles. This is not the DN where the actual roles are, but the DN where the objects containing the user roles are. For example, in a Microsoft Active Directory server, this is the DN where the user account is.

roleFilter

LDAP filter string

none

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

roleAttributeID

attribute

roles

Name of the attribute containing the user roles.

roleAttributeIsDN

true or false

false

Whether or not the roleAttributeID contains the fully-qualified DN of a role object. If false, the role name is taken from the value of the roleNameAttributeId attribute of the context name. Certain directory schemas, such as Microsoft Active Directory, require this attribute to be set to true.

defaultRole

Role name

none

A role included for all authenticated users

parseRoleNameFromDN

true or false

false

A flag indicating if the DN returned by a query contains the roleNameAttributeID. If set to true, the DN is checked for the roleNameATtributeID. If set to false, the DN is not checked for the roleNameAttributeID. This flag can improve the performance of LDAP queries.

parseUsername

true or false

false

A flag indicating if the DN is to be parsed for the username. If set to true, the DN is parsed for the username. If set to false the DN is not parsed for the username. This option is used together with usernameBeginString and usernameEndString.

usernameBeginString

string

none

Defines the string which is to be removed from the start of the DN to reveal the username. This option is used together with usernameEndString.

usernameEndString

string

none

Defines the string which is to be removed from the end of the DN to reveal the username. This option is used together with usernameBeginString.

roleNameAttributeID

attribute

name

Name of the attribute within the roleCtxDN context which contains the role name. If the roleAttributeIsDN property is set to true, this property is used to find the role object’s name attribute.

distinguishedNameAttribute

attribute

distinguishedName

The name of the attribute in the user entry that contains the DN of the user. This may be necessary if the DN of the user itself contains special characters (backslash for example) that prevent correct user mapping. If the attribute does not exist, the entry’s DN is used.

roleRecursion

integer

0

The numbers of levels of recursion the role search will go below a matching context. Disable recursion by setting this to 0.

searchTimeLimit

integer

10000 (10 seconds)

The timeout in milliseconds for user or role searches.

searchScope

One of: OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE

SUBTREE_SCOPE

The search scope to use.

allowEmptyPasswords

true or false

false

Whether to allow empty passwords. Most LDAP servers treat empty passwords as anonymous login attempts. To reject empty passwords, set this to false.

referralUserAttributeIDToCheck

attribute

none

If you are not using referrals, this option can be ignored. When using referrals, this option denotes the attribute name which contains users defined for a certain role (for example, member), if the role object is inside the referral. Users are checked against the content of this attribute name. If this option is not set, the check will always fail, so role objects cannot be stored in a referral tree.

The authentication happens as follows:

  1. An initial bind to the LDAP server is done using the bindDN and bindCredential options. The bindDN is a LDAP 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.
  2. The resulting user DN is authenticated by binding to the LDAP server using the user DN as the InitialLdapContext environment Context.SECURITY_PRINCIPAL. The Context.SECURITY_CREDENTIALS property is set to the String password obtained by the callback handler.

4.1.1. Configuring a Security Domain to use the LdapExtended Login Module

Example Data (LDIF format)

dn: uid=jduke,ou=Users,dc=jboss,dc=org
objectClass: inetOrgPerson
objectClass: person
objectClass: top
cn: Java Duke
sn: duke
uid: jduke
userPassword: theduke
# =============================
dn: uid=hnelson,ou=Users,dc=jboss,dc=org
objectClass: inetOrgPerson
objectClass: person
objectClass: top
cn: Horatio Nelson
sn: Nelson
uid: hnelson
userPassword: secret
# =============================
dn: ou=groups,dc=jboss,dc=org
objectClass: top
objectClass: organizationalUnit
ou: groups
# =============================
dn: uid=ldap,ou=Users,dc=jboss,dc=org
objectClass: inetOrgPerson
objectClass: person
objectClass: top
cn: LDAP
sn: Service
uid: ldap
userPassword: randall
# =============================
dn: ou=Users,dc=jboss,dc=org
objectClass: top
objectClass: organizationalUnit
ou: Users
# =============================
dn: dc=jboss,dc=org
objectclass: top
objectclass: domain
dc: jboss
# =============================
dn: uid=GroupTwo,ou=groups,dc=jboss,dc=org
objectClass: top
objectClass: groupOfNames
objectClass: uidObject
cn: GroupTwo
member: uid=jduke,ou=Users,dc=jboss,dc=org
uid: GroupTwo
# =============================
dn: uid=GroupThree,ou=groups,dc=jboss,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: GroupThree
uid: GroupThree
uniqueMember: uid=GroupOne,ou=groups,dc=jboss,dc=org
# =============================
dn: uid=HTTP,ou=Users,dc=jboss,dc=org
objectClass: inetOrgPerson
objectClass: person
objectClass: top
cn: HTTP
sn: Service
uid: HTTP
userPassword: httppwd
# =============================
dn: uid=GroupOne,ou=groups,dc=jboss,dc=org
objectClass: top
objectClass: groupOfUniqueNames
objectClass: uidObject
cn: GroupOne
uid: GroupOne
uniqueMember: uid=jduke,ou=Users,dc=jboss,dc=org
uniqueMember: uid=hnelson,ou=Users,dc=jboss,dc=org

CLI Commands for Adding the LdapExtended Login Module

/subsystem=security/security-domain=testLdapExtendedExample:add(cache-type=default)

/subsystem=security/security-domain=testLdapExtendedExample/authentication=classic:add
/subsystem=security/security-domain=testLdapExtendedExample/authentication=classic/login-module=LdapExtended:add( \
  code=LdapExtended, \
  flag=required, \
  module-options=[ \
    ("java.naming.factory.initial"=>"com.sun.jndi.ldap.LdapCtxFactory"), \
    ("java.naming.provider.url"=>"ldap://localhost:10389"), \
    ("java.naming.security.authentication"=>"simple"), \
    ("bindDN"=>"uid=ldap,ou=Users,dc=jboss,dc=org"), \
    ("bindCredential"=>"randall"), \
    ("baseCtxDN"=>"ou=Users,dc=jboss,dc=org"), \
    ("baseFilter"=>"(uid={0})"), \
    ("rolesCtxDN"=>"ou=groups,dc=jboss,dc=org"), \
    ("roleFilter"=>"(uniqueMember={1})"), \
    ("roleAttributeID"=>"uid"), \
  ])
reload

Resulting XML

<security-domain name="testLdapExtendedExample" cache-type="default">
  <authentication>
    <login-module code="LdapExtended" flag="required">
      <module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
      <module-option name="java.naming.provider.url" value="ldap://localhost:10389"/>
      <module-option name="java.naming.security.authentication" value="simple"/>
      <module-option name="bindDN" value="uid=ldap,ou=Users,dc=jboss,dc=org"/>
      <module-option name="bindCredential" value="randall"/>
      <module-option name="baseCtxDN" value="ou=Users,dc=jboss,dc=org"/>
      <module-option name="baseFilter" value="(uid={0})"/>
      <module-option name="rolesCtxDN" value="ou=groups,dc=jboss,dc=org"/>
      <module-option name="roleFilter" value="(uniqueMember={1})"/>
      <module-option name="roleAttributeID" value="uid"/>
    </login-module>
  </authentication>
</security-domain>

Note

The above CLI commands were done assuming a standalone instance of JBoss EAP 6. For more details on using the CLI with JBoss EAP 6 domains, please consult The Management CLI section of the Red Hat JBoss Enterprise Application Platform 6 Administration and Configuration Guide.

4.1.1.1. Configuring a Security Domain to use the LdapExtended Login Module for Active Directory

For Microsoft Active Directory, the LdapExtended Login Module may be used.

Default AD Configuration

The example below represents the configuration for a default Active Directory configuration.

Some Active Directory configurations may require searching against the Global Catalog on port 3268 instead of the usual port 389. This is most likely when the Active Directory forest includes multiple domains.

Example Configuration for the LdapExtended Login Module for a Default AD Configuration

<security-domain name="AD_Default" cache-type="default">
  <authentication>
    <login-module code="LdapExtended" flag="required">
      <module-option name="java.naming.provider.url" value="ldap://ldaphost.jboss.org"/>
      <module-option name="bindDN" value="JBOSSsearchuser"/>
      <module-option name="bindCredential" value="password"/>
      <module-option name="baseCtxDN" value="CN=Users,DC=jboss,DC=org"/>
      <module-option name="baseFilter" value="(sAMAccountName={0})"/>
      <module-option name="rolesCtxDN" value="CN=Users,DC=jboss,DC=org"/>
      <module-option name="roleFilter" value="(sAMAccountName={0})"/>
      <module-option name="roleAttributeID" value="memberOf"/>
      <module-option name="roleAttributeIsDN" value="true"/>
      <module-option name="roleNameAttributeID" value="cn"/>
      <module-option name="searchScope" value="ONELEVEL_SCOPE"/>
      <module-option name="allowEmptyPasswords" value="false"/>
    </login-module>
  </authentication>
</security-domain>

Recursive AD Configuration

The example below implements a recursive role search within Active Directory. The key difference between this example and the default Active Directory example is that the role search has been replaced to search the member attribute using the DN of the user. The login module then uses the DN of the role to find groups of which the group is a member.

Example Configuration for the LdapExtended Login Module for a Default AD Configuration with Recursive Search

<security-domain name="AD_Recursive" cache-type="default">
  <authentication>
    <login-module code="LdapExtended" flag="required">
      <module-option name="java.naming.provider.url" value="ldap://ldaphost.jboss.org"/>
      <module-option name="java.naming.referral" value="follow"/>
      <module-option name="bindDN" value="JBOSSsearchuser"/>
      <module-option name="bindCredential" value="password"/>
      <module-option name="baseCtxDN" value="CN=Users,DC=jboss,DC=org"/>
      <module-option name="baseFilter" value="(sAMAccountName={0})"/>
      <module-option name="rolesCtxDN" value="CN=Users,DC=jboss,DC=org"/>
      <module-option name="roleFilter" value="(member={1})"/>
      <module-option name="roleAttributeID" value="cn"/>
      <module-option name="roleAttributeIsDN" value="false"/>
      <module-option name="roleRecursion" value="2"/>
      <module-option name="searchScope" value="ONELEVEL_SCOPE"/>
      <module-option name="allowEmptyPasswords" value="false"/>
    </login-module>
  </authentication>
</security-domain>