diff --git a/src/accesscontrol.js b/src/accesscontrol.js index d0e318d7d..54ea6a431 100644 --- a/src/accesscontrol.js +++ b/src/accesscontrol.js @@ -70,19 +70,17 @@ function validateScope(scope) { } // tests if all requiredScopes are attached to the request -function hasScopes(authorizedScope, requiredScopes) { - assert.strictEqual(typeof authorizedScope, 'string'); +function hasScopes(authorizedScopes, requiredScopes) { + assert(Array.isArray(authorizedScopes), 'Expecting array'); assert(Array.isArray(requiredScopes), 'Expecting array'); - var scopes = authorizedScope.split(','); - - if (scopes.indexOf(exports.SCOPE_ANY) !== -1) return null; + if (authorizedScopes.indexOf(exports.SCOPE_ANY) !== -1) return null; for (var i = 0; i < requiredScopes.length; ++i) { const scopeParts = requiredScopes[i].split(':'); // this allows apps:write if the token has a higher apps scope - if (scopes.indexOf(requiredScopes[i]) === -1 && scopes.indexOf(scopeParts[0]) === -1) { + if (authorizedScopes.indexOf(requiredScopes[i]) === -1 && authorizedScopes.indexOf(scopeParts[0]) === -1) { debug('scope: missing scope "%s".', requiredScopes[i]); return new Error('Missing required scope "' + requiredScopes[i] + '"'); } diff --git a/src/routes/accesscontrol.js b/src/routes/accesscontrol.js index 82f3cc10f..ded070e31 100644 --- a/src/routes/accesscontrol.js +++ b/src/routes/accesscontrol.js @@ -108,10 +108,10 @@ function accessTokenAuth(accessToken, callback) { // scopes here can define what capabilities that token carries // passport put the 'info' object into req.authInfo, where we can further validate the scopes const userScope = user.groupIds.indexOf(constants.ADMIN_GROUP_ID) !== -1 ? '*' : 'profile'; - var scope = accesscontrol.intersectScope(userScope, token.scope); + var scope = accesscontrol.intersectScope(userScope, token.scope).split(','); // these clients do not require password checks unlike UI const skipPasswordVerification = token.clientId === 'cid-sdk' || token.clientId === 'cid-cli'; - var info = { authorizedScope: scope, skipPasswordVerification: skipPasswordVerification }; + var info = { authorizedScopes: scope, skipPasswordVerification: skipPasswordVerification }; callback(null, user, info); }); @@ -138,7 +138,7 @@ function scope(requiredScope) { function (req, res, next) { assert(req.authInfo && typeof req.authInfo === 'object'); - var error = accesscontrol.hasScopes(req.authInfo.authorizedScope, requiredScopes); + var error = accesscontrol.hasScopes(req.authInfo.authorizedScopes, requiredScopes); if (error) return next(new HttpError(403, error.message)); next(); @@ -157,7 +157,7 @@ function websocketAuth(requiredScopes, req, res, next) { req.user = user; - var e = accesscontrol.hasScopes(info.authorizedScope, requiredScopes); + var e = accesscontrol.hasScopes(info.authorizedScopes, requiredScopes); if (e) return next(new HttpError(403, e.message)); next(); diff --git a/src/routes/profile.js b/src/routes/profile.js index 37cdb7361..79c0a1806 100644 --- a/src/routes/profile.js +++ b/src/routes/profile.js @@ -29,7 +29,7 @@ function get(req, res, next) { username: req.user.username, email: req.user.email, fallbackEmail: req.user.fallbackEmail, - tokenScope: req.authInfo.authorizedScope, + tokenScope: req.authInfo.authorizedScopes, displayName: req.user.displayName, twoFactorAuthenticationEnabled: req.user.twoFactorAuthenticationEnabled })); diff --git a/src/routes/test/accesscontrol-test.js b/src/routes/test/accesscontrol-test.js index 824a603fb..0ad8ab0ba 100644 --- a/src/routes/test/accesscontrol-test.js +++ b/src/routes/test/accesscontrol-test.js @@ -27,7 +27,7 @@ describe('scopes middleware', function () { it('fails due to empty scope in request', function (done) { var mw = accesscontrol.scope('admin')[1]; - var req = { authInfo: { authorizedScope: '' } }; + var req = { authInfo: { authorizedScopes: [ ] } }; mw(req, null, function (error) { expect(error).to.be.a(HttpError); @@ -37,7 +37,7 @@ describe('scopes middleware', function () { it('fails due to wrong scope in request', function (done) { var mw = accesscontrol.scope('admin')[1]; - var req = { authInfo: { authorizedScope: 'foobar,something' } }; + var req = { authInfo: { authorizedScopes: [ 'foobar', 'something' ] } }; mw(req, null, function (error) { expect(error).to.be.a(HttpError); @@ -47,7 +47,7 @@ describe('scopes middleware', function () { it('fails due to wrong scope in request', function (done) { var mw = accesscontrol.scope('admin,users')[1]; - var req = { authInfo: { authorizedScope: 'foobar,admin' } }; + var req = { authInfo: { authorizedScopes: [ 'foobar', 'admin' ] } }; mw(req, null, function (error) { expect(error).to.be.a(HttpError); @@ -57,7 +57,7 @@ describe('scopes middleware', function () { it('succeeds with one requested scope and one provided scope', function (done) { var mw = accesscontrol.scope('admin')[1]; - var req = { authInfo: { authorizedScope: 'admin' } }; + var req = { authInfo: { authorizedScopes: [ 'admin' ] } }; mw(req, null, function (error) { expect(error).to.not.be.ok(); @@ -67,7 +67,7 @@ describe('scopes middleware', function () { it('succeeds with one requested scope and two provided scopes', function (done) { var mw = accesscontrol.scope('admin')[1]; - var req = { authInfo: { authorizedScope: 'foobar,admin' } }; + var req = { authInfo: { authorizedScopes: [ 'foobar', 'admin' ] } }; mw(req, null, function (error) { expect(error).to.not.be.ok(); @@ -77,7 +77,7 @@ describe('scopes middleware', function () { it('succeeds with two requested scope and two provided scopes', function (done) { var mw = accesscontrol.scope('admin,foobar')[1]; - var req = { authInfo: { authorizedScope: 'foobar,admin' } }; + var req = { authInfo: { authorizedScopes: [ 'foobar', 'admin' ] } }; mw(req, null, function (error) { expect(error).to.not.be.ok(); @@ -87,7 +87,7 @@ describe('scopes middleware', function () { it('succeeds with two requested scope and provided wildcard scope', function (done) { var mw = accesscontrol.scope('admin,foobar')[1]; - var req = { authInfo: { authorizedScope: '*' } }; + var req = { authInfo: { authorizedScopes: [ '*' ] } }; mw(req, null, function (error) { expect(error).to.not.be.ok(); diff --git a/src/routes/test/profile-test.js b/src/routes/test/profile-test.js index b941e67c8..70fc6327c 100644 --- a/src/routes/test/profile-test.js +++ b/src/routes/test/profile-test.js @@ -105,7 +105,7 @@ describe('Profile API', function () { expect(result.body.displayName).to.be.a('string'); expect(result.body.password).to.not.be.ok(); expect(result.body.salt).to.not.be.ok(); - expect(result.body.tokenScope).to.be(accesscontrol.VALID_SCOPES.join(',')); + expect(result.body.tokenScope).to.eql(accesscontrol.VALID_SCOPES); user_0 = result.body; @@ -143,7 +143,7 @@ describe('Profile API', function () { expect(result.body.displayName).to.be.a('string'); expect(result.body.password).to.not.be.ok(); expect(result.body.salt).to.not.be.ok(); - expect(result.body.tokenScope).to.be(accesscontrol.VALID_SCOPES.join(',')); + expect(result.body.tokenScope).to.eql(accesscontrol.VALID_SCOPES); done(); }); }); @@ -196,7 +196,7 @@ describe('Profile API', function () { expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); expect(res.body.email).to.equal(EMAIL_0_NEW.toLowerCase()); expect(res.body.fallbackEmail).to.equal(EMAIL_0_NEW_FALLBACK.toLowerCase()); - expect(res.body.tokenScope).to.be(accesscontrol.VALID_SCOPES.join(',')); + expect(res.body.tokenScope).to.eql(accesscontrol.VALID_SCOPES); expect(res.body.displayName).to.equal(''); done(); @@ -217,7 +217,7 @@ describe('Profile API', function () { expect(res.statusCode).to.equal(200); expect(res.body.username).to.equal(USERNAME_0.toLowerCase()); expect(res.body.email).to.equal(EMAIL_0_NEW.toLowerCase()); - expect(res.body.tokenScope).to.be(accesscontrol.VALID_SCOPES.join(',')); + expect(res.body.tokenScope).to.eql(accesscontrol.VALID_SCOPES); expect(res.body.displayName).to.equal(DISPLAY_NAME_0_NEW); done(); diff --git a/src/test/accesscontrol-test.js b/src/test/accesscontrol-test.js index 15e2fd845..1dc5275b7 100644 --- a/src/test/accesscontrol-test.js +++ b/src/test/accesscontrol-test.js @@ -63,23 +63,23 @@ describe('access control', function () { describe('hasScopes', function () { it('succeeds if it contains the scope', function () { - expect(accesscontrol.hasScopes('apps', [ 'apps' ])).to.be(null); - expect(accesscontrol.hasScopes('apps,mail', [ 'mail' ])).to.be(null); - expect(accesscontrol.hasScopes('clients,*,apps,mail', [ 'mail' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'apps' ], [ 'apps' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'apps', 'mail' ], [ 'mail' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'clients', '*', 'apps', 'mail' ], [ 'mail' ])).to.be(null); // subscope - expect(accesscontrol.hasScopes('apps', [ 'apps:read' ])).to.be(null); - expect(accesscontrol.hasScopes('apps:read', [ 'apps:read' ])).to.be(null); - expect(accesscontrol.hasScopes('apps,mail', [ 'apps:*' ])).to.be(null); - expect(accesscontrol.hasScopes('*', [ 'apps:read' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'apps' ], [ 'apps:read' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'apps:read' ], [ 'apps:read' ])).to.be(null); + expect(accesscontrol.hasScopes([ 'apps' , 'mail' ], [ 'apps:*' ])).to.be(null); + expect(accesscontrol.hasScopes([ '*' ], [ 'apps:read' ])).to.be(null); }); it('fails if it does not contain the scope', function () { - expect(accesscontrol.hasScopes('apps', [ 'mail' ])).to.be.an(Error); - expect(accesscontrol.hasScopes('apps,mail', [ 'clients' ])).to.be.an(Error); + expect(accesscontrol.hasScopes([ 'apps' ], [ 'mail' ])).to.be.an(Error); + expect(accesscontrol.hasScopes([ 'apps', 'mail' ], [ 'clients' ])).to.be.an(Error); // subscope - expect(accesscontrol.hasScopes('apps:write', [ 'apps:read' ])).to.be.an(Error); + expect(accesscontrol.hasScopes([ 'apps:write' ], [ 'apps:read' ])).to.be.an(Error); }); });