def test_ldap_context(mocker, settings, options): warn = mocker.patch('flask_multipass.providers.ldap.util.warn') ldap_initialize = mocker.patch( 'flask_multipass.providers.ldap.util.ReconnectLDAPObject') ldap_conn = MagicMock() ldap_initialize.return_value = ldap_conn with ldap_context(settings) as ldap_ctx: ldap_initialize.called_once_with(settings['uri']) assert ldap_conn.protocol_version == ldap.VERSION3, 'LDAP v3 has not been set' assert ldap_conn.set_option.mock_calls == [ call.set_option(*args) for args in options ], 'Not all options set' if settings['starttls']: if urlparse(settings['uri']).scheme == 'ldaps': warn.assert_called_once_with( 'Unable to start TLS, LDAP connection already secured over SSL (LDAPS)' ) else: ldap_conn.start_tls_s.assert_called_once_with() ldap_conn.simple_bind_s.assert_called_once_with( settings['bind_dn'], settings['bind_password']) assert current_ldap == ldap_ctx, 'The LDAP context has not been set as the current one' assert current_ldap == LDAPContext(connection=ldap_conn, settings=settings) ldap_conn.unbind_s.called_once() assert not current_ldap, 'The LDAP context has not been unset'
def search_identities(self, criteria, exact=False): with ldap_context(self.ldap_settings): search_filter = build_user_search_filter(criteria, self.settings['mapping'], exact=exact) if not search_filter: raise IdentityRetrievalFailed("Unable to generate search filter from criteria") for _, user_data in self._search_users(search_filter): yield IdentityInfo(self, identifier=user_data[self.ldap_settings['uid']][0], **to_unicode(user_data))
def search_groups(self, name, exact=False): with ldap_context(self.ldap_settings): search_filter = build_group_search_filter({self.ldap_settings['gid']: {name}}, exact=exact) if not search_filter: raise GroupRetrievalFailed("Unable to generate search filter from criteria") for group_dn, group_data in self._search_groups(search_filter): yield self.group_class(self, group_data.get(self.ldap_settings['gid'])[0], group_dn)
def _get_identity(self, identifier): with ldap_context(self.ldap_settings): user_dn, user_data = get_user_by_id(identifier, self._attributes) if not user_dn: return None return IdentityInfo(self, identifier=user_data[self.ldap_settings['uid']][0], **to_unicode(user_data))
def get_group(self, name): with ldap_context(self.ldap_settings): group_dn, group_data = get_group_by_id(name, [self.ldap_settings['gid']]) if not group_dn: return None group_name = to_unicode(group_data[self.ldap_settings['gid']][0]) return self.group_class(self, group_name, group_dn)
def get_group(self, name): with ldap_context(self.ldap_settings): group_dn, group_data = get_group_by_id(name, [self.ldap_settings['gid']]) if not group_dn: return None return self.group_class(self, group_data.get(self.ldap_settings['gid'])[0], group_dn)
def test_search_none_existing_entry(mocker, settings, base_dn, search_filter, attributes, msg_ids): page_ctrl = MagicMock() mocker.patch('flask_multipass.providers.ldap.operations.SimplePagedResultsControl', return_value=page_ctrl) ldap_connection = MagicMock(result3=MagicMock(side_effect=NO_SUCH_OBJECT), search_ext=MagicMock(side_effect=msg_ids)) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_connection) with ldap_context(settings): for result in search(base_dn, search_filter, attributes): pytest.fail('search should not yield any result')
def search_groups(self, name, exact=False): with ldap_context(self.ldap_settings): search_filter = build_group_search_filter( {self.ldap_settings['gid']: {name}}, exact=exact) if not search_filter: raise GroupRetrievalFailed( "Unable to generate search filter from criteria") for group_dn, group_data in self._search_groups(search_filter): yield self.group_class( self, group_data.get(self.ldap_settings['gid'])[0], group_dn)
def get_members(self): with ldap_context(self.ldap_settings): group_dns = self._iter_group() group_dn = next(group_dns) while group_dn: user_filter = build_user_search_filter({self.ldap_settings['member_of_attr']: {group_dn}}, exact=True) for _, user_data in self.provider._search_users(user_filter): yield IdentityInfo(self.provider, identifier=user_data[self.ldap_settings['uid']][0], **to_unicode(user_data)) group_filter = build_group_search_filter({self.ldap_settings['member_of_attr']: {group_dn}}, exact=True) subgroups = list(self.provider._search_groups(group_filter)) group_dn = group_dns.send(subgroups)
def search_groups(self, name, exact=False): with ldap_context(self.ldap_settings): search_filter = build_group_search_filter( {self.ldap_settings['gid']: {name}}, exact=exact) if not search_filter: raise GroupRetrievalFailed( "Unable to generate search filter from criteria", provider=self) for group_dn, group_data in self._search_groups(search_filter): group_name = to_unicode( group_data[self.ldap_settings['gid']][0]) yield self.group_class(self, group_name, group_dn)
def has_member(self, user_identifier): with ldap_context(self.ldap_settings): user_dn, user_data = get_user_by_id(user_identifier, attributes=[self.ldap_settings['member_of_attr']]) if not user_dn: return False if self.ldap_settings['ad_group_style']: group_dn, group_data = get_group_by_id(self.name, attributes=['objectSid']) group_sids = group_data.get('objectSid') token_groups = get_token_groups_from_user_dn(user_dn) return any(group_sid in token_groups for group_sid in group_sids) else: return self.dn in user_data.get(self.ldap_settings['member_of_attr'], [])
def search_identities(self, criteria, exact=False): with ldap_context(self.ldap_settings): search_filter = build_user_search_filter(criteria, self.settings['mapping'], exact=exact) if not search_filter: raise IdentityRetrievalFailed( "Unable to generate search filter from criteria") for _, user_data in self._search_users(search_filter): yield IdentityInfo( self, identifier=user_data[self.ldap_settings['uid']][0], **to_unicode(user_data))
def process_local_login(self, data): username = data['username'] password = data['password'] with ldap_context(self.ldap_settings, use_cache=False): try: user_dn, user_data = get_user_by_id(username, attributes=[self.ldap_settings['uid']]) if not user_dn: raise NoSuchUser current_ldap.connection.simple_bind_s(user_dn, password) except INVALID_CREDENTIALS: raise InvalidCredentials auth_info = AuthInfo(self, identifier=user_data[self.ldap_settings['uid']][0]) return self.multipass.handle_auth_success(auth_info)
def test_search(mocker, settings, base_dn, search_filter, attributes, mock_data, expected): mock_data['cookies'].append('') # last search operation should not return a cookie page_ctrl = MagicMock() mocker.patch('flask_multipass.providers.ldap.operations.SimplePagedResultsControl', return_value=page_ctrl) ldap_connection = MagicMock(result3=MagicMock(side_effect=((None, entries, None, [page_ctrl]) for entries in mock_data['results'])), search_ext=MagicMock(side_effect=mock_data['msg_ids'])) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_connection) mocker.patch('flask_multipass.providers.ldap.operations.get_page_cookie', side_effect=mock_data['cookies']) with ldap_context(settings): for i, result in enumerate(search(base_dn, search_filter, attributes)): assert result == expected[i]
def test_search_none_existing_entry(mocker, settings, base_dn, search_filter, attributes, msg_ids): page_ctrl = MagicMock() mocker.patch( 'flask_multipass.providers.ldap.operations.SimplePagedResultsControl', return_value=page_ctrl) ldap_connection = MagicMock(result3=MagicMock(side_effect=NO_SUCH_OBJECT), search_ext=MagicMock(side_effect=msg_ids)) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_connection) with ldap_context(settings): for result in search(base_dn, search_filter, attributes): pytest.fail('search should not yield any result')
def process_local_login(self, data): username = data['username'] password = data['password'] with ldap_context(self.ldap_settings, use_cache=False): try: user_dn, user_data = get_user_by_id( username, attributes=[self.ldap_settings['uid']]) if not user_dn: raise NoSuchUser(provider=self) current_ldap.connection.simple_bind_s(user_dn, password) except INVALID_CREDENTIALS: raise InvalidCredentials(provider=self) auth_info = AuthInfo( self, identifier=user_data[self.ldap_settings['uid']][0]) return self.multipass.handle_auth_success(auth_info)
def test_find_one(mocker, base_dn, search_filter, data, expected): settings = { 'uri': 'ldaps://ldap.example.com:636', 'bind_dn': 'uid=admin,DC=example,DC=com', 'bind_password': '******', 'verify_cert': True, 'starttls': True, 'timeout': 10 } ldap_search = MagicMock(return_value=data) ldap_conn = MagicMock(search_ext_s=ldap_search) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_conn) with ldap_context(settings): assert find_one(base_dn, search_filter) == expected
def has_member(self, user_identifier): with ldap_context(self.ldap_settings): user_dn, user_data = get_user_by_id( user_identifier, attributes=[self.ldap_settings['member_of_attr']]) if not user_dn: return False if self.ldap_settings['ad_group_style']: group_dn, group_data = get_group_by_id( self.name, attributes=['objectSid']) group_sids = group_data.get('objectSid') token_groups = get_token_groups_from_user_dn(user_dn) return any(group_sid in token_groups for group_sid in group_sids) else: return self.dn in user_data.get( self.ldap_settings['member_of_attr'], [])
def get_members(self): with ldap_context(self.ldap_settings): group_dns = self._iter_group() group_dn = next(group_dns) while group_dn: user_filter = build_user_search_filter( {self.ldap_settings['member_of_attr']: {group_dn}}, exact=True) for _, user_data in self.provider._search_users(user_filter): yield IdentityInfo( self.provider, identifier=user_data[self.ldap_settings['uid']][0], **to_unicode(user_data)) group_filter = build_group_search_filter( {self.ldap_settings['member_of_attr']: {group_dn}}, exact=True) subgroups = list(self.provider._search_groups(group_filter)) group_dn = group_dns.send(subgroups)
def test_ldap_context_invalid_credentials(mocker, method, triggered_exception, caught_exception, message): settings = { 'uri': 'ldaps://ldap.example.com:636', 'bind_dn': 'uid=admin,DC=example,DC=com', 'bind_password': '******', 'verify_cert': True, 'starttls': True } ldap_initialize = mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject') ldap_conn = MagicMock() getattr(ldap_conn, method).side_effect = triggered_exception ldap_initialize.return_value = ldap_conn with pytest.raises(caught_exception) as excinfo: with ldap_context(settings): current_ldap.connection.search_s('dc=example,dc=com', ldap.SCOPE_SUBTREE) assert excinfo.value.message == message
def test_get_token_groups_from_user_dn(mocker, user_dn, mock_data, expected): settings = { 'uri': 'ldaps://ldap.example.com:636', 'bind_dn': 'uid=admin,DC=example,DC=com', 'bind_password': '******', 'verify_cert': True, 'cert_file': ' /etc/ssl/certs/ca-certificates.crt', 'starttls': True, 'timeout': 10 } ldap_search = MagicMock(return_value=mock_data) ldap_conn = MagicMock(search_ext_s=ldap_search) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_conn) with ldap_context(settings): assert get_token_groups_from_user_dn(user_dn) == expected # Token-Groups must be retrieved from a base scope query ldap_search.assert_called_once_with(user_dn, SCOPE_BASE, sizelimit=1, timeout=settings['timeout'], attrlist=['tokenGroups'])
def test_ldap_context(mocker, settings, options): warn = mocker.patch('flask_multipass.providers.ldap.util.warn') ldap_initialize = mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject') ldap_conn = MagicMock() ldap_initialize.return_value = ldap_conn with ldap_context(settings) as ldap_ctx: ldap_initialize.called_once_with(settings['uri']) assert ldap_conn.protocol_version == ldap.VERSION3, 'LDAP v3 has not been set' assert ldap_conn.set_option.mock_calls == [call.set_option(*args) for args in options], 'Not all options set' if settings['starttls']: if urlparse(settings['uri']).scheme == 'ldaps': warn.assert_called_once_with('Unable to start TLS, LDAP connection already secured over SSL (LDAPS)') else: ldap_conn.start_tls_s.assert_called_once() ldap_conn.simple_bind_s.assert_called_once_with(settings['bind_dn'], settings['bind_password']) assert current_ldap == ldap_ctx, 'The LDAP context has not been set as the current one' assert current_ldap == LDAPContext(connection=ldap_conn, settings=settings) ldap_conn.unbind_s.called_once() assert not current_ldap, 'The LDAP context has not been unset'
def test_search(mocker, settings, base_dn, search_filter, attributes, mock_data, expected): mock_data['cookies'].append( '') # last search operation should not return a cookie page_ctrl = MagicMock() mocker.patch( 'flask_multipass.providers.ldap.operations.SimplePagedResultsControl', return_value=page_ctrl) ldap_connection = MagicMock( result3=MagicMock(side_effect=((None, entries, None, [page_ctrl]) for entries in mock_data['results'])), search_ext=MagicMock(side_effect=mock_data['msg_ids'])) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_connection) mocker.patch('flask_multipass.providers.ldap.operations.get_page_cookie', side_effect=mock_data['cookies']) with ldap_context(settings): for i, result in enumerate(search(base_dn, search_filter, attributes)): assert result == expected[i]
def get_identity_groups(self, identifier): groups = set() with ldap_context(self.ldap_settings): user_dn, user_data = get_user_by_id(identifier, self._attributes) if not user_dn: return set() if self.ldap_settings['ad_group_style']: for sid in get_token_groups_from_user_dn(user_dn): search_filter = build_group_search_filter( {'objectSid': {sid}}, exact=True) for group_dn, group_data in self._search_groups( search_filter): group_name = to_unicode( group_data[self.ldap_settings['gid']][0]) groups.add(self.group_class(self, group_name, group_dn)) else: # OpenLDAP does not have a way to get all groups for a user including nested ones raise NotImplementedError( 'Only available for active directory') return groups
def test_get_token_groups_from_user_dn(mocker, user_dn, mock_data, expected): settings = { 'uri': 'ldaps://ldap.example.com:636', 'bind_dn': 'uid=admin,DC=example,DC=com', 'bind_password': '******', 'verify_cert': True, 'starttls': True, 'timeout': 10 } ldap_search = MagicMock(return_value=mock_data) ldap_conn = MagicMock(search_ext_s=ldap_search) mocker.patch('flask_multipass.providers.ldap.util.ReconnectLDAPObject', return_value=ldap_conn) with ldap_context(settings): assert get_token_groups_from_user_dn(user_dn) == expected # Token-Groups must be retrieved from a base scope query ldap_search.assert_called_once_with(user_dn, SCOPE_BASE, sizelimit=1, timeout=settings['timeout'], attrlist=['tokenGroups'])