Skip to content

Commit

Permalink
fix: migrate all permissions to rbac (#782)
Browse files Browse the repository at this point in the history
* fix: migrate all permissions to rbac
* fix: update migration guide

fixes #782
  • Loading branch information
ivarconr committed Apr 12, 2021
1 parent 9bd425c commit 9e7d2f8
Show file tree
Hide file tree
Showing 30 changed files with 174 additions and 425 deletions.
25 changes: 25 additions & 0 deletions docs/deploy/migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,31 @@ title: Migration Guide

Generally, the intention is that `unleash-server` should always provide support for clients one major version lower than the current one. This should make it possible to upgrade `unleash` gradually.

## Upgrading from v3.x to v4.x

(Work In Process!)

### Role-based Access Control (RBAC)

We have implemented RBAC in Unleash v4. This has totally changed the permission system in Unleash.

**Required actions:** If you have implemented "custom authentication" for your users you will need to make changes to your integration:

- _extendedPermissions_ option has been removed. You can no longer specify custom permission per-user basis. All "logged_in users" must belong to a "root" role. This can be "Admin", "Editor" or "Viewer". This is taken care of when you create new users via userService.
- All "logged-in users" needs to be defined in Unleash and have a unique ID. This can be achieved by calling "createUser" on "userService".

Code example:

```js
const user = userService.loginUserWithoutPassword(
'some@getunleash.io',
false, // autoCreateUser. Set to true if you want to create users on the fly.
);

// The user needs to be set on the current active session
req.session.user = user;
```

## Upgrading from v2.x to v3.x

The notable change introduced in Unleash v3.x is a strict separation of API paths for client requests and admin requests. This makes it easier to implement different authentication mechanisms for the admin UI and all unleash-clients. You can read more about [securing unleash](https://github.com/Unleash/unleash/blob/master/docs/securing-unleash.md).
Expand Down
4 changes: 3 additions & 1 deletion src/lib/app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ const getApp = proxyquire('./app', {
});

test('should not throw when valid config', t => {
const app = getApp({ getLogger });
const app = getApp({ getLogger, stores: {} });
t.true(typeof app.listen === 'function');
});

test('should call preHook', t => {
let called = 0;
getApp({
stores: {},
getLogger,
preHook: () => {
called++;
Expand All @@ -32,6 +33,7 @@ test('should call preHook', t => {
test('should call preRouterHook', t => {
let called = 0;
getApp({
stores: {},
getLogger,
preRouterHook: () => {
called++;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module.exports = function(config, services = {}) {
app.locals.baseUriPath = baseUriPath;

if (typeof config.preHook === 'function') {
config.preHook(app);
config.preHook(app, config, services);
}

app.use(compression());
Expand Down
4 changes: 2 additions & 2 deletions src/lib/db/access-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ export class AccessStore {
});
}

async getPermissionsForUser(userId: Number): Promise<IUserPermission[]> {
async getPermissionsForUser(userId: number): Promise<IUserPermission[]> {
const stopTimer = this.timer('getPermissionsForUser');
const rows = await this.db
.select('project', 'permission')
.from<IUserPermission>(`${T.ROLE_PERMISSION} AS rp`)
.leftJoin(`${T.ROLE_USER} AS ur`, 'ur.role_id', 'rp.role_id')
.where('user_id', '=', userId);
.where('ur.user_id', '=', userId);
stopTimer();
return rows;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/middleware/api-token-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const apiAccessMiddleware = (
const logger = config.getLogger('/middleware/api-token.ts');
logger.info('Enabling api-token middleware');

if(!config.authentication.enableApiToken) {
if (!config.authentication.enableApiToken) {
return (req, res, next) => next();
}

Expand Down
7 changes: 6 additions & 1 deletion src/lib/middleware/no-authentication.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
'use strict';

const { ADMIN } = require('../permissions');
const User = require('../user');

function noneAuthentication(basePath = '', app) {
app.use(`${basePath}/api/admin/`, (req, res, next) => {
req.user = new User({ username: 'unknown' });
req.user = new User({
username: 'unknown',
isAPI: true,
permissions: [ADMIN],
});
next();
});
}
Expand Down
39 changes: 0 additions & 39 deletions src/lib/middleware/permission-checker.js

This file was deleted.

135 changes: 0 additions & 135 deletions src/lib/middleware/permission-checker.test.js

This file was deleted.

16 changes: 1 addition & 15 deletions src/lib/middleware/rbac-middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,7 @@ test.beforeEach(() => {
};
});

test('should be disabled if rbac is disabled', t => {
const accessService = {};

const func = rbacMiddleware(config, { accessService });

const cb = sinon.fake();

func(undefined, undefined, cb);

t.true(cb.calledOnce);
});

test('should add checkRbac to request if enabled', t => {
config.experimental.rbac = true;

test('should add checkRbac to request', t => {
const accessService = {};

const func = rbacMiddleware(config, { accessService });
Expand Down
8 changes: 1 addition & 7 deletions src/lib/middleware/rbac-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,7 @@ import {
ADMIN,
} from '../permissions';

import { isRbacEnabled } from '../util/feature-enabled';

const rbacMiddleware = (config: any, { accessService }: any): any => {
if (!isRbacEnabled(config)) {
return (req, res, next) => next();
}

const logger = config.getLogger('/middleware/rbac-middleware.js');
logger.info('Enabling RBAC');

Expand Down Expand Up @@ -45,7 +39,7 @@ const rbacMiddleware = (config: any, { accessService }: any): any => {
const { featureName } = params;
projectId = await featureToggleStore.getProjectId(featureName);
} else if (permission === CREATE_FEATURE) {
projectId = req.body.project;
projectId = req.body.project || 'default';
}

return accessService.hasPermission(user, permission, projectId);
Expand Down
2 changes: 0 additions & 2 deletions src/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ function defaultOptions() {
unleashUrl: process.env.UNLEASH_URL || 'http://localhost:4242',
serverMetrics: true,
enableLegacyRoutes: false, // deprecated. Remove in v4,
extendedPermissions: false, // deprecated. Remove in v4,
publicFolder,
versionCheck: {
url:
Expand Down Expand Up @@ -101,7 +100,6 @@ function defaultOptions() {
enabled: process.env.CLIENT_FEATURE_MEMOIZE || false,
maxAge: process.env.CLIENT_FEATURE_MAXAGE || 1000,
},
rbac: false,
},
email: {
host: process.env.EMAIL_HOST,
Expand Down

0 comments on commit 9e7d2f8

Please sign in to comment.