def test_assign_role_to_user_ignore_already_exists_error(self):
        user_db = UserDB(name='test-user-10')
        user_db = User.add_or_update(user_db)

        role_assignment_db_1 = rbac_service.assign_role_to_user(
            role_db=self.roles['custom_role_1'],
            user_db=user_db,
            source='assignments/%s_10.yaml' % user_db.name)

        # 1. Without ignore errors
        self.assertRaises(StackStormDBObjectConflictError,
                          rbac_service.assign_role_to_user,
                          role_db=self.roles['custom_role_1'],
                          user_db=user_db,
                          source='assignments/%s_10.yaml' % user_db.name)

        # 2. With ignore errors
        role_assignment_db_2 = rbac_service.assign_role_to_user(
            role_db=self.roles['custom_role_1'],
            user_db=user_db,
            source='assignments/%s_10.yaml' % user_db.name,
            ignore_already_exists_error=True)

        self.assertEqual(role_assignment_db_1, role_assignment_db_2)
        self.assertEqual(role_assignment_db_1.id, role_assignment_db_2.id)
        self.assertEqual(role_assignment_db_1.user, role_assignment_db_2.user)
        self.assertEqual(role_assignment_db_1.role, role_assignment_db_2.role)
Exemplo n.º 2
0
    def setUp(self):
        super(RBACRemoteGroupToRoleSyncerTestCase, self).setUp()

        self.roles = {}
        self.role_assignments = {}

        # Insert mock local role assignments
        role_db = rbac_service.create_role(name='mock_local_role_1')
        user_db = self.users['user_1']
        source = 'assignments/%s.yaml' % user_db.name
        role_assignment_db_1 = rbac_service.assign_role_to_user(
            role_db=role_db, user_db=user_db, source=source, is_remote=False)

        self.roles['mock_local_role_1'] = role_db
        self.role_assignments['assignment_1'] = role_assignment_db_1

        role_db = rbac_service.create_role(name='mock_local_role_2')
        user_db = self.users['user_1']
        source = 'assignments/%s.yaml' % user_db.name
        role_assignment_db_2 = rbac_service.assign_role_to_user(
            role_db=role_db, user_db=user_db, source=source, is_remote=False)

        self.roles['mock_local_role_2'] = role_db
        self.role_assignments['assignment_2'] = role_assignment_db_2

        role_db = rbac_service.create_role(name='mock_remote_role_3')
        self.roles['mock_remote_role_3'] = role_db

        role_db = rbac_service.create_role(name='mock_remote_role_4')
        self.roles['mock_remote_role_4'] = role_db

        role_db = rbac_service.create_role(name='mock_role_5')
        self.roles['mock_role_5'] = role_db
    def test_grant_and_revoke_role(self):
        user_db = UserDB(name='test-user-1')
        user_db = User.add_or_update(user_db)

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

        role_dbs = user_db.get_roles()
        self.assertItemsEqual(role_dbs, [])

        # Assign a role, should have one role assigned
        rbac_service.assign_role_to_user(role_db=self.roles['custom_role_1'],
                                         user_db=user_db,
                                         source='assignments/%s.yaml' %
                                         user_db.name)

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [self.roles['custom_role_1']])

        role_dbs = user_db.get_roles()
        self.assertItemsEqual(role_dbs, [self.roles['custom_role_1']])

        # Revoke previously assigned role, should have no roles again
        rbac_service.revoke_role_from_user(role_db=self.roles['custom_role_1'],
                                           user_db=user_db)

        role_dbs = rbac_service.get_roles_for_user(user_db=user_db)
        self.assertItemsEqual(role_dbs, [])
        role_dbs = user_db.get_roles()
        self.assertItemsEqual(role_dbs, [])
Exemplo n.º 4
0
    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'])
Exemplo n.º 5
0
    def setUp(self):
        super(AuthHandlerRBACRoleSyncTestCase, self).setUp()

        cfg.CONF.set_override(group='auth', name='backend', override='mock')
        cfg.CONF.set_override(group='rbac',
                              name='backend',
                              override='enterprise')

        self.users = {}
        self.roles = {}
        self.role_assignments = {}

        # Insert some mock users
        user_1_db = UserDB(name='auser')
        user_1_db = User.add_or_update(user_1_db)
        self.users['user_1'] = user_1_db

        user_2_db = UserDB(name='buser')
        user_2_db = User.add_or_update(user_2_db)
        self.users['user_2'] = user_2_db

        # Insert mock local role assignments
        role_db = rbac_service.create_role(name='mock_local_role_1')
        user_db = self.users['user_1']
        source = 'assignments/%s.yaml' % user_db.name
        role_assignment_db_1 = rbac_service.assign_role_to_user(
            role_db=role_db, user_db=user_db, source=source, is_remote=False)

        self.roles['mock_local_role_1'] = role_db
        self.role_assignments['assignment_1'] = role_assignment_db_1

        role_db = rbac_service.create_role(name='mock_local_role_2')
        user_db = self.users['user_1']
        source = 'assignments/%s.yaml' % user_db.name
        role_assignment_db_2 = rbac_service.assign_role_to_user(
            role_db=role_db, user_db=user_db, source=source, is_remote=False)

        self.roles['mock_local_role_2'] = role_db
        self.role_assignments['assignment_2'] = role_assignment_db_2

        role_db = rbac_service.create_role(name='mock_role_3')
        self.roles['mock_role_3'] = role_db

        role_db = rbac_service.create_role(name='mock_role_4')
        self.roles['mock_role_4'] = role_db

        role_db = rbac_service.create_role(name='mock_role_5')
        self.roles['mock_role_5'] = role_db
Exemplo n.º 6
0
    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'])
Exemplo n.º 7
0
    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_service.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_service.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)
Exemplo n.º 8
0
    def _sync_user_role_assignments(self, user_db, role_assignment_dbs, role_assignment_apis):
        """
        Synchronize role assignments for a particular user.

        :param user_db: User to synchronize the assignments for.
        :type user_db: :class:`UserDB`

        :param role_assignment_dbs: Existing user role assignments.
        :type role_assignment_dbs: ``list`` of :class:`UserRoleAssignmentDB`

        :param role_assignment_apis: List of user role assignments to apply.
        :param role_assignment_apis: ``list`` of :class:`UserRoleAssignmentFileFormatAPI`

        :rtype: ``tuple``
        """
        db_roles = set([(entry.role, entry.source) for entry in role_assignment_dbs])

        api_roles = [
            list(izip_longest(entry.roles, [], fillvalue=entry.file_path))
            for entry in role_assignment_apis
        ]

        api_roles = set(list(chain.from_iterable(api_roles)))

        # A list of new assignments which should be added to the database
        new_roles = api_roles.difference(db_roles)

        # A list of assignments which need to be updated in the database
        updated_roles = db_roles.intersection(api_roles)

        # A list of assignments which should be removed from the database
        removed_roles = (db_roles - api_roles)

        LOG.debug('New assignments for user "%s": %r' % (user_db.name, new_roles))
        LOG.debug('Updated assignments for user "%s": %r' % (user_db.name, updated_roles))
        LOG.debug('Removed assignments for user "%s": %r' % (user_db.name, removed_roles))

        # Build a list of role assignments to delete
        roles_to_delete = updated_roles.union(removed_roles)

        role_assignment_dbs_to_delete = [
            role_assignment_db for role_assignment_db in role_assignment_dbs
            if (role_assignment_db.role, role_assignment_db.source) in roles_to_delete
        ]

        for role_name, assignment_source in roles_to_delete:
            queryset_filter = (
                Q(user=user_db.name) &
                Q(role=role_name) &
                Q(source=assignment_source) &
                (Q(is_remote=False) | Q(is_remote__exists=False))
            )

            UserRoleAssignmentDB.objects(queryset_filter).delete()

            LOG.debug('Removed role "%s" from "%s" for user "%s".' % (role_name, assignment_source,
                                                                      user_db.name))

        # Build a list of roles assignments to create
        roles_to_create = new_roles.union(updated_roles)
        created_role_assignment_dbs = []

        for role_name, assignment_source in roles_to_create:
            role_db = Role.get(name=role_name)
            if not role_db:
                msg = 'Role "%s" referenced in assignment file "%s" doesn\'t exist'
                raise ValueError(msg % (role_name, assignment_source))

            role_assignment_api = [r for r in role_assignment_apis if
                                   r.file_path == assignment_source][0]
            description = getattr(role_assignment_api, 'description', None)

            assignment_db = rbac_service.assign_role_to_user(
                role_db=role_db, user_db=user_db, source=assignment_source, description=description)

            created_role_assignment_dbs.append(assignment_db)

            LOG.debug('Assigned role "%s" from "%s" for user "%s".' %
                (role_name, assignment_source, user_db.name))

        return (created_role_assignment_dbs, role_assignment_dbs_to_delete)
Exemplo n.º 9
0
    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)