Example #1
0
    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, [])
Example #2
0
    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'])
Example #3
0
    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'])
Example #4
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 = 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)
Example #5
0
    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, [])
Example #6
0
    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'])
Example #7
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"
        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'])
Example #8
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"
        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'])
Example #9
0
    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')
Example #10
0
    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()
Example #11
0
    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'])
Example #12
0
    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'])
Example #13
0
    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'])
Example #14
0
    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()