Skip to content

Commit

Permalink
fix: project tokens can now be created with the correct permissions (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
sighphyre committed Jul 6, 2023
1 parent 63beb0c commit 9778f54
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 6 deletions.
Expand Up @@ -7,6 +7,7 @@ import {
ADMIN,
CREATE_FRONTEND_API_TOKEN,
CREATE_CLIENT_API_TOKEN,
CREATE_PROJECT_API_TOKEN,
} from '@server/types/permissions';
import { useHasRootAccess } from 'hooks/useHasAccess';
import { SelectOption } from './TokenTypeSelector/TokenTypeSelector';
Expand All @@ -17,17 +18,28 @@ export const useApiTokenForm = (project?: string) => {
const { uiConfig } = useUiConfig();
const initialEnvironment = environments?.find(e => e.enabled)?.name;

const hasCreateTokenPermission = useHasRootAccess(CREATE_CLIENT_API_TOKEN);
const hasCreateProjectTokenPermission = useHasRootAccess(
CREATE_PROJECT_API_TOKEN,
project
);

const apiTokenTypes: SelectOption[] = [
{
key: TokenType.CLIENT,
label: `Server-side SDK (${TokenType.CLIENT})`,
title: 'Connect server-side SDK or Unleash Proxy',
enabled: useHasRootAccess(CREATE_CLIENT_API_TOKEN),
enabled:
hasCreateTokenPermission || hasCreateProjectTokenPermission,
},
];

const hasAdminAccess = useHasRootAccess(ADMIN);
const hasCreateFrontendAccess = useHasRootAccess(CREATE_FRONTEND_API_TOKEN);
const hasCreateFrontendTokenAccess = useHasRootAccess(
CREATE_PROJECT_API_TOKEN,
project
);
if (!project) {
apiTokenTypes.push({
key: TokenType.ADMIN,
Expand All @@ -42,7 +54,7 @@ export const useApiTokenForm = (project?: string) => {
key: TokenType.FRONTEND,
label: `Client-side SDK (${TokenType.FRONTEND})`,
title: 'Connect web and mobile SDK directly to Unleash',
enabled: hasCreateFrontendAccess,
enabled: hasCreateFrontendAccess || hasCreateFrontendTokenAccess,
});
}

Expand Down
5 changes: 1 addition & 4 deletions src/lib/routes/admin-api/project/api-token.ts
Expand Up @@ -34,7 +34,6 @@ import { Response } from 'express';
import { timingSafeEqual } from 'crypto';
import { createApiToken } from '../../../schema/api-token-schema';
import { OperationDeniedError } from '../../../error';
import { tokenTypeToCreatePermission } from '../api-token';

interface ProjectTokenParam {
token: string;
Expand Down Expand Up @@ -159,9 +158,7 @@ export class ProjectApiTokenController extends Controller {
): Promise<any> {
const createToken = await createApiToken.validateAsync(req.body);
const { projectId } = req.params;
const permissionRequired = tokenTypeToCreatePermission(
createToken.type,
);
const permissionRequired = CREATE_PROJECT_API_TOKEN;
const hasPermission = await this.accessService.hasPermission(
req.user,
permissionRequired,
Expand Down
55 changes: 55 additions & 0 deletions src/test/e2e/api/admin/api-token.auth.e2e.test.ts
Expand Up @@ -5,6 +5,7 @@ import { ApiTokenType } from '../../../../lib/types/models/api-token';
import { RoleName } from '../../../../lib/types/model';
import {
CREATE_CLIENT_API_TOKEN,
CREATE_PROJECT_API_TOKEN,
DELETE_CLIENT_API_TOKEN,
READ_CLIENT_API_TOKEN,
READ_FRONTEND_API_TOKEN,
Expand Down Expand Up @@ -171,6 +172,60 @@ test('Token-admin should be allowed to create token', async () => {
await destroy();
});

test('A role with only CREATE_PROJECT_API_TOKEN can create project tokens', async () => {
expect.assertions(0);

const preHook = (app, config, { userService, accessService }) => {
app.use('/api/admin/', async (req, res, next) => {
const role = await accessService.getRootRole(RoleName.VIEWER);
const user = await userService.createUser({
email: 'powerpuffgirls_viewer@example.com',
rootRole: role.id,
});
req.user = user;
const createClientApiTokenRole = await accessService.createRole({
name: 'project_client_token_creator',
description: 'Can create client tokens',
permissions: [],
type: 'root-custom',
});
await accessService.addPermissionToRole(
role.id,
CREATE_PROJECT_API_TOKEN,
);
await accessService.addUserToRole(
user.id,
createClientApiTokenRole.id,
'default',
);
req.user = await userService.createUser({
email: 'someguyinplaces@example.com',
rootRole: role.id,
});
next();
});
};

const { request, destroy } = await setupAppWithCustomAuth(stores, preHook, {
experimental: {
flags: {
customRootRoles: true,
},
},
});

await request
.post('/api/admin/projects/default/api-tokens')
.send({
username: 'client-token-maker',
type: 'client',
projects: ['default'],
})
.set('Content-Type', 'application/json')
.expect(201);
await destroy();
});

describe('Fine grained API token permissions', () => {
describe('A role with access to CREATE_CLIENT_API_TOKEN', () => {
test('should be allowed to create client tokens', async () => {
Expand Down

0 comments on commit 9778f54

Please sign in to comment.