diff --git a/src/accesscontrol.js b/src/accesscontrol.js index 09ad56ba0..f29b87525 100644 --- a/src/accesscontrol.js +++ b/src/accesscontrol.js @@ -116,6 +116,10 @@ function uninitialize(callback) { callback(null); } +function canonicalScope(scope) { + return scope.replace(exports.SCOPE_ANY, exports.VALID_SCOPES.join(',')); +} + function normalizeScope(allowedScope, wantedScope) { assert.strictEqual(typeof allowedScope, 'string'); assert.strictEqual(typeof wantedScope, 'string'); @@ -123,8 +127,8 @@ function normalizeScope(allowedScope, wantedScope) { const allowedScopes = allowedScope.split(','); const wantedScopes = wantedScope.split(','); - if (allowedScopes.indexOf(exports.SCOPE_ANY) !== -1) return wantedScope; - if (wantedScopes.indexOf(exports.SCOPE_ANY) !== -1) return allowedScope; + if (allowedScopes.indexOf(exports.SCOPE_ANY) !== -1) return canonicalScope(wantedScope); + if (wantedScopes.indexOf(exports.SCOPE_ANY) !== -1) return canonicalScope(allowedScope); return _.intersection(allowedScopes, wantedScopes).join(','); } @@ -156,6 +160,8 @@ function validateScope(scope) { if (scope === '') return new Error('Empty scope not allowed'); + // NOTE: this function intentionally does not allow '*'. This is only allowed in the db to allow + // us not write a migration script every time we add a new scope var allValid = scope.split(',').every(function (s) { return exports.VALID_SCOPES.indexOf(s) !== -1; }); if (!allValid) return new Error('Invalid scope. Available scopes are ' + exports.VALID_SCOPES.join(', ')); @@ -182,7 +188,3 @@ function validateRequestedScopes(authInfo, requestedScopes) { return null; } - -function canonicalScope(scope) { - return scope.replace(exports.SCOPE_ANY, exports.VALID_SCOPES.join(',')); -} diff --git a/src/clients.js b/src/clients.js index 9eb0dcae8..98e9e5c4d 100644 --- a/src/clients.js +++ b/src/clients.js @@ -88,7 +88,6 @@ function add(appId, type, redirectURI, scope, callback) { var error = accesscontrol.validateScope(scope); if (error) return callback(new ClientsError(ClientsError.INVALID_SCOPE, error.message)); - // appId is also client name error = validateName(appId); if (error) return callback(error); @@ -254,8 +253,9 @@ function addTokenByUserId(clientId, userId, expiresAt, callback) { if (error) return callback(error); var token = tokendb.generateToken(); + var scope = accesscontrol.canonicalScope(result.scope); - tokendb.add(token, userId, result.id, expiresAt, result.scope, function (error) { + tokendb.add(token, userId, result.id, expiresAt, scope, function (error) { if (error) return callback(new ClientsError(ClientsError.INTERNAL_ERROR, error)); callback(null, { diff --git a/src/routes/clients.js b/src/routes/clients.js index ba8286dbf..4285256e2 100644 --- a/src/routes/clients.js +++ b/src/routes/clients.js @@ -28,9 +28,6 @@ function add(req, res, next) { if (typeof data.scope !== 'string' || !data.scope) return next(new HttpError(400, 'scope is required')); if (!validUrl.isWebUri(data.redirectURI)) return next(new HttpError(400, 'redirectURI must be a valid uri')); - // allow whitespace - data.scope = data.scope.split(',').map(function (s) { return s.trim(); }).join(','); - clients.add(data.appId, clients.TYPE_EXTERNAL, data.redirectURI, data.scope, function (error, result) { if (error && error.reason === ClientsError.INVALID_SCOPE) return next(new HttpError(400, error.message)); if (error && error.reason === ClientsError.BAD_FIELD) return next(new HttpError(400, error.message)); diff --git a/src/routes/oauth2.js b/src/routes/oauth2.js index 544aef3e7..0e09617c4 100644 --- a/src/routes/oauth2.js +++ b/src/routes/oauth2.js @@ -135,6 +135,7 @@ function initialize() { var token = tokendb.generateToken(); var expires = Date.now() + constants.DEFAULT_TOKEN_EXPIRATION; + var scope = accesscontrol.canonicalScope(client.scope); tokendb.add(token, authCode.userId, authCode.clientId, expires, client.scope, function (error) { if (error) return callback(error);