Keystone with LDAP can't bind to dc=example,dc=com

asked 2013-09-09 16:45:45 -0600

amgrimes gravatar image

updated 2013-09-24 11:23:39 -0600

I have successfully set up Keystone (Grizzly, Ubuntu 12.04) with an LDAP backend (Active Directory) when I set user_tree_dn to be any OU in the domain. The working settings, with all users located in ou=OpenStackUsers,ou=OpenStack,dc-example,dc=com:

url = ldap://DomainController
user = cn=TestUser,cn=Users,dc=example,dc=com
password = password
suffix = dc=example,dc=com
use_dumb_member = True
dumb_member = cn=TestUser,cn=Users,dc=example,dc=com
query_scope = sub
user_tree_dn = ou=OpenStack,dc=example,dc=com
user_filter = (memberof=cn=OpenStackGroup,ou=OpenStack,dc=example,dc=com)

However, I need to have my regular users under one OU and service accounts under another, and both OUs under the root domain (dc=example,dc=com). This corresponds to these settings:

url = ldap://DomainController
user = cn=TestUser,cn=Users,dc=example,dc=com
password = password
suffix = dc=example,dc=com
use_dumb_member = True
dumb_member = cn=TestUser,cn=Users,dc=example,dc=com
query_scope = sub
user_tree_dn = dc=example,dc=com
user_filter = (memberof=cn=OpenStackGroup,ou=OpenStack,dc=example,dc=com

With these settings when I do keystone user-list I get the following error:

Authorization Failed: Unable to communicate with identity service: {"error": {"message": "An unexpected error prevented the server from fulfilling your request. {'info': '000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1', 'desc': 'Operations error'}", "code": 500, "title": "Internal Server Error"}}. (HTTP 500)

When performing an equivalent ldapsearch, the results get returned correctly:

ldapsearch -LLL -x -H ldap://DomainController:389 -b 'dc=example,dc=com' -D 'EXAMPLE\TestUser' -W '(memberof=cn=OpenStackGroup,ou=OpenStack,dc=example,dc=com)' "objectclass=*" cn
Enter LDAP Password:
dn: CN=nova,OU=OpenStackUsers,OU=OpenStack,DC=example,DC=com
cn: nova

dn: CN=admin,OU=OpenStackUsers,OU=OpenStack,DC=example,DC=com
cn: admin

dn: CN=glance,OU=OpenStackUsers,OU=OpenStack,DC=example,DC=com
cn: glance

dn: CN=quantum,OU=OpenStackUsers,OU=OpenStack,DC=example,DC=com
cn: quantum

dn: CN=cinder,OU=OpenStackUsers,OU=OpenStack,DC=example,DC=com
cn: cinder

dn: CN=TestUser,cn=Users,DC=example,DC=com
cn: TestUser

Has anybody ever gotten this type of setup working? Is there something in Keystone that is stopping the bind at the DC level?

UPDATE: I used Wireshark to capture the LDAP packets, and tracked down the "Operations Error" to be the response when OpenStack tries to bind to the following 3 DNs:

  1. cn=Configuration,dc=example,dc=com
  2. dc=ForestDNSZones,dc=example,dc=com
  3. dc=DomainDNSZones,dc=example,dc=com

When I use ldp.exe on Windows or ldapsearch on Ubuntu I'm able to bind to these DNs perfectly fine. I think this is a problem with OpenStack not being able to bind to them, although I don't know why that would be the case. I have no reason to be searching those DNs anyway so if there was a way to make OpenStack ignore them that would be great. Unfortunately, I'm not a ... (more)

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2013-09-30 13:08:55 -0600

amgrimes gravatar image

updated 2013-09-30 13:09:42 -0600

I was finally able to solve this on my own. As it turns out, python-ldap does not handle Active Directory referrals very well, because it can't use the credentials that are used to bind initially and instead tries to bind anonymously. This is why I got the "OperationsError" - Active Directory was (rightly so) refusing the anonymous bind connection. See question #12 at . The fix to this is to add a line in /usr/share/pyshared/keystone/common/ldap/ that says to ignore referrals. Under the ldap.initialize line we need to have:

self.conn.set_option(ldap.OPT_REFERRALS, 0)

After this, I got a new error: "AttributeError: 'list' object has no attribute 'iteritems'". This happened because the referrals were still included in the results list, even though they weren't chased down. This meant that the "res" list had unexpected tuples in it, like "None, ['ldap://,DC=example,DC=com']. The solution was to add another 2 lines. At the beginning of the code, I need:

from types import *

Then I need to modify search_s, adding an if statement before o.append:

def search_s(self, dn, scope, query, attrlist=None):
    LOG.debug(_("attrlist = %s"), attrlist)
    if LOG.isEnabledFor(logging.DEBUG):
        LOG.debug(_('LDAP search: dn=%s, scope=%s, query=%s, attrs=%s'),
    if self.page_size:
        res = self.paged_search_s(dn, scope, query, attrlist)
        res = self.conn.search_s(dn, scope, query, attrlist)
    o = []
    for dn, attrs in res:
        if type(dn) is not NoneType:
            o.append((dn, dict((kind, [ldap2py(x) for x in values])
                               for kind, values in attrs.iteritems())))
    return o

This way, the referrals are removed and I get the correct search results.

Note: I am not a software developer and have never worked with Python until today, so I take no responsibility if you try this and it breaks your application.

edit flag offensive delete link more

Get to know Ask OpenStack

Resources for moderators

Question Tools



Asked: 2013-09-09 16:45:45 -0600

Seen: 15,615 times

Last updated: Sep 30 '13