diff --git a/src/accesscontrol.js b/src/accesscontrol.js index a7f985ac3..db9a0c60e 100644 --- a/src/accesscontrol.js +++ b/src/accesscontrol.js @@ -28,6 +28,7 @@ exports = module.exports = { var assert = require('assert'), DatabaseError = require('./databaseerror.js'), debug = require('debug')('box:accesscontrol'), + settings = require('./settings.js'), tokendb = require('./tokendb.js'), users = require('./users.js'), UsersError = users.UsersError, @@ -111,7 +112,13 @@ function scopesForUser(user, callback) { assert.strictEqual(typeof user, 'object'); assert.strictEqual(typeof callback, 'function'); - return callback(null, user.admin ? exports.VALID_SCOPES : [ 'profile', 'apps:read' ]); + if (user.admin) return callback(null, exports.VALID_SCOPES); + + settings.getSpacesConfig(function (error, spaces) { + if (error) return callback(error); + + callback(null, spaces.enabled ? [ 'profile', 'apps', 'domains:read', 'users:read' ] : [ 'profile', 'apps:read' ]); + }); } function validateToken(accessToken, callback) { diff --git a/src/routes/accesscontrol.js b/src/routes/accesscontrol.js index d41f98944..e88916478 100644 --- a/src/routes/accesscontrol.js +++ b/src/routes/accesscontrol.js @@ -1,13 +1,17 @@ 'use strict'; exports = module.exports = { + initialize: initialize, + uninitialize: uninitialize, + scope: scope, websocketAuth: websocketAuth, - initialize: initialize, - uninitialize: uninitialize + verifyAppOwnership: verifyAppOwnership }; var accesscontrol = require('../accesscontrol.js'), + apps = require('../apps.js'), + AppsError = apps.AppsError, assert = require('assert'), BasicStrategy = require('passport-http').BasicStrategy, BearerStrategy = require('passport-http-bearer').Strategy, @@ -17,6 +21,7 @@ var accesscontrol = require('../accesscontrol.js'), HttpError = require('connect-lastmile').HttpError, LocalStrategy = require('passport-local').Strategy, passport = require('passport'), + settings = require('../settings.js'), users = require('../users.js'), UsersError = users.UsersError; @@ -137,3 +142,25 @@ function websocketAuth(requiredScopes, req, res, next) { next(); }); } + +function verifyAppOwnership(req, res, next) { + if (req.user.admin) return next(); + + const appCreate = !('id' in req.params); + + settings.getSpacesConfig(function (error, spaces) { + if (error) return next(new HttpError(500, error)); + if (!spaces.enabled) return next(); + + if (appCreate) return next(); // ok to install app + + apps.get(req.params.id, function (error, app) { + if (error && error.reason === AppsError.NOT_FOUND) return next(new HttpError(404, 'No such app')); + if (error) return next(new HttpError(500, error)); + + if (app.ownerId !== req.user.id) return next(new HttpError(401, 'Unauthorized')); + + next(); + }); + }); +} diff --git a/src/server.js b/src/server.js index 4248ae571..052c2a321 100644 --- a/src/server.js +++ b/src/server.js @@ -94,7 +94,7 @@ function initializeExpressSync() { var usersReadScope = routes.accesscontrol.scope(accesscontrol.SCOPE_USERS_READ); var usersManageScope = routes.accesscontrol.scope(accesscontrol.SCOPE_USERS_MANAGE); var appsReadScope = routes.accesscontrol.scope(accesscontrol.SCOPE_APPS_READ); - var appsManageScope = routes.accesscontrol.scope(accesscontrol.SCOPE_APPS_MANAGE); + var appsManageScope = [ routes.accesscontrol.scope(accesscontrol.SCOPE_APPS_MANAGE), routes.accesscontrol.verifyAppOwnership ]; var settingsScope = routes.accesscontrol.scope(accesscontrol.SCOPE_SETTINGS); var mailScope = routes.accesscontrol.scope(accesscontrol.SCOPE_MAIL); var clientsScope = routes.accesscontrol.scope(accesscontrol.SCOPE_CLIENTS);