migrate permissions and admin flag to user.role
This commit is contained in:
@@ -105,14 +105,13 @@ function tokenAuth(req, res, next) {
|
||||
});
|
||||
}
|
||||
|
||||
function authorize(requiredPermission) {
|
||||
assert.strictEqual(typeof requiredPermission, 'string');
|
||||
function authorize(requiredRole) {
|
||||
assert.strictEqual(typeof requiredRole, 'string');
|
||||
|
||||
return function (req, res, next) {
|
||||
assert.strictEqual(typeof req.user, 'object');
|
||||
|
||||
var error = accesscontrol.hasPermission(req.user, requiredPermission);
|
||||
if (error) return next(new HttpError(403, error.message));
|
||||
if (users.compareRoles(req.user.role, requiredRole) < 0) return next(new HttpError(403, `role '${requiredRole}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
next();
|
||||
};
|
||||
@@ -129,8 +128,7 @@ function websocketAuth(requiredRole, req, res, next) {
|
||||
|
||||
req.user = user;
|
||||
|
||||
var e = accesscontrol.hasRole(req.user, requiredRole);
|
||||
if (e) return next(new HttpError(403, e.message));
|
||||
if (users.compareRoles(req.user.role, requiredRole) < 0) return next(new HttpError(403, `role '${requiredRole}' is required but user has only '${user.role}'`));
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
@@ -37,9 +37,8 @@ function get(req, res, next) {
|
||||
fallbackEmail: req.user.fallbackEmail,
|
||||
displayName: req.user.displayName,
|
||||
twoFactorAuthenticationEnabled: req.user.twoFactorAuthenticationEnabled,
|
||||
admin: req.user.admin,
|
||||
role: req.user.role,
|
||||
source: req.user.source,
|
||||
permissions: req.user.permissions,
|
||||
avatarUrl: fs.existsSync(path.join(paths.PROFILE_ICONS_DIR, req.user.id)) ? `${settings.adminOrigin()}/api/v1/profile/avatar/${req.user.id}` : `https://www.gravatar.com/avatar/${emailHash}.jpg`
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ function setup(done) {
|
||||
function (callback) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users')
|
||||
.query({ access_token: token })
|
||||
.send({ username: 'nonadmin', email: 'notadmin@server.test', invite: false })
|
||||
.send({ username: 'nonadmin', email: 'notadmin@server.test' })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(201);
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('Eventlog API', function () {
|
||||
.query({ access_token: token, page: 1, per_page: 10, search: EMAIL })
|
||||
.end(function (error, result) {
|
||||
expect(result.statusCode).to.equal(200);
|
||||
expect(result.body.eventlogs.length).to.equal(2);
|
||||
expect(result.body.eventlogs.length).to.equal(1);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -168,7 +168,7 @@ describe('Users API', function () {
|
||||
expect(res.body.username).to.equal(USERNAME_0.toLowerCase());
|
||||
expect(res.body.email).to.equal(EMAIL_0.toLowerCase());
|
||||
expect(res.body.groupIds).to.eql([]);
|
||||
expect(res.body.admin).to.be(true);
|
||||
expect(res.body.role).to.be(users.ROLE_OWNER);
|
||||
|
||||
done();
|
||||
});
|
||||
@@ -209,7 +209,7 @@ describe('Users API', function () {
|
||||
expect(res.body.username).to.equal(USERNAME_0.toLowerCase());
|
||||
expect(res.body.email).to.equal(EMAIL_0.toLowerCase());
|
||||
expect(res.body.groupIds).to.eql([]);
|
||||
expect(res.body.admin).to.be(true);
|
||||
expect(res.body.role).to.be(users.ROLE_OWNER);
|
||||
|
||||
done();
|
||||
});
|
||||
@@ -250,7 +250,7 @@ describe('Users API', function () {
|
||||
expect(res.body.username).to.equal(USERNAME_0.toLowerCase());
|
||||
expect(res.body.email).to.equal(EMAIL_0.toLowerCase());
|
||||
expect(res.body.groupIds).to.eql([]);
|
||||
expect(res.body.admin).to.be(true);
|
||||
expect(res.body.role).to.be(users.ROLE_OWNER);
|
||||
expect(res.body.displayName).to.be.a('string');
|
||||
expect(res.body.password).to.not.be.ok();
|
||||
expect(res.body.salt).to.not.be.ok();
|
||||
@@ -486,7 +486,7 @@ describe('Users API', function () {
|
||||
it('set second user as admin succeeds', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id)
|
||||
.query({ access_token: token })
|
||||
.send({ admin: true })
|
||||
.send({ role: users.ROLE_ADMIN })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(204);
|
||||
|
||||
@@ -494,17 +494,27 @@ describe('Users API', function () {
|
||||
.query({ access_token: token })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(200);
|
||||
expect(res.body.admin).to.be(true);
|
||||
expect(res.body.role).to.be(users.ROLE_ADMIN);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('remove self as admin fails', function (done) {
|
||||
it('make self as admin fails', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id)
|
||||
.query({ access_token: token })
|
||||
.send({ admin: false })
|
||||
.send({ role: users.ROLE_ADMIN })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(409);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('make self as normal user fails', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_0.id)
|
||||
.query({ access_token: token })
|
||||
.send({ role: users.ROLE_USER })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(409);
|
||||
done();
|
||||
@@ -514,7 +524,7 @@ describe('Users API', function () {
|
||||
it('remove second user as admin succeeds', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id)
|
||||
.query({ access_token: token })
|
||||
.send({ admin: false })
|
||||
.send({ role: users.ROLE_USER })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(204);
|
||||
done();
|
||||
@@ -797,11 +807,11 @@ describe('Users API', function () {
|
||||
});
|
||||
|
||||
|
||||
describe('permissions', function () {
|
||||
describe('role - user manager', function () {
|
||||
it('can make second user a usermanager', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id)
|
||||
.query({ access_token: token })
|
||||
.send({ permissions: [ 'manage_users' ] })
|
||||
.send({ role: users.ROLE_USER_MANAGER })
|
||||
.end(function (err, res) {
|
||||
expect(res.statusCode).to.equal(204);
|
||||
done();
|
||||
@@ -850,7 +860,7 @@ describe('Users API', function () {
|
||||
it('cannot change admin bit of another', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_2.id)
|
||||
.query({ access_token: token_1 })
|
||||
.send({ admin: true })
|
||||
.send({ role: users.ROLE_ADMIN })
|
||||
.end(function (err, result) {
|
||||
expect(result.statusCode).to.equal(403);
|
||||
done();
|
||||
@@ -860,9 +870,9 @@ describe('Users API', function () {
|
||||
it('cannot change admin bit of self', function (done) {
|
||||
superagent.post(SERVER_URL + '/api/v1/users/' + user_1.id)
|
||||
.query({ access_token: token_1 })
|
||||
.send({ admin: true })
|
||||
.send({ role: users.ROLE_ADMIN })
|
||||
.end(function (err, result) {
|
||||
expect(result.statusCode).to.equal(403);
|
||||
expect(result.statusCode).to.equal(409);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
+13
-26
@@ -41,14 +41,9 @@ function create(req, res, next) {
|
||||
if ('username' in req.body && typeof req.body.username !== 'string') return next(new HttpError(400, 'username must be string'));
|
||||
if ('displayName' in req.body && typeof req.body.displayName !== 'string') return next(new HttpError(400, 'displayName must be string'));
|
||||
if ('password' in req.body && typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be string'));
|
||||
if ('admin' in req.body && typeof req.body.admin !== 'boolean') return next(new HttpError(400, 'admin flag must be a boolean'));
|
||||
if ('permissions' in req.body) {
|
||||
if (!Array.isArray(req.body.permissions)) return next(new HttpError(400, 'permissions must be an array'));
|
||||
if (req.body.permissions.some((p) => typeof p !== 'string')) return next(new HttpError(400, 'permissions array must contain strings'));
|
||||
}
|
||||
|
||||
if (!req.user.admin) {
|
||||
if ('admin' in req.body || 'permissions' in req.body) return next(new HttpError(403, 'Only admin add admins or set permissions'));
|
||||
if ('role' in req.body) {
|
||||
if (typeof req.body.role !== 'string') return next(new HttpError(400, 'role must be string'));
|
||||
if (users.compareRoles(req.user.role, req.body.role) < 0) return next(new HttpError(403, `role '${req.body.role}' is required but user has only '${req.user.role}'`));
|
||||
}
|
||||
|
||||
var password = req.body.password || null;
|
||||
@@ -56,7 +51,7 @@ function create(req, res, next) {
|
||||
var username = 'username' in req.body ? req.body.username : null;
|
||||
var displayName = req.body.displayName || '';
|
||||
|
||||
users.create(username, password, email, displayName, { invitor: req.user, admin: req.body.admin, permissions: req.body.permissions }, auditSource.fromRequest(req), function (error, user) {
|
||||
users.create(username, password, email, displayName, { invitor: req.user, role: req.body.role || users.ROLE_USER }, auditSource.fromRequest(req), function (error, user) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(201, users.removePrivateFields(user)));
|
||||
@@ -73,23 +68,15 @@ function update(req, res, next) {
|
||||
if ('displayName' in req.body && typeof req.body.displayName !== 'string') return next(new HttpError(400, 'displayName must be string'));
|
||||
if ('username' in req.body && typeof req.body.username !== 'string') return next(new HttpError(400, 'username must be a string'));
|
||||
|
||||
if ('admin' in req.body) {
|
||||
if (typeof req.body.admin !== 'boolean') return next(new HttpError(400, 'admin must be a boolean'));
|
||||
// this route is only allowed for admins, so req.user has to be an admin
|
||||
if (req.user.id === req.resource.id && !req.body.admin) return next(new HttpError(409, 'Cannot remove admin flag on self'));
|
||||
}
|
||||
if ('role' in req.body) {
|
||||
if (typeof req.body.role !== 'string') return next(new HttpError(400, 'role must be a string'));
|
||||
if (req.user.id === req.resource.id) return next(new HttpError(409, 'Cannot set role flag on self'));
|
||||
|
||||
if ('permissions' in req.body) {
|
||||
if (!Array.isArray(req.body.permissions)) return next(new HttpError(400, 'permissions must be an array'));
|
||||
if (req.body.permissions.some((p) => typeof p !== 'string')) return next(new HttpError(400, 'permissions array must contain strings'));
|
||||
if (users.compareRoles(req.user.role, req.body.role) < 0) return next(new HttpError(403, `role '${req.body.role}' is required but user has only '${req.user.role}'`));
|
||||
}
|
||||
|
||||
if ('active' in req.body && typeof req.body.active !== 'boolean') return next(new HttpError(400, 'active must be a boolean'));
|
||||
|
||||
if (!req.user.admin) {
|
||||
if ('admin' in req.body || 'permissions' in req.body) return next(new HttpError(403, 'Only admin add admins or set permissions'));
|
||||
}
|
||||
|
||||
users.update(req.resource, req.body, auditSource.fromRequest(req), function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
@@ -126,7 +113,7 @@ function remove(req, res, next) {
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
|
||||
if (req.user.id === req.resource.id) return next(new HttpError(409, 'Not allowed to remove yourself.'));
|
||||
if (!req.user.admin && req.resource.admin) return next(new HttpError(403, 'Non-admin cannot remove admin user'));
|
||||
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
users.remove(req.resource, auditSource.fromRequest(req), function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
@@ -152,7 +139,7 @@ function verifyPassword(req, res, next) {
|
||||
function createInvite(req, res, next) {
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
|
||||
if (!req.user.admin && req.resource.admin) return next(new HttpError(403, 'Non-admin cannot reset admin user'));
|
||||
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
users.createInvite(req.resource, function (error, result) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
@@ -164,7 +151,7 @@ function createInvite(req, res, next) {
|
||||
function sendInvite(req, res, next) {
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
|
||||
if (!req.user.admin && req.resource.admin) return next(new HttpError(403, 'Non-admin cannot invite admin user'));
|
||||
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
users.sendInvite(req.resource, { invitor: req.user }, function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
@@ -178,7 +165,7 @@ function setGroups(req, res, next) {
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
|
||||
if (!Array.isArray(req.body.groupIds)) return next(new HttpError(400, 'API call requires a groups array.'));
|
||||
if (!req.user.admin && req.resource.admin) return next(new HttpError(403, 'Non-admin cannot modify admin user'));
|
||||
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
users.setMembership(req.resource, req.body.groupIds, function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
@@ -192,7 +179,7 @@ function changePassword(req, res, next) {
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
|
||||
if (typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a string'));
|
||||
if (!req.user.admin && req.resource.admin) return next(new HttpError(403, 'Non-admin cannot modify admin user'));
|
||||
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
|
||||
|
||||
users.setPassword(req.resource, req.body.password, function (error) {
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
Reference in New Issue
Block a user