Map group roles to scopes
This commit is contained in:
@@ -16,6 +16,8 @@ exports = module.exports = {
|
|||||||
|
|
||||||
ROLE_OWNER: 'owner',
|
ROLE_OWNER: 'owner',
|
||||||
|
|
||||||
|
scopesForRoles: scopesForRoles,
|
||||||
|
|
||||||
validateRoles: validateRoles,
|
validateRoles: validateRoles,
|
||||||
|
|
||||||
validateScopeString: validateScopeString,
|
validateScopeString: validateScopeString,
|
||||||
@@ -24,6 +26,19 @@ exports = module.exports = {
|
|||||||
canonicalScopeString: canonicalScopeString
|
canonicalScopeString: canonicalScopeString
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions
|
||||||
|
const ROLE_DEFINITIONS = {
|
||||||
|
'owner': {
|
||||||
|
scopes: exports.VALID_SCOPES
|
||||||
|
},
|
||||||
|
'manage_apps': {
|
||||||
|
scopes: [ 'apps', 'domains', 'users' ]
|
||||||
|
},
|
||||||
|
'manage_users': {
|
||||||
|
scopes: [ 'users' ]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var assert = require('assert'),
|
var assert = require('assert'),
|
||||||
debug = require('debug')('box:accesscontrol'),
|
debug = require('debug')('box:accesscontrol'),
|
||||||
_ = require('underscore');
|
_ = require('underscore');
|
||||||
@@ -80,3 +95,17 @@ function hasScopes(authorizedScopes, requiredScopes) {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scopesForRoles(roles) {
|
||||||
|
assert(Array.isArray(roles), 'Expecting array');
|
||||||
|
|
||||||
|
var scopes = [ 'profile' ];
|
||||||
|
|
||||||
|
for (let r of roles) {
|
||||||
|
if (!ROLE_DEFINITIONS[r]) continue; // unknown or some legacy role
|
||||||
|
|
||||||
|
scopes = scopes.concat(ROLE_DEFINITIONS[r].scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _.uniq(scopes.sort(), true /* isSorted */);
|
||||||
|
}
|
||||||
|
|||||||
@@ -291,7 +291,6 @@ function getGroups(userId, callback) {
|
|||||||
database.query('SELECT ' + GROUPS_FIELDS + ' ' +
|
database.query('SELECT ' + GROUPS_FIELDS + ' ' +
|
||||||
' FROM groups INNER JOIN groupMembers ON groups.id = groupMembers.groupId AND groupMembers.userId = ?', [ userId ], function (error, results) {
|
' FROM groups INNER JOIN groupMembers ON groups.id = groupMembers.groupId AND groupMembers.userId = ?', [ userId ], function (error, results) {
|
||||||
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error));
|
||||||
if (results.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND));
|
|
||||||
|
|
||||||
results.forEach(postProcess);
|
results.forEach(postProcess);
|
||||||
|
|
||||||
|
|||||||
@@ -275,7 +275,6 @@ function getGroups(userId, callback) {
|
|||||||
assert.strictEqual(typeof callback, 'function');
|
assert.strictEqual(typeof callback, 'function');
|
||||||
|
|
||||||
groupdb.getGroups(userId, function (error, results) {
|
groupdb.getGroups(userId, function (error, results) {
|
||||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new GroupsError(GroupsError.NOT_FOUND));
|
|
||||||
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
if (error) return callback(new GroupsError(GroupsError.INTERNAL_ERROR, error));
|
||||||
|
|
||||||
callback(null, results);
|
callback(null, results);
|
||||||
|
|||||||
@@ -101,13 +101,13 @@ function accessTokenAuth(accessToken, callback) {
|
|||||||
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(null, null /* user */, 'Invalid Token'); // will end up as a 401
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(null, null /* user */, 'Invalid Token'); // will end up as a 401
|
||||||
if (error) return callback(error); // this triggers 'internal error' in passport
|
if (error) return callback(error); // this triggers 'internal error' in passport
|
||||||
|
|
||||||
users.get(token.identifier, function (error, user) {
|
users.getWithRoles(token.identifier, function (error, user) {
|
||||||
if (error && error.reason === UsersError.NOT_FOUND) return callback(null, null /* user */, 'Invalid Token'); // will end up as a 401
|
if (error && error.reason === UsersError.NOT_FOUND) return callback(null, null /* user */, 'Invalid Token'); // will end up as a 401
|
||||||
if (error) return callback(error);
|
if (error) return callback(error);
|
||||||
|
|
||||||
// scopes here can define what capabilities that token carries
|
// scopes here can define what capabilities that token carries
|
||||||
// passport put the 'info' object into req.authInfo, where we can further validate the scopes
|
// passport put the 'info' object into req.authInfo, where we can further validate the scopes
|
||||||
const userScopes = user.groupIds.indexOf(constants.ADMIN_GROUP_ID) !== -1 ? accesscontrol.VALID_SCOPES : [ 'profile' ];
|
const userScopes = accesscontrol.scopesForRoles(user.roles);
|
||||||
var authorizedScopes = accesscontrol.intersectScopes(userScopes, token.scope.split(','));
|
var authorizedScopes = accesscontrol.intersectScopes(userScopes, token.scope.split(','));
|
||||||
// these clients do not require password checks unlike UI
|
// these clients do not require password checks unlike UI
|
||||||
const skipPasswordVerification = token.clientId === 'cid-sdk' || token.clientId === 'cid-cli';
|
const skipPasswordVerification = token.clientId === 'cid-sdk' || token.clientId === 'cid-cli';
|
||||||
|
|||||||
19
src/users.js
19
src/users.js
@@ -13,6 +13,7 @@ exports = module.exports = {
|
|||||||
verifyWithEmail: verifyWithEmail,
|
verifyWithEmail: verifyWithEmail,
|
||||||
remove: removeUser,
|
remove: removeUser,
|
||||||
get: get,
|
get: get,
|
||||||
|
getWithRoles: getWithRoles,
|
||||||
getByResetToken: getByResetToken,
|
getByResetToken: getByResetToken,
|
||||||
getAllAdmins: getAllAdmins,
|
getAllAdmins: getAllAdmins,
|
||||||
resetPasswordByIdentifier: resetPasswordByIdentifier,
|
resetPasswordByIdentifier: resetPasswordByIdentifier,
|
||||||
@@ -330,6 +331,24 @@ function get(userId, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getWithRoles(userId, callback) {
|
||||||
|
assert.strictEqual(typeof userId, 'string');
|
||||||
|
assert.strictEqual(typeof callback, 'function');
|
||||||
|
|
||||||
|
userdb.get(userId, function (error, result) {
|
||||||
|
if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND));
|
||||||
|
if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error));
|
||||||
|
|
||||||
|
groups.getGroups(userId, function (error, userGroups) {
|
||||||
|
if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error));
|
||||||
|
|
||||||
|
result.roles = _.uniq(_.flatten(userGroups.map(function (r) { return r.roles; })));
|
||||||
|
|
||||||
|
return callback(null, result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getByResetToken(email, resetToken, callback) {
|
function getByResetToken(email, resetToken, callback) {
|
||||||
assert.strictEqual(typeof email, 'string');
|
assert.strictEqual(typeof email, 'string');
|
||||||
assert.strictEqual(typeof resetToken, 'string');
|
assert.strictEqual(typeof resetToken, 'string');
|
||||||
|
|||||||
Reference in New Issue
Block a user