Merge "make LDAP query scope configurable"

This commit is contained in:
Jenkins 2013-02-20 10:28:19 +00:00 committed by Gerrit Code Review
commit d036db145d
4 changed files with 49 additions and 10 deletions

View File

@ -138,6 +138,10 @@
# allow_subtree_delete = False
# dumb_member = cn=dumb,dc=example,dc=com
# The LDAP scope for queries, this can be either 'one'
# (onelevel/singleLevel) or 'sub' (subtree/wholeSubtree)
# query_scope = one
# user_tree_dn = ou=Users,dc=example,dc=com
# user_filter =
# user_objectclass = inetOrgPerson

View File

@ -26,6 +26,8 @@ LOG = logging.getLogger(__name__)
LDAP_VALUES = {'TRUE': True, 'FALSE': False}
CONTROL_TREEDELETE = '1.2.840.113556.1.4.805'
LDAP_SCOPES = {'one': ldap.SCOPE_ONELEVEL,
'sub': ldap.SCOPE_SUBTREE}
def py2ldap(val):
@ -59,6 +61,14 @@ def safe_iter(attrs):
yield attrs
def ldap_scope(scope):
try:
return LDAP_SCOPES[scope]
except KeyError:
raise ValueError(_('Invalid LDAP scope: %s. Choose one of: ' % scope) +
', '.join(LDAP_SCOPES.keys()))
class BaseLdap(object):
DEFAULT_SUFFIX = "dc=example,dc=com"
DEFAULT_OU = None
@ -77,6 +87,7 @@ class BaseLdap(object):
self.LDAP_URL = conf.ldap.url
self.LDAP_USER = conf.ldap.user
self.LDAP_PASSWORD = conf.ldap.password
self.LDAP_SCOPE = ldap_scope(conf.ldap.query_scope)
if self.options_name is not None:
self.suffix = conf.ldap.suffix
@ -133,9 +144,18 @@ class BaseLdap(object):
return conn
def _id_to_dn(self, id):
return '%s=%s,%s' % (self.id_attr,
ldap.dn.escape_dn_chars(str(id)),
self.tree_dn)
conn = self.get_connection()
try:
dn, attrs = 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})[0]
except ValueError, IndexError:
raise ldap.NO_SUCH_OBJECT
else:
return dn
@staticmethod
def _dn_to_id(dn):
@ -203,16 +223,18 @@ class BaseLdap(object):
def _ldap_get(self, id, filter=None):
conn = self.get_connection()
query = '(&%s(objectClass=%s))' % (filter or self.filter or '',
self.object_class)
query = ('(&(%(id_attr)s=%(id)s)'
'%(filter)s'
'(objectClass=%(object_class)s))'
% {'id_attr': self.id_attr,
'id': ldap.filter.escape_filter_chars(str(id)),
'filter': (filter or self.filter or ''),
'object_class': self.object_class})
try:
res = conn.search_s(self._id_to_dn(id),
ldap.SCOPE_BASE,
query,
res = conn.search_s(self.tree_dn, self.LDAP_SCOPE, query,
self.attribute_mapping.values())
except ldap.NO_SUCH_OBJECT:
return None
try:
return res[0]
except IndexError:
@ -224,7 +246,7 @@ class BaseLdap(object):
self.object_class)
try:
return conn.search_s(self.tree_dn,
ldap.SCOPE_ONELEVEL,
self.LDAP_SCOPE,
query,
self.attribute_mapping.values())
except ldap.NO_SUCH_OBJECT:

View File

@ -249,6 +249,7 @@ register_str('suffix', group='ldap', default='cn=example,cn=com')
register_bool('use_dumb_member', group='ldap', default=False)
register_str('dumb_member', group='ldap', default='cn=dumb,dc=nonexistent')
register_bool('allow_subtree_delete', group='ldap', default=False)
register_str('query_scope', group='ldap', default='one')
register_str('user_tree_dn', group='ldap', default=None)
register_str('user_filter', group='ldap', default=None)

View File

@ -14,9 +14,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import ldap
import uuid
import nose.exc
from keystone.common import ldap as ldap_common
from keystone.common.ldap import fakeldap
from keystone import config
from keystone import exception
@ -42,6 +44,9 @@ class LDAPIdentity(test.TestCase, test_backend.IdentityTests):
test.testsdir('test_overrides.conf'),
test.testsdir('backend_ldap.conf')])
clear_database()
self.stubs.Set(ldap_common.BaseLdap, "_id_to_dn",
lambda self, id: '%s=%s,%s' % (self.id_attr,
str(id), self.tree_dn))
self.identity_api = identity_ldap.Identity()
self.load_fixtures(default_fixtures)
@ -347,6 +352,13 @@ class LDAPIdentity(test.TestCase, test_backend.IdentityTests):
user_api.get_connection(user=None, password=None)
def test_wrong_ldap_scope(self):
CONF.ldap.query_scope = uuid.uuid4().hex
self.assertRaisesRegexp(
ValueError,
'Invalid LDAP scope: %s. *' % CONF.ldap.query_scope,
identity_ldap.Identity)
# TODO (henry-nash) These need to be removed when the full LDAP implementation
# is submitted - see Bugs 1092187, 1101287, 1101276, 1101289
def test_group_crud(self):