Skip to content

Commit

Permalink
[ML] Transforms: Align privileges checks with ML plugin. (#112970) (#…
Browse files Browse the repository at this point in the history
…113115)

To check the available node count, the ML plugin has an additional privileges check before returning the result. This PR uses the same approach for the corresponding transforms node endpoint.

Co-authored-by: Walter Rafelsberger <walter@elastic.co>
  • Loading branch information
kibanamachine and walterra authored Sep 27, 2021
1 parent c24d285 commit ac14197
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 1 deletion.
3 changes: 3 additions & 0 deletions x-pack/plugins/transform/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export const APP_CLUSTER_PRIVILEGES = [
'cluster:admin/transform/stop',
];

// Minimum privileges required to return transform node count
export const NODES_INFO_PRIVILEGES = ['cluster:monitor/transform/get'];

// Equivalent of capabilities.canGetTransform
export const APP_GET_TRANSFORM_CLUSTER_PRIVILEGES = [
'cluster.cluster:monitor/transform/get',
Expand Down
19 changes: 19 additions & 0 deletions x-pack/plugins/transform/server/routes/api/transforms_nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
* 2.0.
*/

import Boom from '@hapi/boom';

import { NODES_INFO_PRIVILEGES } from '../../../common/constants';
import { isPopulatedObject } from '../../../common/shared_imports';

import { RouteDependencies } from '../../types';
Expand Down Expand Up @@ -44,6 +47,22 @@ export function registerTransformNodesRoutes({ router, license }: RouteDependenc
},
license.guardApiRoute<undefined, undefined, undefined>(async (ctx, req, res) => {
try {
// If security is enabled, check that the user has at least permission to
// view transforms before calling the _nodes endpoint with the internal user.
if (license.getStatus().isSecurityEnabled === true) {
const {
body: { has_all_requested: hasAllPrivileges },
} = await ctx.core.elasticsearch.client.asCurrentUser.security.hasPrivileges({
body: {
cluster: NODES_INFO_PRIVILEGES,
},
});

if (!hasAllPrivileges) {
return res.customError(wrapError(new Boom.Boom('Forbidden', { statusCode: 403 })));
}
}

const {
body: { nodes },
} = await ctx.core.elasticsearch.client.asInternalUser.nodes.info({
Expand Down
28 changes: 27 additions & 1 deletion x-pack/test/api_integration/apis/transform/transforms_nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default ({ getService }: FtrProviderContext) => {
}

describe('/api/transform/transforms/_nodes', function () {
it('should return the number of available transform nodes', async () => {
it('should return the number of available transform nodes for a power user', async () => {
const { body } = await supertest
.get('/api/transform/transforms/_nodes')
.auth(
Expand All @@ -44,5 +44,31 @@ export default ({ getService }: FtrProviderContext) => {

assertTransformsNodesResponseBody(body);
});

it('should return the number of available transform nodes for a viewer user', async () => {
const { body } = await supertest
.get('/api/transform/transforms/_nodes')
.auth(
USER.TRANSFORM_VIEWER,
transform.securityCommon.getPasswordForUser(USER.TRANSFORM_VIEWER)
)
.set(COMMON_REQUEST_HEADERS)
.send()
.expect(200);

assertTransformsNodesResponseBody(body);
});

it('should not return the number of available transform nodes for an unauthorized user', async () => {
await supertest
.get('/api/transform/transforms/_nodes')
.auth(
USER.TRANSFORM_UNAUTHORIZED,
transform.securityCommon.getPasswordForUser(USER.TRANSFORM_UNAUTHORIZED)
)
.set(COMMON_REQUEST_HEADERS)
.send()
.expect(403);
});
});
};
7 changes: 7 additions & 0 deletions x-pack/test/functional/services/transform/security_common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type TransformSecurityCommon = ProvidedType<typeof TransformSecurityCommo
export enum USER {
TRANSFORM_POWERUSER = 'transform_poweruser',
TRANSFORM_VIEWER = 'transform_viewer',
TRANSFORM_UNAUTHORIZED = 'transform_unauthorized',
}

export function TransformSecurityCommonProvider({ getService }: FtrProviderContext) {
Expand Down Expand Up @@ -69,6 +70,12 @@ export function TransformSecurityCommonProvider({ getService }: FtrProviderConte
password: 'tfv001',
roles: ['kibana_admin', 'transform_user', 'transform_dest_readonly'],
},
{
name: 'transform_unauthorized',
full_name: 'Transform Unauthorized',
password: 'tfu001',
roles: ['kibana_admin'],
},
];

return {
Expand Down

0 comments on commit ac14197

Please sign in to comment.