Skip to content

Commit f0259db

Browse files
committed
tests(integration): grant types integration tests model integration covered
1 parent 704d917 commit f0259db

11 files changed

+544
-300
lines changed

lib/grant-types/abstract-grant-type.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ function AbstractGrantType(options) {
3636

3737
AbstractGrantType.prototype.generateAccessToken = async function(client, user, scope) {
3838
if (this.model.generateAccessToken) {
39-
const accessToken = await this.model.generateAccessToken(client, user, scope);
40-
return accessToken || tokenUtil.generateRandomToken();
39+
// We should not fall back to a random accessToken, if the model did not
40+
// return a token, in order to prevent unintended token-issuing.
41+
return this.model.generateAccessToken(client, user, scope);
4142
}
4243

4344
return tokenUtil.generateRandomToken();
@@ -49,8 +50,9 @@ AbstractGrantType.prototype.generateAccessToken = async function(client, user, s
4950

5051
AbstractGrantType.prototype.generateRefreshToken = async function(client, user, scope) {
5152
if (this.model.generateRefreshToken) {
52-
const refreshToken = await this.model.generateRefreshToken(client, user, scope);
53-
return refreshToken || tokenUtil.generateRandomToken();
53+
// We should not fall back to a random refreshToken, if the model did not
54+
// return a token, in order to prevent unintended token-issuing.
55+
return this.model.generateRefreshToken(client, user, scope);
5456
}
5557

5658
return tokenUtil.generateRandomToken();

lib/grant-types/authorization-code-grant-type.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ class AuthorizationCodeGrantType extends AbstractGrantType {
195195
const refreshTokenExpiresAt = await this.getRefreshTokenExpiresAt();
196196

197197
const token = {
198-
accessToken: accessToken,
199-
authorizationCode: authorizationCode,
200-
accessTokenExpiresAt: accessTokenExpiresAt,
201-
refreshToken: refreshToken,
202-
refreshTokenExpiresAt: refreshTokenExpiresAt,
198+
accessToken,
199+
authorizationCode,
200+
accessTokenExpiresAt,
201+
refreshToken,
202+
refreshTokenExpiresAt,
203203
scope: validatedScope,
204204
};
205205

lib/grant-types/client-credentials-grant-type.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ class ClientCredentialsGrantType extends AbstractGrantType {
7373
const accessToken = await this.generateAccessToken(client, user, scope);
7474
const accessTokenExpiresAt = await this.getAccessTokenExpiresAt(client, user, scope);
7575
const token = {
76-
accessToken: accessToken,
77-
accessTokenExpiresAt: accessTokenExpiresAt,
76+
accessToken,
77+
accessTokenExpiresAt,
7878
scope: validatedScope,
7979
};
8080

lib/grant-types/password-grant-type.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ class PasswordGrantType extends AbstractGrantType {
9494
const refreshTokenExpiresAt = await this.getRefreshTokenExpiresAt();
9595

9696
const token = {
97-
accessToken: accessToken,
98-
accessTokenExpiresAt: accessTokenExpiresAt,
99-
refreshToken: refreshToken,
100-
refreshTokenExpiresAt: refreshTokenExpiresAt,
97+
accessToken,
98+
accessTokenExpiresAt,
99+
refreshToken,
100+
refreshTokenExpiresAt,
101101
scope: validatedScope,
102102
};
103103

test/integration/grant-types/abstract-grant-type_test.js

Lines changed: 84 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
const AbstractGrantType = require('../../../lib/grant-types/abstract-grant-type');
88
const InvalidArgumentError = require('../../../lib/errors/invalid-argument-error');
99
const Request = require('../../../lib/request');
10+
const InvalidScopeError = require('../../../lib/errors/invalid-scope-error');
1011
const should = require('chai').should();
1112

1213
/**
@@ -44,7 +45,7 @@ describe('AbstractGrantType integration', function() {
4445
});
4546

4647
it('should set the `model`', function() {
47-
const model = {};
48+
const model = { async generateAccessToken () {} };
4849
const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: model });
4950

5051
grantType.model.should.equal(model);
@@ -58,70 +59,62 @@ describe('AbstractGrantType integration', function() {
5859
});
5960

6061
describe('generateAccessToken()', function() {
61-
it('should return an access token', function() {
62+
it('should return an access token', async function() {
6263
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 });
63-
64-
return handler.generateAccessToken()
65-
.then(function(data) {
66-
data.should.be.a.sha256();
67-
})
68-
.catch(should.fail);
64+
const accessToken = await handler.generateAccessToken();
65+
accessToken.should.be.a.sha256();
6966
});
7067

71-
it('should support promises', function() {
68+
it('should support promises', async function() {
7269
const model = {
7370
generateAccessToken: async function() {
74-
return {};
71+
return 'long-hash-foo-bar';
7572
}
7673
};
7774
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 });
78-
79-
handler.generateAccessToken().should.be.an.instanceOf(Promise);
75+
const accessToken = await handler.generateAccessToken();
76+
accessToken.should.equal('long-hash-foo-bar');
8077
});
8178

82-
it('should support non-promises', function() {
79+
it('should support non-promises', async function() {
8380
const model = {
8481
generateAccessToken: function() {
85-
return {};
82+
return 'long-hash-foo-bar';
8683
}
8784
};
8885
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 });
89-
90-
handler.generateAccessToken().should.be.an.instanceOf(Promise);
86+
const accessToken = await handler.generateAccessToken();
87+
accessToken.should.equal('long-hash-foo-bar');
9188
});
9289
});
9390

9491
describe('generateRefreshToken()', function() {
95-
it('should return a refresh token', function() {
92+
it('should return a refresh token', async function() {
9693
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 });
97-
98-
return handler.generateRefreshToken()
99-
.then(function(data) {
100-
data.should.be.a.sha256();
101-
})
102-
.catch(should.fail);
94+
const refreshToken = await handler.generateRefreshToken();
95+
refreshToken.should.be.a.sha256();
10396
});
10497

105-
it('should support promises', function() {
98+
it('should support promises', async function() {
10699
const model = {
107100
generateRefreshToken: async function() {
108-
return {};
101+
return 'long-hash-foo-bar';
109102
}
110103
};
111104
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 });
112-
113-
handler.generateRefreshToken().should.be.an.instanceOf(Promise);
105+
const refreshToken = await handler.generateRefreshToken();
106+
refreshToken.should.equal('long-hash-foo-bar');
114107
});
115108

116-
it('should support non-promises', function() {
109+
it('should support non-promises', async function() {
117110
const model = {
118111
generateRefreshToken: function() {
119-
return {};
112+
return 'long-hash-foo-bar';
120113
}
121114
};
122115
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 });
123-
124-
handler.generateRefreshToken().should.be.an.instanceOf(Promise);
116+
const refreshToken = await handler.generateRefreshToken();
117+
refreshToken.should.equal('long-hash-foo-bar');
125118
});
126119
});
127120

@@ -170,4 +163,64 @@ describe('AbstractGrantType integration', function() {
170163
handler.getScope(request).should.equal('foo');
171164
});
172165
});
166+
167+
describe('validateScope()', function () {
168+
it('accepts the scope, if the model does not implement it', async function () {
169+
const scope = 'some,scope,this,that';
170+
const user = { id: 123 };
171+
const client = { id: 456 };
172+
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 });
173+
const validated = await handler.validateScope(user, client, scope);
174+
validated.should.equal(scope);
175+
});
176+
177+
it('accepts the scope, if the model accepts it', async function () {
178+
const scope = 'some,scope,this,that';
179+
const user = { id: 123 };
180+
const client = { id: 456 };
181+
182+
const model = {
183+
async validateScope (_user, _client, _scope) {
184+
// make sure the model received the correct args
185+
_user.should.deep.equal(user);
186+
_client.should.deep.equal(_client);
187+
_scope.should.equal(scope);
188+
189+
return scope;
190+
}
191+
};
192+
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model, refreshTokenLifetime: 456 });
193+
const validated = await handler.validateScope(user, client, scope);
194+
validated.should.equal(scope);
195+
});
196+
197+
it('throws if the model rejects the scope', async function () {
198+
const scope = 'some,scope,this,that';
199+
const user = { id: 123 };
200+
const client = { id: 456 };
201+
const returnTypes = [undefined, null, false, 0, ''];
202+
203+
for (const type of returnTypes) {
204+
const model = {
205+
async validateScope (_user, _client, _scope) {
206+
// make sure the model received the correct args
207+
_user.should.deep.equal(user);
208+
_client.should.deep.equal(_client);
209+
_scope.should.equal(scope);
210+
211+
return type;
212+
}
213+
};
214+
const handler = new AbstractGrantType({ accessTokenLifetime: 123, model, refreshTokenLifetime: 456 });
215+
216+
try {
217+
await handler.validateScope(user, client, scope);
218+
should.fail();
219+
} catch (e) {
220+
e.should.be.an.instanceOf(InvalidScopeError);
221+
e.message.should.equal('Invalid scope: Requested scope is invalid');
222+
}
223+
}
224+
});
225+
});
173226
});

0 commit comments

Comments
 (0)