Red Hat Training
A Red Hat training course is available for Red Hat JBoss Enterprise Application Platform
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
Option | Type | Default | Description |
---|---|---|---|
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:
- 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.
- 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>
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>