Document howto config LDAP identity with non-DN based ids.

Bug #1210141 reported by Brian Seltzer
44
This bug affects 7 people
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Won't Fix
Medium
Marek Denis

Bug Description

I can successfully configure keystone LDAP settings to authenticate against Active Directory using the cn attribute of the user account as the user_id_attribute (i.e. user_id_attribute = cn in keystone.conf). However, in my (and most) Active Directory deployments, the cn is not used as the login ID. Instead, other attributes such as samAccountName or userPrincipalName are used for login. In Activev Directory, cn is commonly populated with the user's full name.

When I try to use samAccountName (i.e. user_id_attribute = samAccountName) then authentication fails.

The search bit works fine:

2013-08-08 09:43:23 DEBUG [keystone.common.ldap.core] LDAP search: dn=cn=Users,dc=seltzer,dc=net, scope=1, query=(&(samAccountName=seltzb01a)(objectClass=organizationalPerson)), attrs=['businessCategory', 'userPassword', 'userAccountControl', 'mail', 'cn']

But the subsequent bind fails when the code appears to build an invalid dn and tries to bind with it as shown below:

2013-08-08 09:43:23 DEBUG [keystone.common.ldap.core] LDAP bind: dn=samAccountName=myaccount,cn=Users,dc=mydomain,dc=net

The dn should start with cn= not samAccountName=. The code should search for a user object by samAccountName and return the correct dn to be used for the bind. Since the dn is invalid, the bind fails and authentication fails.

Invalid user / password (HTTP 401)

I'm not sure if this is all within the keystone ldap provider code or in some dependant LDAP code. Any help would be much appreciated.

tags: added: openstack
removed: identity
Revision history for this message
Brian Seltzer (seltzerb01) wrote :
Revision history for this message
Brian Seltzer (seltzerb01) wrote :

I have found the bug in the keystone/common/ldap/core.py module. The problem is with the id_to_dn_string function. The function incorrectly assembles the object's distinguishedName if any attribute other than cn is used for the user_id_attribute. I can work around the issue by commenting out the lines that call this function within the associated function id_to_dn as shown below:

    def _id_to_dn_string(self, id):
        return '%s=%s,%s' % (self.id_attr,
                             ldap.dn.escape_dn_chars(str(id)),
                             self.tree_dn)

    def _id_to_dn(self, id):
        #if self.LDAP_SCOPE == ldap.SCOPE_ONELEVEL:
        # return self._id_to_dn_string(id)
        conn = self.get_connection()
        search_result = conn.search_s(
            self.tree_dn, self.LDAP_SCOPE,
            '(&(%(id_attr)s=%(id)s)(objectclass=%(objclass)s))' %
            {'id_attr': self.id_attr,
             'id': ldap.filter.escape_filter_chars(str(id)),
             'objclass': self.object_class})
        if search_result:
            dn, attrs = search_result[0]
            return dn
        else:
            return self._id_to_dn_string(id)

With these lines removed, I can successfully use samAccountName as the user_id_attribute. I hope this is helpful!

Dolph Mathews (dolph)
Changed in keystone:
status: New → Triaged
importance: Undecided → Medium
milestone: none → havana-3
Adam Young (ayoung)
Changed in keystone:
assignee: nobody → Adam Young (ayoung)
Revision history for this message
Dolph Mathews (dolph) wrote :

This sounds like it should be a release blocker for havana

Thierry Carrez (ttx)
Changed in keystone:
milestone: havana-3 → havana-rc1
Revision history for this message
Adam Young (ayoung) wrote :

I think this can be handled with current code. If the config value

CONF.ldap.query_scope = one

which is the default, we generate a DN in order to speed up the querying. However, if the option is set

CONF.ldap.query_scope = sub

Keystone will search on the ID attribute directly.

Try setting in the config file:

[ldap]
query_scope = sub

Changed in keystone:
status: Triaged → In Progress
Revision history for this message
Dolph Mathews (dolph) wrote :

It sounds like this use case just needs some more coverage in documentation, either in etc/keystone.conf.sample or perhaps in openstack-manuals

Changed in keystone:
importance: Medium → Low
milestone: havana-rc1 → none
Revision history for this message
Brian Seltzer (seltzerb01) wrote :

Confirmed. With the query_scope set to sub, I can use samAccountName successfully. I should have realized this, as the code clearly works that way. Thanks for the effort guys!

Revision history for this message
Dolph Mathews (dolph) wrote :

Thanks for the follow up!

Adam Young (ayoung)
summary: - LDAP identity provider fails when using samAccountName
+ Document howto config LDAP identity with non-DN based ids.
Revision history for this message
Endre Karlson (endre-karlson) wrote :
Download full text (14.3 KiB)

I am trying to do the same kind of thing but Keystone doesn't seem to honor the settings that I have for ldap because it doesn't do sAMAccountName for the user_id_attribute as I've set.

I do the commands:
root@os-ctrl01:~# keystone user-list
WARNING: Bypassing authentication using a token & endpoint (authentication credentials are being ignored).
+----------------+----------------+---------+-------+
| id | name | enabled | email |
+----------------+----------------+---------+-------+
| Administrator | Administrator | True | |
| Endre Karlsone | Endre Karlsone | True | |
| Guest | Guest | False | |
| krbtgt | krbtgt | False | |
| s_ceilometer | s_ceilometer | True | |
| s_cinder | s_cinder | True | |
| s_glance | s_glance | True | |
| s_keystone | s_keystone | True | |
| s_neutron | s_neutron | True | |
| s_nova | s_nova | True | |
| s_sql | s_sql | True | |
+----------------+----------------+---------+-------+
root@os-ctrl01:~# keystone user-get "endre"
WARNING: Bypassing authentication using a token & endpoint (authentication credentials are being ignored).
No user with a name or ID of 'endre' exists.

And it doesnt' make it correctly as you see
[ldap]
url = ldap://10.0.0.6
# user = dc=Manager,dc=example,dc=com
user = CN=s_keystone,CN=Users,DC=lab,DC=local
password = Superrand0m
suffix = DC=lab,=DC=local
# use_dumb_member = False
allow_subtree_delete = False
# dumb_member = cn=dumb,dc=example,dc=com

# Maximum results per page; a value of zero ('0') disables paging (default)
# page_size = 0

# The LDAP dereferencing option for queries. This can be either 'never',
# 'searching', 'always', 'finding' or 'default'. The 'default' option falls
# back to using default dereferencing configured by your ldap.conf.
#c:alias_dereferencing = default

# The LDAP scope for queries, this can be either 'one'
# (onelevel/singleLevel) or 'sub' (subtree/wholeSubtree)
query_scope = sub

user_tree_dn = CN=Users,dc=lab,dc=local
user_objectclass = person
user_name_attribute = cn
user_mail_attribute = mail
user_enabled_attribute = userAccountControl
#user_domain_id_attribute = businessCategory
user_enabled_mask = 2
user_enabled_default = 512
user_attribute_ignore = password
user_allow_create = False
user_allow_update = False
user_allow_delete = False
# user_filter =
user_objectclass = organizationalPerson
# user_domain_id_attribute = businessCategory
user_id_attribute = sAMAccountName

Relevant lines from startup log:
2013-10-04 09:05:31.636 25129 DEBUG keystone-all [-] ldap.alias_dereferencing = default log_opt_values /usr/lib/python2.7/dist-packages/oslo/config/cfg.py:1907
2013-10-04 09:05:31.636 25129 DEBUG keystone-all [-] ldap.allow_subtree_delete = False log_opt_values /usr/lib/python2.7/dist-packages/oslo/config/cfg.py:1907
2013-10-04 09:05:31.636 25129 DEBUG keystone-all [-] ldap.dumb_member = cn=dumb,dc=nonexistent log_opt_values /usr/lib/python2.7/dist-packages/oslo/config/cfg.py:1907
2013-10-04 0...

Revision history for this message
Brian Seltzer (seltzerb01) wrote :

Endre, your suffix has an extra = in it.

You have:

suffix = DC=lab,=DC=local

should be:

suffix = DC=lab,DC=local

could that be your problem?

Revision history for this message
Endre Karlson (endre-karlson) wrote :

@Brian, I don't think so. That due to the suffix shouldn't affect in my belief how attributes are mapped?

Since the user id is returned wrongly in my user-list which makes it seem so.

I fixed it also and the user-list is still the same.

Dolph Mathews (dolph)
tags: added: documentation
tags: removed: keystone openstack samaccountname
Dolph Mathews (dolph)
Changed in keystone:
importance: Low → Medium
Revision history for this message
Adam Young (ayoung) wrote :

user-list, when backed by LDAP does the following...
first, it starts at the generic Identity level; keystone.identity.controller.py. That maps over to the identity.core.py Manager call
 Manager will do the generic work and then call the driver. You can see this here: https://github.com/openstack/keystone/blob/master/keystone/identity/core.py#L343
 that will call over to the keystone.identity.backends.ldap.py file https://github.com/openstack/keystone/blob/master/keystone/identity/backends/ldap.py#L85
that calls into the User API object defined here https://github.com/openstack/keystone/blob/master/keystone/identity/backends/ldap.py#L186 and the method call is here: https://github.com/openstack/keystone/blob/master/keystone/identity/backends/ldap.py#L242
 get_all is a core call, in keystone.common.ldap.core.py
 https://github.com/openstack/keystone/blob/master/keystone/common/ldap/core.py#L386
 that will call the ldap specific call https://github.com/openstack/keystone/blob/master/keystone/common/ldap/core.py#L388
 _ldap_get_all, and then attempt to map the LDAP objects back to python domain objects
filter defaults to none, which is how it is passed from list_users.

Revision history for this message
Endre Karlson (endre-karlson) wrote :

Ignore me here, I guess the current stuff is right for AD as well. I have blinxed :)

Revision history for this message
Craig Jellick (craig-jellick) wrote :

There is actually a small bug here. You _can_ configure user_id and user_name to be sAMAccountName and sAMAccountName will be used as the user id. It will be used properly in ReST URIs and in database relationships.

But, the ReST API response body will still have the commonname as the id. The problem is when we're building the model:

https://github.com/openstack/keystone/blob/master/keystone/common/ldap/core.py#L280

There you can we that we set the model's id with the cn (or more precisely the value returned by self._dn_to_id()

Revision history for this message
Dolph Mathews (dolph) wrote :

Interesting... but DN's are not URL safe, so that would at least require encoding?

Revision history for this message
Craig Jellick (craig-jellick) wrote :

Well, the whole DN isn't used in the URL, just the common name, which for Active Directory is often something like "Craig Jellick". But yes, that does require encoding.

I just finished up the first draft of a patch that will fix the issue that I'm describing. But now I'm thinking that this bug should remain a documentation change and that I should open a new bug specifically for the issue that I'm describing. Thoughts on that?

Revision history for this message
Craig Jellick (craig-jellick) wrote :

Opened bug
https://bugs.launchpad.net/keystone/+bug/1254849
to specifically address the situation I described.

Revision history for this message
Dolph Mathews (dolph) wrote :

Thanks craig! I'm always happy to see tasks broken down into smaller bits.

Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix proposed to keystone (master)

Fix proposed to branch: master
Review: https://review.openstack.org/93480

Changed in keystone:
assignee: Adam Young (ayoung) → Eric N. Vander Weele (ericvw)
Changed in keystone:
assignee: Eric N. Vander Weele (ericvw) → Adam Young (ayoung)
Changed in keystone:
assignee: Adam Young (ayoung) → Eric N. Vander Weele (ericvw)
Changed in keystone:
assignee: Eric N. Vander Weele (ericvw) → Marek Denis (marek-denis)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Change abandoned on keystone (master)

Change abandoned by Morgan Fainberg (<email address hidden>) on branch: master
Review: https://review.openstack.org/93480
Reason: This change is being abandoned because it has a negative score and has not seen an update in > 60 days. Feel free to re-instate this patch (as the author) by using the "restore" button or any member of the core team can re-instate the patch.

Changed in keystone:
status: In Progress → Won't Fix
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.