Merge "make LDAP query scope configurable"
This commit is contained in:
commit
d036db145d
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
Loading…
x
Reference in New Issue
Block a user