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 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"
        rbac_service.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 = rbac_service.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"
        rbac_service.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'
        rbac_service.assign_role_to_user(role_db=role_db,
                                         user_db=user_db,
                                         source=source,
                                         is_remote=True)

        # Verify initial state
        role_dbs = rbac_service.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 = rbac_service.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"
        rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.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')
Exemple #5
0
    def test_group_to_role_sync_is_performed_on_successful_auth_with_groups_and_mappings(
            self):
        # Enable group sync
        cfg.CONF.set_override(group='rbac',
                              name='sync_remote_groups',
                              override=True)

        user_db = self.users['user_1']
        h = handlers.StandaloneAuthHandler()
        request = {}

        # Single mapping, new remote assignment should be created
        rbac_service.create_group_to_role_map(
            group='CN=stormers,OU=groups,DC=stackstorm,DC=net',
            roles=['mock_role_3', 'mock_role_4'],
            source='mappings/stormers.yaml')

        # Verify initial state
        role_dbs = rbac_service.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'])

        h._auth_backend.groups = ['CN=stormers,OU=groups,DC=stackstorm,DC=net']

        token = h.handle_auth(request,
                              headers={},
                              remote_addr=None,
                              remote_user=None,
                              authorization=('basic', DUMMY_CREDS))
        self.assertEqual(token.user, 'auser')

        # Verify a new role assignments based on the group mapping has been created
        role_dbs = rbac_service.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_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"
        rbac_service.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)

        rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.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 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 = rbac_service.create_role(name='mock_role_7')

        source = 'assignments/user_6_one.yaml'
        rbac_service.assign_role_to_user(role_db=role_db,
                                         user_db=user_db,
                                         source=source,
                                         is_remote=False)

        source = 'assignments/user_6_two.yaml'
        rbac_service.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"
        rbac_service.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"
        rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_6'])
        self.assertEqual(len(role_assignment_dbs), 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"
        rbac_service.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)

        rbac_service.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 = rbac_service.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 = rbac_service.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 = rbac_service.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'])