def sync_group_to_role_maps(self, group_to_role_map_apis): LOG.info("Synchronizing group to role maps...") # Retrieve all the mappings currently in the db group_to_role_map_dbs = rbac_service.get_all_group_to_role_maps() # 1. Delete all the existing mappings in the db group_to_role_map_to_delete = [] for group_to_role_map_db in group_to_role_map_dbs: group_to_role_map_to_delete.append(group_to_role_map_db.id) GroupToRoleMapping.query(id__in=group_to_role_map_to_delete).delete() # 2. Insert all mappings read from disk for group_to_role_map_api in group_to_role_map_apis: source = getattr(group_to_role_map_api, "file_path", None) rbac_service.create_group_to_role_map( group=group_to_role_map_api.group, roles=group_to_role_map_api.roles, description=group_to_role_map_api.description, enabled=group_to_role_map_api.enabled, source=source, ) LOG.info("Group to role map definitions synchronized.")
def sync_group_to_role_maps(self, group_to_role_map_apis): LOG.info('Synchronizing group to role maps...') # Retrieve all the mappings currently in the db group_to_role_map_dbs = rbac_services.get_all_group_to_role_maps() # 1. Delete all the existing mappings in the db group_to_role_map_to_delete = [] for group_to_role_map_db in group_to_role_map_dbs: group_to_role_map_to_delete.append(group_to_role_map_db.id) GroupToRoleMapping.query(id__in=group_to_role_map_to_delete).delete() # 2. Insert all mappings read from disk for group_to_role_map_api in group_to_role_map_apis: source = getattr(group_to_role_map_api, 'file_path', None) rbac_services.create_group_to_role_map(group=group_to_role_map_api.group, roles=group_to_role_map_api.roles, description=group_to_role_map_api.description, enabled=group_to_role_map_api.enabled, source=source) LOG.info('Group to role map definitions synchronized.')
def sync(self, user_db, groups): """ :param user_db: User to sync the assignments for. :type user: :class:`UserDB` :param groups: A list of remote groups user is a member of. :type groups: ``list`` of ``str`` :return: A list of mappings which have been created. :rtype: ``list`` of :class:`UserRoleAssignmentDB` """ groups = list(set(groups)) extra = {'user_db': user_db, 'groups': groups} LOG.info('Synchronizing remote role assignments for user "%s"' % (str(user_db)), extra=extra) # 1. Retrieve group to role mappings for the provided groups all_mapping_dbs = GroupToRoleMapping.query(group__in=groups) enabled_mapping_dbs = [ mapping_db for mapping_db in all_mapping_dbs if mapping_db.enabled ] disabled_mapping_dbs = [ mapping_db for mapping_db in all_mapping_dbs if not mapping_db.enabled ] if not all_mapping_dbs: LOG.debug('No group to role mappings found for user "%s"' % (str(user_db)), extra=extra) # 2. Remove all the existing remote role assignments remote_assignment_dbs = UserRoleAssignment.query(user=user_db.name, is_remote=True) existing_role_names = [ assignment_db.role for assignment_db in remote_assignment_dbs ] existing_role_names = set(existing_role_names) current_role_names = set([]) for mapping_db in all_mapping_dbs: for role in mapping_db.roles: current_role_names.add(role) # A list of new role assignments which should be added to the database new_role_names = current_role_names.difference(existing_role_names) # A list of role assignments which need to be updated in the database updated_role_names = existing_role_names.intersection( current_role_names) # A list of role assignments which should be removed from the database removed_role_names = (existing_role_names - new_role_names) # Also remove any assignments for mappings which are disabled in the database for mapping_db in disabled_mapping_dbs: for role in mapping_db.roles: removed_role_names.add(role) LOG.debug('New role assignments: %r' % (new_role_names)) LOG.debug('Updated role assignments: %r' % (updated_role_names)) LOG.debug('Removed role assignments: %r' % (removed_role_names)) # Build a list of role assignments to delete role_names_to_delete = updated_role_names.union(removed_role_names) role_assignment_dbs_to_delete = [ role_assignment_db for role_assignment_db in remote_assignment_dbs if role_assignment_db.role in role_names_to_delete ] UserRoleAssignment.query(user=user_db.name, role__in=role_names_to_delete, is_remote=True).delete() # 3. Create role assignments for all the current groups created_assignments_dbs = [] for mapping_db in enabled_mapping_dbs: extra['mapping_db'] = mapping_db for role_name in mapping_db.roles: role_db = rbac_services.get_role_by_name(name=role_name) if not role_db: # Gracefully skip assignment for role which doesn't exist in the db LOG.info( 'Role with name "%s" for mapping "%s" not found, skipping assignment.' % (role_name, str(mapping_db)), extra=extra) continue description = ( 'Automatic role assignment based on the remote user membership in ' 'group "%s"' % (mapping_db.group)) assignment_db = rbac_services.assign_role_to_user( role_db=role_db, user_db=user_db, description=description, is_remote=True, source=mapping_db.source, ignore_already_exists_error=True) assert assignment_db.is_remote is True created_assignments_dbs.append(assignment_db) LOG.debug('Created %s new remote role assignments for user "%s"' % (len(created_assignments_dbs), str(user_db)), extra=extra) return (created_assignments_dbs, role_assignment_dbs_to_delete)
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_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 sync(self, user_db, groups): """ :param user_db: User to sync the assignments for. :type user: :class:`UserDB` :param groups: A list of remote groups user is a member of. :type groups: ``list`` of ``str`` :return: A list of mappings which have been created. :rtype: ``list`` of :class:`UserRoleAssignmentDB` """ groups = list(set(groups)) extra = {'user_db': user_db, 'groups': groups} LOG.info('Synchronizing remote role assignments for user "%s"' % (str(user_db)), extra=extra) # 1. Retrieve group to role mappings for the provided groups all_mapping_dbs = GroupToRoleMapping.query(group__in=groups) enabled_mapping_dbs = [mapping_db for mapping_db in all_mapping_dbs if mapping_db.enabled] disabled_mapping_dbs = [mapping_db for mapping_db in all_mapping_dbs if not mapping_db.enabled] if not all_mapping_dbs: LOG.debug('No group to role mappings found for user "%s"' % (str(user_db)), extra=extra) # 2. Remove all the existing remote role assignments remote_assignment_dbs = UserRoleAssignment.query(user=user_db.name, is_remote=True) existing_role_names = [assignment_db.role for assignment_db in remote_assignment_dbs] existing_role_names = set(existing_role_names) current_role_names = set([]) for mapping_db in all_mapping_dbs: for role in mapping_db.roles: current_role_names.add(role) # A list of new role assignments which should be added to the database new_role_names = current_role_names.difference(existing_role_names) # A list of role assignments which need to be updated in the database updated_role_names = existing_role_names.intersection(current_role_names) # A list of role assignments which should be removed from the database removed_role_names = (existing_role_names - new_role_names) # Also remove any assignments for mappings which are disabled in the database for mapping_db in disabled_mapping_dbs: for role in mapping_db.roles: removed_role_names.add(role) LOG.debug('New role assignments: %r' % (new_role_names)) LOG.debug('Updated role assignments: %r' % (updated_role_names)) LOG.debug('Removed role assignments: %r' % (removed_role_names)) # Build a list of role assignments to delete role_names_to_delete = updated_role_names.union(removed_role_names) role_assignment_dbs_to_delete = [role_assignment_db for role_assignment_db in remote_assignment_dbs if role_assignment_db.role in role_names_to_delete] UserRoleAssignment.query(user=user_db.name, role__in=role_names_to_delete, is_remote=True).delete() # 3. Create role assignments for all the current groups created_assignments_dbs = [] for mapping_db in enabled_mapping_dbs: extra['mapping_db'] = mapping_db for role_name in mapping_db.roles: role_db = rbac_services.get_role_by_name(name=role_name) if not role_db: # Gracefully skip assignment for role which doesn't exist in the db LOG.info('Role with name "%s" for mapping "%s" not found, skipping assignment.' % (role_name, str(mapping_db)), extra=extra) continue description = ('Automatic role assignment based on the remote user membership in ' 'group "%s"' % (mapping_db.group)) assignment_db = rbac_services.assign_role_to_user(role_db=role_db, user_db=user_db, description=description, is_remote=True, source=mapping_db.source, ignore_already_exists_error=True) assert assignment_db.is_remote is True created_assignments_dbs.append(assignment_db) LOG.debug('Created %s new remote role assignments for user "%s"' % (len(created_assignments_dbs), str(user_db)), extra=extra) return (created_assignments_dbs, role_assignment_dbs_to_delete)