Skip to content

Commit

Permalink
[Spaces] Excluded roles with reserved only privileges (elastic#192041)
Browse files Browse the repository at this point in the history
## Summary

Excluded roles with reserved only privileges
`/internal/security/roles/{spaceId}` route. `_reserved` privileges are
legacy, and they do not grant access to spaces directly, but rather rely
on other roles to grant that access in order to function.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios


__Fixes: https://github.com/elastic/kibana/issues/191996__

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
elena-shostak and elasticmachine authored Sep 6, 2024
1 parent c6dce58 commit ab1646f
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -320,5 +320,81 @@ describe('GET all roles by space id', () => {
],
},
});

getRolesTest(`filters roles with reserved only privileges`, {
apiResponse: () => ({
first_role: {
description: 'first role description',
cluster: [],
indices: [],
applications: [],
run_as: [],
metadata: {
_reserved: true,
},
transient_metadata: {
enabled: true,
},
},
second_role: {
cluster: [],
indices: [],
applications: [
{
application,
privileges: ['space_all', 'space_read'],
resources: ['space:marketing', 'space:sales'],
},
],
run_as: [],
metadata: {
_reserved: true,
},
transient_metadata: {
enabled: true,
},
},
third_role: {
cluster: [],
indices: [],
applications: [],
run_as: [],
transient_metadata: {
enabled: true,
},
},
}),
spaceId: 'marketing',
asserts: {
statusCode: 200,
result: [
{
_transform_error: [],
_unrecognized_applications: [],
elasticsearch: {
cluster: [],
indices: [],
remote_cluster: undefined,
remote_indices: undefined,
run_as: [],
},
kibana: [
{
base: ['all', 'read'],
feature: {},
spaces: ['marketing', 'sales'],
},
],
metadata: {
_reserved: true,
},
name: 'second_role',
transient_metadata: {
enabled: true,
},
},
],
},
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { schema } from '@kbn/config-schema';

import type { RouteDefinitionParams } from '../..';
import type { Role } from '../../../../common';
import { ALL_SPACES_ID } from '../../../../common/constants';
import { compareRolesByName, transformElasticsearchRoleToRole } from '../../../authorization';
import { wrapIntoCustomErrorResponse } from '../../../errors';
Expand Down Expand Up @@ -43,25 +44,42 @@ export function defineGetAllRolesBySpaceRoutes({
// Transform elasticsearch roles into Kibana roles and return in a list sorted by the role name.
return response.ok({
body: Object.entries(elasticsearchRoles)
.map(([roleName, elasticsearchRole]) =>
transformElasticsearchRoleToRole(
.reduce<Role[]>((acc, [roleName, elasticsearchRole]) => {
if (hideReservedRoles && elasticsearchRole.metadata?._reserved) {
return acc;
}

const role = transformElasticsearchRoleToRole(
features,
// @ts-expect-error @elastic/elasticsearch SecurityIndicesPrivileges.names expected to be string[]
elasticsearchRole,
roleName,
authz.applicationName,
logger
)
)
.filter(
(role) =>
!(hideReservedRoles && role.metadata?._reserved) &&
role.kibana.some(
(privilege) =>
privilege.spaces.includes(request.params.spaceId) ||
privilege.spaces.includes(ALL_SPACES_ID)
)
)
);

const includeRoleForSpace = role.kibana.some((privilege) => {
const privilegeInSpace =
privilege.spaces.includes(request.params.spaceId) ||
privilege.spaces.includes(ALL_SPACES_ID);

if (privilegeInSpace && privilege.base.length) {
return true;
}

const hasFeaturePrivilege = Object.values(privilege.feature).some(
(featureList) => featureList.length
);

return privilegeInSpace && hasFeaturePrivilege;
});

if (includeRoleForSpace) {
acc.push(role);
}

return acc;
}, [])
.sort(compareRolesByName),
});
} catch (error) {
Expand Down

0 comments on commit ab1646f

Please sign in to comment.