diff --git a/etc/keystone.conf.sample b/etc/keystone.conf.sample index 82bd757cb5..c81d3b6c41 100644 --- a/etc/keystone.conf.sample +++ b/etc/keystone.conf.sample @@ -110,6 +110,7 @@ # allow_subtree_delete = False # user_tree_dn = ou=Users,dc=example,dc=com +# user_filter = # user_objectclass = inetOrgPerson # user_id_attribute = cn # user_name_attribute = sn @@ -118,6 +119,7 @@ # user_allow_delete = True # tenant_tree_dn = ou=Groups,dc=example,dc=com +# tenant_filter = # tenant_objectclass = groupOfNames # tenant_id_attribute = cn # tenant_member_attribute = member @@ -127,6 +129,7 @@ # tenant_allow_delete = True # role_tree_dn = ou=Roles,dc=example,dc=com +# role_filter = # role_objectclass = organizationalRole # role_id_attribute = cn # role_member_attribute = roleOccupant diff --git a/keystone/common/ldap/core.py b/keystone/common/ldap/core.py index 027bc1bedc..4a80d66a3e 100644 --- a/keystone/common/ldap/core.py +++ b/keystone/common/ldap/core.py @@ -65,6 +65,7 @@ class BaseLdap(object): DEFAULT_STRUCTURAL_CLASSES = None DEFAULT_ID_ATTR = 'cn' DEFAULT_OBJECTCLASS = None + DEFAULT_FILTER = None DUMB_MEMBER_DN = 'cn=dumb,dc=nonexistent' options_name = None model = None @@ -93,6 +94,9 @@ class BaseLdap(object): self.object_class = (getattr(conf.ldap, objclass) or self.DEFAULT_OBJECTCLASS) + filter = '%s_filter' % self.options_name + self.filter = getattr(conf.ldap, filter) or self.DEFAULT_FILTER + allow_create = '%s_allow_create' % self.options_name self.allow_create = getattr(conf.ldap, allow_create) @@ -198,9 +202,10 @@ class BaseLdap(object): def _ldap_get(self, id, filter=None): conn = self.get_connection() query = '(objectClass=%s)' % self.object_class - if filter is not None: - query = '(&%s%s)' % (filter, query) - + if (filter is not None or self.filter is not None): + localfilter = self.filter if self.filter is not None else '' + paramfilter = filter if filter is not None else '' + query = '(&%s%s%s)' % (localfilter, paramfilter, query) try: res = conn.search_s(self._id_to_dn(id), ldap.SCOPE_BASE, query) except ldap.NO_SUCH_OBJECT: @@ -214,8 +219,10 @@ class BaseLdap(object): def _ldap_get_all(self, filter=None): conn = self.get_connection() query = '(objectClass=%s)' % (self.object_class,) - if filter is not None: - query = '(&%s%s)' % (filter, query) + if (filter is not None or self.filter is not None): + localfilter = self.filter if self.filter is not None else '' + paramfilter = filter if filter is not None else '' + query = '(&%s%s%s)' % (localfilter, paramfilter, query) try: return conn.search_s(self.tree_dn, ldap.SCOPE_ONELEVEL, query) except ldap.NO_SUCH_OBJECT: diff --git a/keystone/config.py b/keystone/config.py index a6d5f0c62a..dc6c41d2ae 100644 --- a/keystone/config.py +++ b/keystone/config.py @@ -167,6 +167,7 @@ register_str('user_name_attribute', group='ldap', default='sn') register_bool('allow_subtree_delete', group='ldap', default=False) register_str('user_tree_dn', group='ldap', default=None) +register_str('user_filter', group='ldap', default=None) register_str('user_objectclass', group='ldap', default='inetOrgPerson') register_str('user_id_attribute', group='ldap', default='cn') register_bool('user_allow_create', group='ldap', default=True) @@ -174,6 +175,7 @@ register_bool('user_allow_update', group='ldap', default=True) register_bool('user_allow_delete', group='ldap', default=True) register_str('tenant_tree_dn', group='ldap', default=None) +register_str('tenant_filter', group='ldap', default=None) register_str('tenant_objectclass', group='ldap', default='groupOfNames') register_str('tenant_id_attribute', group='ldap', default='cn') register_str('tenant_member_attribute', group='ldap', default='member') @@ -183,6 +185,7 @@ register_bool('tenant_allow_update', group='ldap', default=True) register_bool('tenant_allow_delete', group='ldap', default=True) register_str('role_tree_dn', group='ldap', default=None) +register_str('role_filter', group='ldap', default=None) register_str('role_objectclass', group='ldap', default='organizationalRole') register_str('role_id_attribute', group='ldap', default='cn') register_str('role_member_attribute', group='ldap', default='roleOccupant') diff --git a/keystone/identity/backends/ldap/core.py b/keystone/identity/backends/ldap/core.py index deb78e43d2..352abd7d68 100644 --- a/keystone/identity/backends/ldap/core.py +++ b/keystone/identity/backends/ldap/core.py @@ -357,9 +357,9 @@ class UserApi(common_ldap.BaseLdap, ApiShimMixin): raise exception.UserNotFound(user_id=id) def get_by_name(self, name, filter=None): - users = self.get_all('(%s=%s)' % - (self.attribute_mapping['name'], + query = ('(%s=%s)' % (self.attribute_mapping['name'], ldap_filter.escape_filter_chars(name))) + users = self.get_all(query) try: return users[0] except IndexError: @@ -411,8 +411,9 @@ class UserApi(common_ldap.BaseLdap, ApiShimMixin): self.role_api.rolegrant_delete(ref.id) def get_by_email(self, email): - users = self.get_all('(mail=%s)' % - (ldap_filter.escape_filter_chars(email),)) + query = ('(%s=%s)' % (self.attribute_mapping['mail'], + ldap_filter.escape_filter_chars(email))) + users = self.get_all(query) try: return users[0] except IndexError: diff --git a/tests/test_backend_ldap.py b/tests/test_backend_ldap.py index d4ca25064e..1b3d4b902a 100644 --- a/tests/test_backend_ldap.py +++ b/tests/test_backend_ldap.py @@ -202,3 +202,43 @@ class LDAPIdentity(test.TestCase, test_backend.IdentityTests): self.assertRaises(exception.ForbiddenAction, self.identity_api.delete_role, self.role_useless['id']) + + def test_user_filter(self): + self.config([test.etcdir('keystone.conf.sample'), + test.testsdir('test_overrides.conf'), + test.testsdir('backend_ldap.conf')]) + user_ref = self.identity_api.get_user(self.user_foo['id']) + self.user_foo.pop('password') + self.assertDictEqual(user_ref, self.user_foo) + + CONF.ldap.user_filter = '(CN=DOES_NOT_MATCH)' + self.identity_api = identity_ldap.Identity() + self.assertRaises(exception.UserNotFound, + self.identity_api.get_user, + self.user_foo['id']) + + def test_tenant_filter(self): + self.config([test.etcdir('keystone.conf.sample'), + test.testsdir('test_overrides.conf'), + test.testsdir('backend_ldap.conf')]) + tenant_ref = self.identity_api.get_tenant(self.tenant_bar['id']) + self.assertDictEqual(tenant_ref, self.tenant_bar) + + CONF.ldap.tenant_filter = '(CN=DOES_NOT_MATCH)' + self.identity_api = identity_ldap.Identity() + self.assertRaises(exception.TenantNotFound, + self.identity_api.get_tenant, + self.tenant_bar['id']) + + def test_role_filter(self): + self.config([test.etcdir('keystone.conf.sample'), + test.testsdir('test_overrides.conf'), + test.testsdir('backend_ldap.conf')]) + role_ref = self.identity_api.get_role(self.role_useless['id']) + self.assertDictEqual(role_ref, self.role_useless) + + CONF.ldap.role_filter = '(CN=DOES_NOT_MATCH)' + self.identity_api = identity_ldap.Identity() + self.assertRaises(exception.RoleNotFound, + self.identity_api.get_role, + self.role_useless['id'])