From 801a81506e688bca800bd4164b4210fdcc5fee05 Mon Sep 17 00:00:00 2001 From: Brant Knudson Date: Thu, 8 Aug 2013 15:36:20 -0500 Subject: [PATCH] Fixes for Active Directory The LDAP Identity backend was not properly using the user_enabled_default option as a string. This caused operations to fail with TypeError: unsupported operand type(s) for &: 'str' and 'int' Also, fetching users using the LDAP Identity backend would fail with KeyError: 'enabled' from _ldap_res_to_model when user_enabled_mask is not 0. Closes-Bug: #1210175 (cherry picked from commit 68f38a65c60485c34474e490d649b328421e10f5) (cherry picked from commit 116897786dbb8473154ec85a01b019af8106a1f4) (cherry picked from commit 54178b735dea4dfee4578caa95cb3ae704afef07) (cherry picked from commit 87ababb38506a1a51b9e38fc343dd3b46c828a80) (cherry picked from commit 781c65b72b78bd1e2b1d93db029d6b0c6fbc2050) Change-Id: Ic01aa505d867c1de30e2a1ed7c79ff1478e213ef --- keystone/identity/backends/ldap/core.py | 7 ++-- tests/_ldap_livetest.py | 8 +++-- tests/test_backend_ldap.py | 47 ++++++++++++++++++++----- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/keystone/identity/backends/ldap/core.py b/keystone/identity/backends/ldap/core.py index 090e802e58..8ac73951a7 100644 --- a/keystone/identity/backends/ldap/core.py +++ b/keystone/identity/backends/ldap/core.py @@ -430,14 +430,15 @@ class UserApi(common_ldap.EnabledEmuMixIn, common_ldap.BaseLdap, ApiShimMixin): def _ldap_res_to_model(self, res): obj = super(UserApi, self)._ldap_res_to_model(res) if self.enabled_mask != 0: - obj['enabled_nomask'] = obj['enabled'] - obj['enabled'] = ((obj['enabled'] & self.enabled_mask) != + enabled = int(obj.get('enabled', self.enabled_default)) + obj['enabled_nomask'] = enabled + obj['enabled'] = ((enabled & self.enabled_mask) != self.enabled_mask) return obj def mask_enabled_attribute(self, values): value = values['enabled'] - values.setdefault('enabled_nomask', self.enabled_default) + values.setdefault('enabled_nomask', int(self.enabled_default)) if value != ((values['enabled_nomask'] & self.enabled_mask) != self.enabled_mask): values['enabled_nomask'] ^= self.enabled_mask diff --git a/tests/_ldap_livetest.py b/tests/_ldap_livetest.py index 279986a099..383b6edca7 100644 --- a/tests/_ldap_livetest.py +++ b/tests/_ldap_livetest.py @@ -92,9 +92,6 @@ class LiveLDAPIdentity(test_backend_ldap.LDAPIdentity): def tearDown(self): test.TestCase.tearDown(self) - def test_user_enable_attribute_mask(self): - raise nose.exc.SkipTest('Test is for Active Directory Only') - def test_ldap_dereferencing(self): alt_users_ldif = {'objectclass': ['top', 'organizationalUnit'], 'ou': 'alt_users'} @@ -163,3 +160,8 @@ class LiveLDAPIdentity(test_backend_ldap.LDAPIdentity): alias_dereferencing=deref) self.assertEqual(ldap.DEREF_SEARCHING, ldap_wrapper.conn.get_option(ldap.OPT_DEREF)) + + def test_user_enable_attribute_mask(self): + CONF.ldap.user_enabled_emulation = False + CONF.ldap.user_enabled_attribute = 'employeeType' + super(LiveLDAPIdentity, self).test_user_enable_attribute_mask() diff --git a/tests/test_backend_ldap.py b/tests/test_backend_ldap.py index 4020b36234..cd2506e8c6 100644 --- a/tests/test_backend_ldap.py +++ b/tests/test_backend_ldap.py @@ -19,7 +19,6 @@ 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 @@ -318,25 +317,55 @@ class LDAPIdentity(test.TestCase, test_backend.IdentityTests): self.assertNotIn('name', role_ref) def test_user_enable_attribute_mask(self): - CONF.ldap.user_enabled_attribute = 'enabled' CONF.ldap.user_enabled_mask = 2 - CONF.ldap.user_enabled_default = 512 + CONF.ldap.user_enabled_default = '512' self.clear_database() self.identity_api = identity.backends.ldap.Identity() + self.load_fixtures(default_fixtures) + + ldap_ = self.identity_api.user.get_connection() + + def get_enabled_vals(): + user_dn = self.identity_api.user._id_to_dn_string('fake1') + enabled_attr_name = CONF.ldap.user_enabled_attribute + + res = ldap_.search_s(user_dn, + ldap.SCOPE_BASE, + query='(sn=fake1)') + return res[0][1][enabled_attr_name] + user = {'id': 'fake1', 'name': 'fake1', 'enabled': True} - self.identity_api.create_user('fake1', user) + + user_ref = self.identity_api.create_user('fake1', user) + + self.assertEqual(user_ref['enabled'], 512) + # TODO(blk-u): 512 seems wrong, should it be True? + + enabled_vals = get_enabled_vals() + self.assertEqual(enabled_vals, [512]) + user_ref = self.identity_api.get_user('fake1') - self.assertEqual(user_ref['enabled'], True) + self.assertIs(user_ref['enabled'], True) user['enabled'] = False - self.identity_api.update_user('fake1', user) + user_ref = self.identity_api.update_user('fake1', user) + self.assertIs(user_ref['enabled'], False) + + enabled_vals = get_enabled_vals() + self.assertEqual(enabled_vals, [514]) + user_ref = self.identity_api.get_user('fake1') - self.assertEqual(user_ref['enabled'], False) + self.assertIs(user_ref['enabled'], False) user['enabled'] = True - self.identity_api.update_user('fake1', user) + user_ref = self.identity_api.update_user('fake1', user) + self.assertIs(user_ref['enabled'], True) + + enabled_vals = get_enabled_vals() + self.assertEqual(enabled_vals, [512]) + user_ref = self.identity_api.get_user('fake1') - self.assertEqual(user_ref['enabled'], True) + self.assertIs(user_ref['enabled'], True) def test_user_api_get_connection_no_user_password(self): """Don't bind in case the user and password are blank"""