Advanced LDAP
Advanced LDAP Authentication¶
The default configuration computes the bind DN for incoming user based on userDnTemplate. This does not work in enterprises where users could belong to multiple branches of LDAP tree. You could instead enable advanced configuration that would compute bind DN of incoming user with an LDAP search.
Problem with userDnTemplate based Authentication¶
UserDnTemplate based authentication uses the configuration parameter ldapRealm.userDnTemplate
.
Typical values of userDNTemplate would look like uid={0},ou=people,dc=hadoop,dc=apache,dc=org
.
To compute bind DN of the client, we swap the place holder {0}
with the login id provided by the client.
For example, if the login id provided by the client is "guest',
the computed bind DN would be uid=guest,ou=people,dc=hadoop,dc=apache,dc=org
.
This keeps configuration simple.
However, this does not work if users belong to different branches of LDAP DIT.
For example, if there are some users under ou=people,dc=hadoop,dc=apache,dc=org
and some users under ou=contractors,dc=hadoop,dc=apache,dc=org
,
we cannot come up with userDnTemplate that would work for all the users.
Using advanced LDAP Authentication¶
With advanced LDAP authentication, we find the bind DN of the user by searching the LDAP directory instead of interpolating the bind DN from userDNTemplate.
Example search filter to find the client bind DN¶
Assuming
- ldapRealm.userSearchAttributeName=uid
- ldapRealm.userObjectClass=person
- client specified login id = "guest"
The LDAP Filter for doing a search to find the bind DN would be
(&(uid=guest)(objectclass=person))
This could find the bind DN to be
uid=guest,ou=people,dc=hadoop,dc=apache,dc=org
Please note that the userSearchAttributeName
need not be part of bindDN.
For example, you could use
- ldapRealm.userSearchAttributeName=email
- ldapRealm.userObjectClass=person
- client specified login id = "bill.clinton@gmail.com"
The LDAP Filter for doing a search to find the bind DN would be
(&(email=bill.clinton@gmail.com)(objectclass=person))
This could find the bind DN to be
uid=billc,ou=contractors,dc=hadoop,dc=apache,dc=org
Advanced LDAP configuration parameters¶
The table below provides a brief description and sample of the available advanced bind and search configuration parameters.
Parameter | Description | Default | Sample |
---|---|---|---|
principalRegex | Parses the principal for insertion into templates via regex. | (.*) | (.*?)\\(.*) (e.g. match US\tom: {0}=US\tom, {1}=US, {2}=tom) |
userDnTemplate | Direct user bind DN template. | {0} | cn={2},dc={1},dc=qa,dc=company,dc=com |
userSearchBase | Search based template. Used with config below. | none | dc={1},dc=qa,dc=company,dc=com |
userSearchAttributeName | Attribute name for simplified search filter. | none | sAMAccountName |
userSearchAttributeTemplate | Attribute template for simplified search filter. | {0} | {2} |
userSearchFilter | Advanced search filter template. Note \& is \& in XML. | none | (\&(objectclass=person)(sAMAccountName={2})) |
userSearchScope | Search scope: subtree, onelevel, object. | subtree | onelevel |
Advanced LDAP configuration combinations¶
There are also only certain valid combinations of advanced LDAP configuration parameters.
- User DN Template
- userDnTemplate (Required)
- principalRegex (Optional)
- User Search by Attribute
- userSearchBase (Required)
- userAttributeName (Required)
- userAttributeTemplate (Optional)
- userSearchScope (Optional)
- principalRegex (Optional)
- User Search by Filter
- userSearchBase (Required)
- userSearchFilter (Required)
- userSearchScope (Optional)
- principalRegex (Optional)
Advanced LDAP configuration precedence¶
The presence of multiple configuration combinations should be avoided. The rules below clarify which combinations take precedence when present.
- userSearchBase takes precedence over userDnTemplate
- userSearchFilter takes precedence over userSearchAttributeName
Example provider configuration to use advanced LDAP authentication¶
The example configuration appears verbose due to the presence of liberal comments and illustration of optional parameters and default values. The configuration that you would use could be much shorter if you rely on default values.
<provider>
<role>authentication</role>
<name>ShiroProvider</name>
<enabled>true</enabled>
<param>
<name>main.ldapRealm</name>
<value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>
</param>
<param>
<name>main.ldapContextFactory</name>
<value>org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory</value>
</param>
<param>
<name>main.ldapRealm.contextFactory</name>
<value>$ldapContextFactory</value>
</param>
<!-- update the value based on your ldap directory protocol, host and port -->
<param>
<name>main.ldapRealm.contextFactory.url</name>
<value>ldap://hdp.example.com:389</value>
</param>
<!-- optional, default value: simple
Update the value based on mechanisms supported by your ldap directory -->
<param>
<name>main.ldapRealm.contextFactory.authenticationMechanism</name>
<value>simple</value>
</param>
<!-- optional, default value: {0}
update the value based on your ldap DIT(directory information tree).
ignored if value is defined for main.ldapRealm.userSearchAttributeName -->
<param>
<name>main.ldapRealm.userDnTemplate</name>
<value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- optional, default value: null
If you specify a value for this attribute, useDnTemplate
specified above would be ignored and user bind DN would be computed using
ldap search
update the value based on your ldap DIT(directory information layout)
value of search attribute should identity the user uniquely -->
<param>
<name>main.ldapRealm.userSearchAttributeName</name>
<value>uid</value>
</param>
<!-- optional, default value: false
If the value is true, groups in which user is a member are looked up
from LDAP and made available for service level authorization checks -->
<param>
<name>main.ldapRealm.authorizationEnabled</name>
<value>true</value>
</param>
<!-- bind DN used to search for groups and user bind DN.
Required if a value is defined for main.ldapRealm.userSearchAttributeName
or if the value of main.ldapRealm.authorizationEnabled is true -->
<param>
<name>main.ldapRealm.contextFactory.systemUsername</name>
<value>uid=guest,ou=people,dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- password for systemUserName.
Required if a value is defined for main.ldapRealm.userSearchAttributeName
or if the value of main.ldapRealm.authorizationEnabled is true -->
<param>
<name>main.ldapRealm.contextFactory.systemPassword</name>
<value>${ALIAS=ldcSystemPassword}</value>
</param>
<!-- optional, default value: simple
Update the value based on mechanisms supported by your ldap directory -->
<param>
<name>main.ldapRealm.contextFactory.systemAuthenticationMechanism</name>
<value>simple</value>
</param>
<!-- optional, default value: person
Objectclass to identify user entries in ldap, used to build search
filter to search for user bind DN -->
<param>
<name>main.ldapRealm.userObjectClass</name>
<value>person</value>
</param>
<!-- search base used to search for user bind DN and groups -->
<param>
<name>main.ldapRealm.searchBase</name>
<value>dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- search base used to search for user bind DN.
Defaults to the value of main.ldapRealm.searchBase.
If main.ldapRealm.userSearchAttributeName is defined,
value for main.ldapRealm.searchBase or main.ldapRealm.userSearchBase
should be defined -->
<param>
<name>main.ldapRealm.userSearchBase</name>
<value>dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- search base used to search for groups.
Defaults to the value of main.ldapRealm.searchBase.
If value of main.ldapRealm.authorizationEnabled is true,
value for main.ldapRealm.searchBase or main.ldapRealm.groupSearchBase should be defined -->
<param>
<name>main.ldapRealm.groupSearchBase</name>
<value>dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- optional, default value: groupOfNames
Objectclass to identify group entries in ldap, used to build search
filter to search for group entries -->
<param>
<name>main.ldapRealm.groupObjectClass</name>
<value>groupOfNames</value>
</param>
<!-- optional, default value: member
If value is memberUrl, we treat found groups as dynamic groups -->
<param>
<name>main.ldapRealm.memberAttribute</name>
<value>member</value>
</param>
<!-- optional, default value: uid={0}
Ignored if value is defined for main.ldapRealm.userSearchAttributeName -->
<param>
<name>main.ldapRealm.memberAttributeValueTemplate</name>
<value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>
</param>
<!-- optional, default value: cn -->
<param>
<name>main.ldapRealm.groupIdAttribute</name>
<value>cn</value>
</param>
<param>
<name>urls./**</name>
<value>authcBasic</value>
</param>
<!-- optional, default value: 30min -->
<param>
<name>sessionTimeout</name>
<value>30</value>
</param>
</provider>
Special note on parameter main.ldapRealm.contextFactory.systemPassword¶
The value for this could have one of the following 2 formats
- plaintextpassword
- ${ALIAS=ldcSystemPassword}
The first format specifies the password in plain text in the provider configuration. Use of this format should be limited for testing and troubleshooting.
We strongly recommend using the second format ${ALIAS=ldcSystemPassword}
in production.
This format uses an alias for the password stored in credential store.
In the example ${ALIAS=ldcSystemPassword}
,
ldcSystemPassword is the alias for the password stored in credential store.
Assuming the plain text password is "hadoop", and your topology file name is "hdp.xml", you would use following command to create the right password alias in credential store.
{GATEWAY_HOME}/bin/knoxcli.sh create-alias ldcSystemPassword --cluster hdp --value hadoop