Skip to content

Commit c31841f

Browse files
committed
Merge pull request oauthjs#451 from razvanz/fix/validate-scope-on-authorize
fix: validate requested scope on authorize request
1 parent e827859 commit c31841f

File tree

2 files changed

+115
-4
lines changed

2 files changed

+115
-4
lines changed

lib/handlers/authorize-handler.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,16 @@ AuthorizeHandler.prototype.handle = function(request, response) {
9797
var ResponseType;
9898

9999
return Promise.bind(this)
100-
.then(function() {
101-
scope = this.getScope(request);
100+
.then(function() {
101+
var requestedScope = this.getScope(request);
102102

103-
return this.generateAuthorizationCode(client, user, scope);
104-
})
103+
return this.validateScope(user, client, requestedScope);
104+
})
105+
.then(function(validScope) {
106+
scope = validScope;
107+
108+
return this.generateAuthorizationCode(client, user, scope);
109+
})
105110
.then(function(authorizationCode) {
106111
state = this.getState(request);
107112
ResponseType = this.getResponseType(request);
@@ -196,6 +201,24 @@ AuthorizeHandler.prototype.getClient = function(request) {
196201
});
197202
};
198203

204+
/**
205+
* Validate requested scope.
206+
*/
207+
AuthorizeHandler.prototype.validateScope = function(user, client, scope) {
208+
if (this.model.validateScope) {
209+
return promisify(this.model.validateScope, 3).call(this.model, user, client, scope)
210+
.then(function (scope) {
211+
if (!scope) {
212+
throw new InvalidScopeError('Invalid scope: Requested scope is invalid');
213+
}
214+
215+
return scope;
216+
});
217+
} else {
218+
return Promise.resolve(scope);
219+
}
220+
};
221+
199222
/**
200223
* Get scope from the request.
201224
*/

test/integration/handlers/authorize-handler_test.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,94 @@ describe('AuthorizeHandler integration', function() {
332332
});
333333
});
334334

335+
it('should redirect to a successful response if `model.validateScope` is not defined', function() {
336+
var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] };
337+
var model = {
338+
getAccessToken: function() {
339+
return {
340+
client: client,
341+
user: {},
342+
accessTokenExpiresAt: new Date(new Date().getTime() + 10000)
343+
};
344+
},
345+
getClient: function() {
346+
return client;
347+
},
348+
saveAuthorizationCode: function() {
349+
return { authorizationCode: 12345, client: client };
350+
}
351+
};
352+
var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model });
353+
var request = new Request({
354+
body: {
355+
client_id: 12345,
356+
response_type: 'code'
357+
},
358+
headers: {
359+
'Authorization': 'Bearer foo'
360+
},
361+
method: {},
362+
query: {
363+
scope: 'read',
364+
state: 'foobar'
365+
}
366+
});
367+
var response = new Response({ body: {}, headers: {} });
368+
369+
return handler.handle(request, response)
370+
.then(function(data) {
371+
data.should.eql({
372+
authorizationCode: 12345,
373+
client: client
374+
});
375+
})
376+
.catch(should.fail);
377+
});
378+
379+
it('should redirect to an error response if `scope` is insufficient', function() {
380+
var client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] };
381+
var model = {
382+
getAccessToken: function() {
383+
return {
384+
client: client,
385+
user: {},
386+
accessTokenExpiresAt: new Date(new Date().getTime() + 10000)
387+
};
388+
},
389+
getClient: function() {
390+
return client;
391+
},
392+
saveAuthorizationCode: function() {
393+
return { authorizationCode: 12345, client: client };
394+
},
395+
validateScope: function() {
396+
return false;
397+
}
398+
};
399+
var handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model });
400+
var request = new Request({
401+
body: {
402+
client_id: 12345,
403+
response_type: 'code'
404+
},
405+
headers: {
406+
'Authorization': 'Bearer foo'
407+
},
408+
method: {},
409+
query: {
410+
scope: 'read',
411+
state: 'foobar'
412+
}
413+
});
414+
var response = new Response({ body: {}, headers: {} });
415+
416+
return handler.handle(request, response)
417+
.then(should.fail)
418+
.catch(function() {
419+
response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid');
420+
});
421+
});
422+
335423
it('should redirect to an error response if `state` is missing', function() {
336424
var model = {
337425
getAccessToken: function() {

0 commit comments

Comments
 (0)