def test_sync_no_groups_and_on_disk_definitions(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) # No groups - should result in no new remote assignments but existing local assignments # shouldn't be manipulated result = syncer.sync(user_db=self.users['user_1'], groups=[]) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(created_role_assignment_dbs, []) self.assertEqual(removed_role_assignment_dbs, []) role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) # Groups but no mapping to role definitions, should result in no new remote assignments groups = ['CN=stormers,OU=groups,DC=stackstorm,DC=net'] result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(created_role_assignment_dbs, []) self.assertEqual(removed_role_assignment_dbs, []) role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2'])
def test_sync_user_same_role_granted_locally_and_remote_via_mapping(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_6'] # Insert 2 local assignments for mock_role_7 role_db = create_role(name='mock_role_7') source = 'assignments/user_6_one.yaml' assign_role_to_user(role_db=role_db, user_db=user_db, source=source, is_remote=False) source = 'assignments/user_6_two.yaml' assign_role_to_user(role_db=role_db, user_db=user_db, source=source, is_remote=False) # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_role_7" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_7'], source='mappings/stormers.yaml') # Create mock mapping which maps CN=testers,OU=groups,DC=stackstorm,DC=net # to "mock_role_7" create_group_to_role_map(group='CN=testers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_7'], source='mappings/testers.yaml') groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] result = syncer.sync(user_db=self.users['user_6'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_role_7') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_role_7') self.assertEqual(removed_role_assignment_dbs, []) # There should be one role and 4 assignments for the same role role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 1) self.assertEqual(role_dbs[0].name, 'mock_role_7') role_assignment_dbs = get_role_assignments_for_user(user_db=self.users['user_6']) self.assertEqual(len(role_assignment_dbs), 4) self.assertEqual(role_assignment_dbs[0].source, 'assignments/user_6_one.yaml') self.assertEqual(role_assignment_dbs[1].source, 'assignments/user_6_two.yaml') self.assertEqual(role_assignment_dbs[2].source, 'mappings/stormers.yaml') self.assertEqual(role_assignment_dbs[3].source, 'mappings/testers.yaml') # Remove one remote group - should be 3 left groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net' ] result = syncer.sync(user_db=self.users['user_6'], groups=groups) role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 1) self.assertEqual(role_dbs[0].name, 'mock_role_7') role_assignment_dbs = get_role_assignments_for_user(user_db=self.users['user_6']) self.assertEqual(len(role_assignment_dbs), 3)
def test_sync_no_mappings_exist_for_the_provided_groups(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_role_3" and "mock_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_3', 'mock_role_4']) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) groups = [ 'CN=testers1,OU=groups,DC=stackstorm,DC=net', 'CN=testers2,OU=groups,DC=stackstorm,DC=net' ] # No mappings exist for the groups user is a member of so no new assignments should be # created result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(created_role_assignment_dbs, []) self.assertEqual(removed_role_assignment_dbs, [])
def test_sync_success_no_existing_remote_assignments(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_role_3" and "mock_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_3', 'mock_role_4']) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net', # We repeat the same group to validate that repated groups are correctly de-duplicated 'CN=stormers,OU=groups,DC=stackstorm,DC=net', ] result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_role_4') self.assertEqual(removed_role_assignment_dbs, []) # User should have two new roles assigned now role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_role_4'])
def test_sync_no_mappings_exist_for_the_provided_groups(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and "mock_remote_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3', 'mock_remote_role_4'], source='mappings/stormers.yaml') # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) groups = [ 'CN=testers1,OU=groups,DC=stackstorm,DC=net', 'CN=testers2,OU=groups,DC=stackstorm,DC=net' ] # No mappings exist for the groups user is a member of so no new assignments should be # created result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(created_role_assignment_dbs, []) self.assertEqual(removed_role_assignment_dbs, [])
def test_sync_success_one_existing_remote_assignment(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and "mock_remote_role_4" create_group_to_role_map( group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3', 'mock_remote_role_4'], source='mappings/stormers.yaml') # Assign existing remote mock_role_5 to the user role_db = self.roles['mock_role_5'] source = 'mappings/stormers.yaml' assign_role_to_user(role_db=role_db, user_db=user_db, source=source, is_remote=True) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 3) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_role_5']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_remote_role_4') self.assertEqual(len(removed_role_assignment_dbs), 1) self.assertEqual(removed_role_assignment_dbs[0].role, 'mock_role_5') # User should have two new roles assigned now, but the existing "mock_role_5" remote role # removed since it wasn't specified in any mapping role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_remote_role_4'])
def test_sync_success_one_existing_remote_assignment(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and "mock_remote_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3', 'mock_remote_role_4'], source='mappings/stormers.yaml') # Assign existing remote mock_role_5 to the user role_db = self.roles['mock_role_5'] source = 'mappings/stormers.yaml' assign_role_to_user(role_db=role_db, user_db=user_db, source=source, is_remote=True) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 3) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_role_5']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_remote_role_4') self.assertEqual(len(removed_role_assignment_dbs), 1) self.assertEqual(removed_role_assignment_dbs[0].role, 'mock_role_5') # User should have two new roles assigned now, but the existing "mock_role_5" remote role # removed since it wasn't specified in any mapping role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_remote_role_4'])
def test_sync_success_no_existing_remote_assignments(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and "mock_remote_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3', 'mock_remote_role_4'], source='mappings/stormers.yaml') # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) role_assignment_dbs = get_role_assignments_for_user(user_db=self.users['user_1']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net', # We repeat the same group to validate that repated groups are correctly de-duplicated 'CN=stormers,OU=groups,DC=stackstorm,DC=net', ] result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_remote_role_4') self.assertEqual(removed_role_assignment_dbs, []) # User should have two new roles assigned now role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_remote_role_4']) role_assignment_dbs = get_role_assignments_for_user(user_db=self.users['user_1']) self.assertEqual(len(role_assignment_dbs), 4) self.assertEqual(role_assignment_dbs[2].source, 'mappings/stormers.yaml') self.assertEqual(role_assignment_dbs[3].source, 'mappings/stormers.yaml')
def handle_auth(self, request, headers=None, remote_addr=None, remote_user=None, authorization=None, **kwargs): auth_backend = self._auth_backend.__class__.__name__ extra = {'auth_backend': auth_backend, 'remote_addr': remote_addr} if not authorization: LOG.audit('Authorization header not provided', extra=extra) abort_request() return auth_type, auth_value = authorization if auth_type.lower() not in ['basic']: extra['auth_type'] = auth_type LOG.audit('Unsupported authorization type: %s' % (auth_type), extra=extra) abort_request() return try: auth_value = base64.b64decode(auth_value) except Exception: LOG.audit('Invalid authorization header', extra=extra) abort_request() return split = auth_value.split(':', 1) if len(split) != 2: LOG.audit('Invalid authorization header', extra=extra) abort_request() return username, password = split result = self._auth_backend.authenticate(username=username, password=password) if result is True: ttl = getattr(request, 'ttl', None) username = self._get_username_for_request(username, request) try: token = self._create_token_for_user(username=username, ttl=ttl) except TTLTooLargeException as e: abort_request(status_code=http_client.BAD_REQUEST, message=e.message) return # If remote group sync is enabled, sync the remote groups with local StackStorm roles if cfg.CONF.rbac.sync_remote_groups: LOG.debug('Retrieving auth backend groups for user "%s"' % (username), extra=extra) try: user_groups = self._auth_backend.get_user_groups( username=username) except NotImplementedError: LOG.debug( 'Configured auth backend doesn\'t expose user group membership ' 'information, skipping sync...') return token if not user_groups: # No groups, return early return token extra['username'] = username extra['user_groups'] = user_groups LOG.debug('Found "%s" groups for user "%s"' % (len(user_groups), username), extra=extra) user_db = UserDB(name=username) syncer = RBACRemoteGroupToRoleSyncer() try: syncer.sync(user_db=user_db, groups=user_groups) except Exception as e: # Note: Failed sync is not fatal LOG.exception( 'Failed to synchronize remote groups for user "%s"' % (username), extra=extra) else: LOG.debug('Successfuly synchronized groups for user "%s"' % (username), extra=extra) return token return token LOG.audit('Invalid credentials provided', extra=extra) abort_request()
def test_sync_success_one_mapping_is_disabled_on_second_sync_run(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_role_3" and CN=testers,OU=groups,DC=stackstorm,DC=net to "mock_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_3'], enabled=True) create_group_to_role_map(group='CN=testers,OU=groups,DC=stackstorm,DC=net', roles=['mock_role_4'], enabled=True) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] # Two new remote assignments should have been created # No mappings exist for the groups user is a member of so no new assignments should be # created result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_role_4') self.assertEqual(removed_role_assignment_dbs, []) # Verify post sync run state - two new assignments should have been created role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_role_4']) # Disable second mapping - one assignment should be removed mapping_db = GroupToRoleMapping.get(group='CN=testers,OU=groups,DC=stackstorm,DC=net') mapping_db.enabled = False GroupToRoleMapping.add_or_update(mapping_db) result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 1) self.assertEqual(len(removed_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_role_3') self.assertEqual(removed_role_assignment_dbs[0].role, 'mock_role_3') self.assertEqual(removed_role_assignment_dbs[1].role, 'mock_role_4') # Verify post sync run state - mock_role_4 assignment should be removed role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 3) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_role_3'])
def test_no_mappings_in_db_old_mappings_are_deleted(self): # Test case which verifies that existing / old mappings are deleted from db if no mappings # exist on disk for a particular set of groups. syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and CN=testers,OU=groups,DC=stackstorm,DC=net to # "mock_remote_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3'], source='mappings/stormers.yaml', enabled=True) create_group_to_role_map(group='CN=testers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_4'], source='mappings/testers.yaml', enabled=True) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] # Two new remote assignments should have been created # No mappings exist for the groups user is a member of so no new assignments should be # created result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_remote_role_4') self.assertEqual(removed_role_assignment_dbs, []) # Verify post sync run state - two new assignments should have been created role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_remote_role_4']) # Delete all existing mappings, make sure all old assignments are deleted on sync GroupToRoleMapping.query(group__in=groups).delete() self.assertEqual(len(GroupToRoleMapping.query(group__in=groups)), 0) result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(created_role_assignment_dbs, []) self.assertEqual(len(removed_role_assignment_dbs), 2) self.assertEqual(removed_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(removed_role_assignment_dbs[1].role, 'mock_remote_role_4') # Verify post sync run state - two old remote assignments should have been deleted, but # local assignments shouldn't have been touched role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2'])
def test_sync_success_one_mapping_is_disabled_on_second_sync_run(self): syncer = RBACRemoteGroupToRoleSyncer() user_db = self.users['user_1'] # Create mock mapping which maps CN=stormers,OU=groups,DC=stackstorm,DC=net # to "mock_remote_role_3" and CN=testers,OU=groups,DC=stackstorm,DC=net to # "mock_remote_role_4" create_group_to_role_map(group='CN=stormers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_3'], source='mappings/stormers.yaml', enabled=True) create_group_to_role_map(group='CN=testers,OU=groups,DC=stackstorm,DC=net', roles=['mock_remote_role_4'], source='mappings/testers.yaml', enabled=True) # Verify initial state role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 2) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) groups = [ 'CN=stormers,OU=groups,DC=stackstorm,DC=net', 'CN=testers,OU=groups,DC=stackstorm,DC=net' ] # Two new remote assignments should have been created # No mappings exist for the groups user is a member of so no new assignments should be # created result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(created_role_assignment_dbs[1].role, 'mock_remote_role_4') self.assertEqual(removed_role_assignment_dbs, []) # Verify post sync run state - two new assignments should have been created role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 4) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3']) self.assertEqual(role_dbs[3], self.roles['mock_remote_role_4']) # Disable second mapping - one assignment should be removed mapping_db = GroupToRoleMapping.get(group='CN=testers,OU=groups,DC=stackstorm,DC=net') mapping_db.enabled = False GroupToRoleMapping.add_or_update(mapping_db) result = syncer.sync(user_db=self.users['user_1'], groups=groups) created_role_assignment_dbs = result[0] removed_role_assignment_dbs = result[1] self.assertEqual(len(created_role_assignment_dbs), 1) self.assertEqual(len(removed_role_assignment_dbs), 2) self.assertEqual(created_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(removed_role_assignment_dbs[0].role, 'mock_remote_role_3') self.assertEqual(removed_role_assignment_dbs[1].role, 'mock_remote_role_4') # Verify post sync run state - mock_remote_role_4 assignment should be removed role_dbs = get_roles_for_user(user_db=user_db, include_remote=True) self.assertEqual(len(role_dbs), 3) self.assertEqual(role_dbs[0], self.roles['mock_local_role_1']) self.assertEqual(role_dbs[1], self.roles['mock_local_role_2']) self.assertEqual(role_dbs[2], self.roles['mock_remote_role_3'])
def handle_auth(self, request, headers=None, remote_addr=None, remote_user=None, authorization=None, **kwargs): auth_backend = self._auth_backend.__class__.__name__ extra = {'auth_backend': auth_backend, 'remote_addr': remote_addr} if not authorization: LOG.audit('Authorization header not provided', extra=extra) abort_request() return auth_type, auth_value = authorization if auth_type.lower() not in ['basic']: extra['auth_type'] = auth_type LOG.audit('Unsupported authorization type: %s' % (auth_type), extra=extra) abort_request() return try: auth_value = base64.b64decode(auth_value) except Exception: LOG.audit('Invalid authorization header', extra=extra) abort_request() return split = auth_value.split(b':', 1) if len(split) != 2: LOG.audit('Invalid authorization header', extra=extra) abort_request() return username, password = split if six.PY3 and isinstance(username, six.binary_type): username = username.decode('utf-8') if six.PY3 and isinstance(password, six.binary_type): password = password.decode('utf-8') result = self._auth_backend.authenticate(username=username, password=password) if result is True: ttl = getattr(request, 'ttl', None) username = self._get_username_for_request(username, request) try: token = self._create_token_for_user(username=username, ttl=ttl) except TTLTooLargeException as e: abort_request(status_code=http_client.BAD_REQUEST, message=six.text_type(e)) return # If remote group sync is enabled, sync the remote groups with local StackStorm roles if cfg.CONF.rbac.sync_remote_groups: LOG.debug('Retrieving auth backend groups for user "%s"' % (username), extra=extra) try: user_groups = self._auth_backend.get_user_groups(username=username) except (NotImplementedError, AttributeError): LOG.debug('Configured auth backend doesn\'t expose user group membership ' 'information, skipping sync...') return token if not user_groups: # No groups, return early return token extra['username'] = username extra['user_groups'] = user_groups LOG.debug('Found "%s" groups for user "%s"' % (len(user_groups), username), extra=extra) user_db = UserDB(name=username) syncer = RBACRemoteGroupToRoleSyncer() try: syncer.sync(user_db=user_db, groups=user_groups) except Exception as e: # Note: Failed sync is not fatal LOG.exception('Failed to synchronize remote groups for user "%s"' % (username), extra=extra) else: LOG.debug('Successfully synchronized groups for user "%s"' % (username), extra=extra) return token return token LOG.audit('Invalid credentials provided', extra=extra) abort_request()