Skip to content

Commit c169c1b

Browse files
committed
Allow any valid URI for extension grants
URI as per RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3)
1 parent 4d4f248 commit c169c1b

File tree

5 files changed

+85
-7
lines changed

5 files changed

+85
-7
lines changed

Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ The spec does not actually require that you revoke the old token - hence this is
266266

267267
## Extension Grants
268268
You can support extension/custom grants by implementing the extendedGrant method as outlined above.
269-
Any requests that begin with http(s):// (as [defined in the spec](http://tools.ietf.org/html/rfc6749#section-4.5)) will be passed to it for you to handle.
269+
Any grant type that is a valid URI will be passed to it for you to handle (as [defined in the spec](http://tools.ietf.org/html/rfc6749#section-4.5)).
270270
You can access the grant type via the first argument and you should pass back supported as `false` if you do not support it to ensure a consistent (and compliant) response.
271271

272272
## Example using the `password` grant type

lib/grant.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,8 @@ function checkClient (done) {
151151
* @this OAuth
152152
*/
153153
function checkGrantType (done) {
154-
if (this.grantType.match(/^http(s|):\/\//) && this.model.extendedGrant) {
154+
if (this.grantType.match(/^[a-zA-Z][a-zA-Z0-9+.-]+:/)
155+
&& this.model.extendedGrant) {
155156
return useExtendedGrant.call(this, done);
156157
}
157158

lib/oauth2server.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ OAuth2Server.prototype.authorise = function () {
6767
var self = this;
6868

6969
return function (req, res, next) {
70-
new Authorise(self, req, next);
70+
return new Authorise(self, req, next);
7171
};
7272
};
7373

@@ -213,7 +213,9 @@ OAuth2Server.prototype.lockdown = function (app) {
213213

214214
if (app.routes) {
215215
for (var method in app.routes) {
216-
app.routes[method].callbacks.forEach(lockdownExpress3);
216+
app.routes[method].forEach(function (route) {
217+
lockdownExpress3(route.callbacks);
218+
});
217219
}
218220
} else {
219221
app._router.stack.forEach(lockdownExpress4);

test/grant.extended.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ describe('Granting with extended grant type', function () {
129129
extendedGrant: function (grantType, req, callback) {
130130
callback(false, true, { id: 3 });
131131
},
132-
saveAccessToken: function () {
133-
done(); // That's enough
134-
}
132+
saveAccessToken: function (token, clientId, expires, user, cb) {
133+
cb();
134+
},
135135
},
136136
grants: ['http://custom.com']
137137
});
@@ -146,4 +146,34 @@ describe('Granting with extended grant type', function () {
146146
})
147147
.expect(200, done);
148148
});
149+
150+
it('should allow any valid URI valid request', function (done) {
151+
var app = bootstrap({
152+
model: {
153+
getClient: function (id, secret, callback) {
154+
callback(false, true);
155+
},
156+
grantTypeAllowed: function (clientId, grantType, callback) {
157+
callback(false, true);
158+
},
159+
extendedGrant: function (grantType, req, callback) {
160+
callback(false, true, { id: 3 });
161+
},
162+
saveAccessToken: function (token, clientId, expires, user, cb) {
163+
cb();
164+
},
165+
},
166+
grants: ['urn:custom:grant']
167+
});
168+
169+
request(app)
170+
.post('/oauth/token')
171+
.set('Content-Type', 'application/x-www-form-urlencoded')
172+
.send({
173+
grant_type: 'urn:custom:grant',
174+
client_id: 'thom',
175+
client_secret: 'nightworld'
176+
})
177+
.expect(200, done);
178+
});
149179
});

test/lockdown.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var express = require('express'),
2020
should = require('should');
2121

2222
var oauth2server = require('../');
23+
var Authorise = require('../lib/authorise');
2324

2425
var bootstrap = function (oauthConfig) {
2526
var app = express();
@@ -86,4 +87,48 @@ describe('Lockdown pattern', function() {
8687
.get('/public')
8788
.expect(200, /hello/i, done);
8889
});
90+
91+
describe('in express 3', function () {
92+
var app, privateAction, publicAction;
93+
94+
beforeEach(function () {
95+
privateAction = function () {};
96+
publicAction = function () {};
97+
98+
// mock express 3 app
99+
app = {
100+
routes: { get: [] }
101+
};
102+
103+
app.oauth = oauth2server({ model: {} });
104+
app.routes.get.push({ callbacks: [ privateAction ] });
105+
app.routes.get.push({ callbacks: [ app.oauth.bypass, publicAction ] })
106+
app.oauth.lockdown(app);
107+
});
108+
109+
function mockRequest(authoriseFactory) {
110+
var req = {
111+
get: function () {},
112+
query: { access_token: { expires: null } }
113+
};
114+
var next = function () {};
115+
116+
app.oauth.model.getAccessToken = function (t, c) { c(null, t); };
117+
118+
return authoriseFactory(req, null, next);
119+
}
120+
121+
it('adds authorise to non-bypassed routes', function () {
122+
var authorise = mockRequest(app.routes.get[0].callbacks[0]);
123+
authorise.should.be.an.instanceOf(Authorise);
124+
});
125+
126+
it('runs non-bypassed routes after authorise', function () {
127+
app.routes.get[0].callbacks[1].should.equal(privateAction);
128+
});
129+
130+
it('removes oauth.bypass from bypassed routes', function () {
131+
app.routes.get[1].callbacks[0].should.equal(publicAction);
132+
});
133+
});
89134
});

0 commit comments

Comments
 (0)