def test_sync_role_assignments_no_assignment_file_on_disk(self):
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, no roles
        user_db = self.users['user_3']
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with two roles defined
        api = UserRoleAssignmentFileFormatAPI(username=user_db.name,
                                              roles=['role_1', 'role_2'],
                                              file_path='assignments/%s.yaml' %
                                              user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 2)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])

        # Do the sync with no roles - existing assignments should be removed from the databse
        syncer.sync_users_role_assignments(role_assignment_apis=[])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 0)
    def test_sync_assignments_user_doesnt_exist_in_db(self):
        # Make sure that the assignments for the users which don't exist in the db are still saved
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        username = '******'

        # Initial state, no roles
        user_db = UserDB(name=username)
        self.assertEqual(len(User.query(name=username)), 0)
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with two roles defined
        api = UserRoleAssignmentFileFormatAPI(
            username=user_db.name,
            roles=['role_1', 'role_2'],
            file_path='assignments/foobar.yaml')

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 2)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])
    def test_sync_user_assignments_multiple_custom_roles_assignments(self):
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, no roles
        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with two roles defined
        api = UserRoleAssignmentFileFormatAPI(
            username='******',
            roles=['role_1', 'role_2'],
            file_path='assignments/user2.yaml')
        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_dbs), 2)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])
        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_assignment_dbs), 2)
        self.assertEqual(role_assignment_dbs[0].source,
                         'assignments/user2.yaml')
        self.assertEqual(role_assignment_dbs[1].source,
                         'assignments/user2.yaml')
    def test_sync_user_assignments_multiple_sources_same_role_assignment(self):
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, no roles
        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with role defined in separate files
        assignment1 = UserRoleAssignmentFileFormatAPI(
            username='******',
            roles=['role_1'],
            file_path='assignments/user2a.yaml')

        assignment2 = UserRoleAssignmentFileFormatAPI(
            username='******',
            roles=['role_1'],
            file_path='assignments/user2b.yaml')

        syncer.sync_users_role_assignments(
            role_assignment_apis=[assignment1, assignment2])

        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_dbs), 1)
        self.assertEqual(role_dbs[0], self.roles['role_1'])

        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_assignment_dbs), 2)

        sources = [r.source for r in role_assignment_dbs]
        self.assertIn('assignments/user2a.yaml', sources)
        self.assertIn('assignments/user2b.yaml', sources)

        # Do another sync with one assignment file removed - only one assignment should be left
        syncer.sync_users_role_assignments(role_assignment_apis=[assignment2])

        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_dbs), 1)
        self.assertEqual(role_dbs[0], self.roles['role_1'])

        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_assignment_dbs), 1)

        sources = [r.source for r in role_assignment_dbs]
        self.assertIn('assignments/user2b.yaml', sources)
    def test_sync_remote_assignments_are_not_manipulated(self):
        # Verify remote assignments are not manipulated.
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, no roles
        user_db = UserDB(name='doesntexistwhaha')
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])

        # Create mock remote role assignment
        role_db = self.roles['role_3']
        source = 'assignments/%s.yaml' % user_db.name
        role_assignment_db = rbac_service.assign_role_to_user(role_db=role_db,
                                                              user_db=user_db,
                                                              source=source,
                                                              is_remote=True)
        self.assertTrue(role_assignment_db.is_remote)

        # Verify assignment has been created
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [self.roles['role_3']])

        # Do the sync with two roles defined - verify remote role assignment hasn't been
        # manipulated with.
        api = UserRoleAssignmentFileFormatAPI(username=user_db.name,
                                              roles=['role_1', 'role_2'],
                                              file_path='assignments/%s.yaml' %
                                              user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 3)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])
        self.assertEqual(role_dbs[2], self.roles['role_3'])

        # Do sync with no roles - verify all roles except remote one are removed.
        api = UserRoleAssignmentFileFormatAPI(username=user_db.name,
                                              roles=[],
                                              file_path='assignments/%s.yaml' %
                                              user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 1)
        self.assertEqual(role_dbs[0], self.roles['role_3'])
    def test_sync_user_assignments_assignments_without_is_remote_are_deleted(
            self):
        # Test case which verifies roles without "is_remote" field (pre v2.3) are removed from the
        # database
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, 4 roles
        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_5'])
        self.assertEqual(len(role_assignment_dbs), 4)

        # All 3 non remote roles should have been deleted
        syncer.sync_users_role_assignments(role_assignment_apis=[])
        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=self.users['user_5'])
        self.assertEqual(len(role_assignment_dbs), 1)
        self.assertEqual(role_assignment_dbs[0].role, 'role_4')
        self.assertEqual(role_assignment_dbs[0].is_remote, True)
    def test_sync_user_assignments_locally_removed_assignments_are_removed_from_db(
            self):
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        # Initial state, no roles
        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with two roles defined
        api = UserRoleAssignmentFileFormatAPI(
            username='******',
            roles=['role_1', 'role_2'],
            file_path='assignments/user2.yaml')

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_dbs), 2)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])

        # Do the sync with one role defined (one should be removed from the db)
        api = UserRoleAssignmentFileFormatAPI(
            username='******',
            roles=['role_2'],
            file_path='assignments/user2.yaml')

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(
            user_db=self.users['user_2'])
        self.assertEqual(len(role_dbs), 1)
        self.assertEqual(role_dbs[0], self.roles['role_2'])
    def test_sync_assignments_are_removed_user_doesnt_exist_in_db(self):
        # Make sure that the assignments for the users which don't exist in the db are correctly
        # removed
        syncer = RBACDefinitionsDBSyncer()

        self._insert_mock_roles()

        username = '******'

        # Initial state, no roles
        user_db = UserDB(name=username)
        self.assertEqual(len(User.query(name=username)), 0)
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with two roles defined
        api = UserRoleAssignmentFileFormatAPI(username=user_db.name,
                                              roles=['role_1', 'role_2'],
                                              file_path='assignments/%s.yaml' %
                                              user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 2)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])

        # Sync with no roles on disk - existing roles should be removed
        syncer.sync_users_role_assignments(role_assignment_apis=[])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)

        self.assertEqual(len(role_dbs), 0)

        username = '******'

        # Initial state, no roles
        user_db = UserDB(name=username)
        self.assertEqual(len(User.query(name=username)), 0)
        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])

        # Do the sync with three roles defined
        api = UserRoleAssignmentFileFormatAPI(
            username=user_db.name,
            roles=['role_1', 'role_2', 'role_3'],
            file_path='assignments/%s.yaml' % user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 3)
        self.assertEqual(role_dbs[0], self.roles['role_1'])
        self.assertEqual(role_dbs[1], self.roles['role_2'])
        self.assertEqual(role_dbs[2], self.roles['role_3'])
        role_assignment_dbs = rbac_service.get_role_assignments_for_user(
            user_db=user_db)
        self.assertEqual(len(role_assignment_dbs), 3)
        self.assertEqual(role_assignment_dbs[0].source,
                         'assignments/%s.yaml' % user_db.name)

        # Sync with one role on disk - two roles should be removed
        api = UserRoleAssignmentFileFormatAPI(username=user_db.name,
                                              roles=['role_3'],
                                              file_path='assignments/%s.yaml' %
                                              user_db.name)

        syncer.sync_users_role_assignments(role_assignment_apis=[api])

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertEqual(len(role_dbs), 1)
        self.assertEqual(role_dbs[0], self.roles['role_3'])