Keystone Havana Authentication Error using samAccountName in Active Directory

Bug #1281216 reported by Brian Seltzer
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
OpenStack Identity (keystone)
Fix Released
Low
Nathan Kinder
Icehouse
Fix Released
Low
Nathan Kinder

Bug Description

When using Active Directory as the LDAP backend for Keystone, if I use the cn attribute for user_id_attribute and user_name_attribute, authentication works fine. However, if I try to use samAccountName, authentication fails. For example, keystone user-list returns the following error:

Authorization Failed: An unexpected error prevented the server from fulfilling your request. 'name' (HTTP 500)

and the login screen in Horizon shows: An error occurred authenticating. Please try again later.

Also, the following trace is shown in the keystone.log:

2014-02-17 06:48:37.472 8207 ERROR keystone.common.wsgi [-] 'name'
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi Traceback (most recent call last):
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/common/wsgi.py", line 238, in __call__
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi result = method(context, **params)
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/token/controllers.py", line 127, in authenticate
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi auth_token_data, roles_ref=roles_ref, catalog_ref=catalog_ref)
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/common/manager.py", line 44, in _wrapper
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi return f(*args, **kw)
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/token/providers/uuid.py", line 362, in issue_v2_token
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi token_ref, roles_ref, catalog_ref)
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi File "/usr/lib/python2.7/dist-packages/keystone/token/providers/uuid.py", line 57, in format_token
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi 'name': user_ref['name'],
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi KeyError: 'name'
2014-02-17 06:48:37.472 8207 TRACE keystone.common.wsgi
2014-02-17 06:48:37.474 8207 INFO access [-] 192.168.1.128 - - [17/Feb/2014:11:48:37 +0000] "POST http://192.168.1.128:35357/v2.0/tokens HTTP/1.0" 500 150

It appears that the user_ref has no 'name' property when I try to use samAccountName. This seems to have worked in Grizzly but does not work in Havana. Below are the applicable lines from the keystone.conf:

[ldap]
query_scope = sub
url = LDAP://192.168.1.253
user = CN=ldapuser,CN=Users,DC=mydomain,DC=net
password = ldapuserpassword
suffix = DC=mydomain,DC=net
use_dumb_member = True
dumb_member = CN=ldapuser,CN=Users,DC=mydomain,DC=net

user_tree_dn = CN=Users,DC=mydomain,DC=net
user_objectclass = organizationalPerson
user_id_attribute = samAccountName
user_name_attribute = samAccountName
user_mail_attribute = mail
user_enabled_attribute = userAccountControl
user_enabled_mask = 2
user_enabled_default = 512
user_attribute_ignore = password,tenant_id,tenants
user_allow_create = False
user_allow_update = False
user_allow_delete = False

tenant_tree_dn = OU=Projects,OU=OpenStack,DC=mydomain,DC=net
tenant_objectclass = organizationalUnit
tenant_id_attribute = ou
tenant_member_attribute = member
tenant_name_attribute = ou
tenant_desc_attribute = description
tenant_enabled_attribute = extensionName
tenant_attribute_ignore = description,businessCategory,extensionName
tenant_allow_create = True
tenant_allow_update = True
tenant_allow_delete = True

role_tree_dn = OU=Roles,OU=OpenStack,DC=mydomain,DC=net
role_objectclass = organizationalRole
role_id_attribute = cn
role_name_attribute = cn
role_member_attribute = roleOccupant
role_allow_create = True
role_allow_update = True
role_allow_delete = True

Again, if I change the user_id_attribute and the user_name_attribute to cn then everything works fine. Please advise. Thanks!

Dolph Mathews (dolph)
tags: added: havana-backport-potential
Revision history for this message
Brian Seltzer (seltzerb01) wrote :

I've discovered that other attributes work besides cn, including sn and gecos, but samAccountName doesn't work. This makes me think that it's got something to do with a schema definition somewhere, but I'm still digging around trying to find it. I'm running keystone havana on Ubuntu 12.04.4 LTS

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

I'd also be curious to know if this is still an issue in master -- a similar sounding issue was fixed awhile back, but perhaps not backported.

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

looks like I've got it working now. Turns out things are case sensitive, and the id attribute must be cn apparently. So:

user_id_attribute = cn
user_name_attribute = sAMAccountName

works. Note that I was using a different case - samAccountName - which is incorrect. sAMAccountName is correct. Now I can logon using my sAMAccountName even when it is different than the cn, which was my goal.

I guess this can be closed, though it might be good to document it somewhere.

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

FYI, I've got my whole Keystone/Active Directory configuration documented at http://behindtheracks.com/2013/08/openstack-active-directory-integration/

Dolph Mathews (dolph)
Changed in keystone:
importance: Undecided → Low
status: New → Triaged
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/74236

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

> it might be good to document it somewhere

Thanks, will do! I'm bookmarking your config as well.

Revision history for this message
Brant Knudson (blk-u) wrote :

I think we should look into this more to see if keystone is doing a case-insensitive compare of an attribute.

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

I've just done more testing, and I believe the case sensitivity is in python-ldap. This code demonstrates:

#!/usr/bin/env python
import ldap

server="ldap://mydomain.net"
user_dn="mydomain\myaccount"
user_pw="mypassword"

l = ldap.initialize(server)
l.bind_s(user_dn, user_pw)
base_dn = 'cn=Users,dc=mydomain,dc=net'
filter = '(&(objectclass=person)(sn=Seltzer))'
attrs = ['samaccountname']
results = l.search_s( base_dn, ldap.SCOPE_SUBTREE, filter, attrs )
for result in results:
 print result[1]
 print result[1]["samAccountName"][0]

the search itself is not case sensitive (the case used in the attrs doesn't matter), however the keyname in the result is indeed case sensitive so the last line throws a keyerror. However if I fix the case:

 print result[1]["sAMAccountName"][0]

then it works fine. So I think this behavior is baked into python-ldap...

Revision history for this message
Brant Knudson (blk-u) wrote :

I guess we could wrapper the results with a dict that does case-insensitive comparison.

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

That makes sense to me. If it was case-insensitive, my config would have worked the first time I think. Thanks for the attention!

Adam Young (ayoung)
Changed in keystone:
assignee: Dolph Mathews (dolph) → Adam Young (ayoung)
Revision history for this message
Nathan Kinder (nkinder) wrote :

The exact behavior is really a function of the LDAP server, as the server determines what case an attribute name is returned in. However the attribute name is returned is how python-ldap will use it in the dict. As an example, I did some tests with 389 Directory Server. If I don't explicitly ask for the attribute to return, it uses the attribute name as defined in the schema. If I do ask for the attribute to be returned, it is returned in the case that the client asked for it:

------------------------------------------------------
$ ldapsearch -x -D "cn=directory manager" -W -b "dc=example,dc=com" "sn=Kinder"
# nkinder, example.com
dn: uid=nkinder,dc=example,dc=com
cn: Nathan Kinder
...

$ ldapsearch -x -D "cn=directory manager" -W -b "dc=example,dc=com" "sn=Kinder" "cN"
# nkinder, example.com
dn: uid=nkinder,dc=example,dc=com
cN: Nathan Kinder

$ ldapsearch -x -D "cn=directory manager" -W -b "dc=example,dc=com" "sn=Kinder" "cn"
# nkinder, example.com
dn: uid=nkinder,dc=example,dc=com
cn: Nathan Kinder
------------------------------------------------------

Other LDAP servers may behave differently, such as returning the attribute name in the case that it is defined in the schema, regardless of how the client specifies the attribute name. Without knowing how a particular LDAP server implementation behaves, it's difficult to guess what case we should use when looking for an attribute in the dict. The only sure way to make this work is to do a case-insensitive comparison as suggested by Brant in comment#9.

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

Nathan, You are correct. I just tested against Active Directory, and the result came back with the case as defined in the schema, regardless of my input.

$ ldapsearch -x -D "cn=administrator,cn=users,dc=example,dc=com" -W -b "cn=users,dc=example,dc=com" -h 192.168.1.253 "cn=brian" "samaccountname"

# brian, Users, example.com
dn: CN=brian,CN=Users,DC=example,DC=com
sAMAccountName: brian

So yes, Active Directory appears to behave differently than 389 Directory Server, and Nate's case-insensitive compare suggestion would seem to be the right way to fix this.

Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

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

Changed in keystone:
assignee: Adam Young (ayoung) → Nathan Kinder (nkinder)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to keystone (master)

Reviewed: https://review.openstack.org/86486
Committed: https://git.openstack.org/cgit/openstack/keystone/commit/?id=7c104e13fce919dd2563f06ce31c059f145beb77
Submitter: Jenkins
Branch: master

commit 7c104e13fce919dd2563f06ce31c059f145beb77
Author: Nathan Kinder <email address hidden>
Date: Wed Apr 9 18:24:21 2014 -0700

    Treat LDAP attribute names as case-insensitive

    LDAP attribute names are case-insensitive, and different LDAP
    server implementations behave differently when returning search
    results. Keystone attempts to use the attribute names as defined
    in the mapping configuration when checking for values in the dict
    that represents the search results. If the case doesn't match,
    we won't find the values which can lead to errors.

    This patch converts the dictionary keys to lowercase to allow us
    to perform a case-insensitive lookup when processing LDAP search
    results. When we create the model object, we still use the
    attribute name case as defined in the mapping to allow predictable
    lookups when we process the model object later.

    Change-Id: Ib9a03b912bc7652dc6a61b1c97a950e263a9c6fa
    Closes-bug: 1281216

Changed in keystone:
status: In Progress → Fix Committed
Brant Knudson (blk-u)
tags: added: icehouse-backport-potential
Dolph Mathews (dolph)
tags: added: ldap
removed: active directory
Revision history for this message
Openstack Gerrit (openstack-gerrit) wrote : Fix proposed to keystone (stable/icehouse)

Fix proposed to branch: stable/icehouse
Review: https://review.openstack.org/89898

Alan Pevec (apevec)
tags: removed: icehouse-backport-potential
Revision history for this message
Openstack Gerrit (openstack-gerrit) wrote : Fix merged to keystone (stable/icehouse)

Reviewed: https://review.openstack.org/89898
Committed: https://git.openstack.org/cgit/openstack/keystone/commit/?id=1716748df15443f1141f69ea620c4bc33758433d
Submitter: Jenkins
Branch: stable/icehouse

commit 1716748df15443f1141f69ea620c4bc33758433d
Author: Nathan Kinder <email address hidden>
Date: Wed Apr 9 18:24:21 2014 -0700

    Treat LDAP attribute names as case-insensitive

    LDAP attribute names are case-insensitive, and different LDAP
    server implementations behave differently when returning search
    results. Keystone attempts to use the attribute names as defined
    in the mapping configuration when checking for values in the dict
    that represents the search results. If the case doesn't match,
    we won't find the values which can lead to errors.

    This patch converts the dictionary keys to lowercase to allow us
    to perform a case-insensitive lookup when processing LDAP search
    results. When we create the model object, we still use the
    attribute name case as defined in the mapping to allow predictable
    lookups when we process the model object later.

    Change-Id: Ib9a03b912bc7652dc6a61b1c97a950e263a9c6fa
    Closes-bug: 1281216
    (cherry picked from commit 7c104e13fce919dd2563f06ce31c059f145beb77)

Thierry Carrez (ttx)
Changed in keystone:
milestone: none → juno-1
status: Fix Committed → Fix Released
Thierry Carrez (ttx)
Changed in keystone:
milestone: juno-1 → 2014.2
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.