Skip to content

Support for retrieving user based on client #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions docs/model/spec.rst
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ The return value (``client``) can carry additional properties that will be ignor

.. _Model#getUser:

``getUser(username, password)``
``getUser(username, password, client)``
===========================================

Invoked to retrieve a user using a username/password combination.
Expand All @@ -454,13 +454,15 @@ This model function is **required** if the ``password`` grant is used.

**Arguments:**

+------------+----------+---------------------------------------------------------------------+
| Name | Type | Description |
+============+==========+=====================================================================+
| username | String | The username of the user to retrieve. |
+------------+----------+---------------------------------------------------------------------+
| password | String | The user's password. |
+------------+----------+---------------------------------------------------------------------+
+-------------------+----------+---------------------------------------------------------------------+
| Name | Type | Description |
+===================+==========+=====================================================================+
| username | String | The username of the user to retrieve. |
+-------------------+----------+---------------------------------------------------------------------+
| password | String | The user's password. |
+-------------------+----------+---------------------------------------------------------------------+
| client (optional) | Client | The client. |
+-------------------+----------+---------------------------------------------------------------------+

**Return value:**

Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ declare namespace OAuth2Server {
* Invoked to retrieve a user using a username/password combination.
*
*/
getUser(username: string, password: string): Promise<User | Falsey>;
getUser(username: string, password: string, client: Client): Promise<User | Falsey>;

/**
* Invoked to check if the requested scope is valid for a particular client/user combination.
Expand Down
6 changes: 3 additions & 3 deletions lib/grant-types/password-grant-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class PasswordGrantType extends AbstractGrantType {
}

const scope = this.getScope(request);
const user = await this.getUser(request);
const user = await this.getUser(request, client);

return this.saveToken(user, client, scope);
}
Expand All @@ -56,7 +56,7 @@ class PasswordGrantType extends AbstractGrantType {
* Get user using a username/password combination.
*/

async getUser(request) {
async getUser(request, client) {
if (!request.body.username) {
throw new InvalidRequestError('Missing parameter: `username`');
}
Expand All @@ -73,7 +73,7 @@ class PasswordGrantType extends AbstractGrantType {
throw new InvalidRequestError('Invalid parameter: `password`');
}

const user = await this.model.getUser(request.body.username, request.body.password);
const user = await this.model.getUser(request.body.username, request.body.password, client);

if (!user) {
throw new InvalidGrantError('Invalid grant: user credentials are invalid');
Expand Down
24 changes: 16 additions & 8 deletions test/integration/grant-types/password-grant-type_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,12 @@ describe('PasswordGrantType integration', function() {
getUser: () => should.fail(),
saveToken: () => should.fail()
};
const client = { id: 'foobar' };
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: {}, headers: {}, method: {}, query: {} });

try {
await grantType.getUser(request);
await grantType.getUser(request, client);

should.fail();
} catch (e) {
Expand All @@ -195,11 +196,12 @@ describe('PasswordGrantType integration', function() {
getUser: () => should.fail(),
saveToken: () => should.fail()
};
const client = { id: 'foobar' };
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foo' }, headers: {}, method: {}, query: {} });

try {
await grantType.getUser(request);
await grantType.getUser(request, client);

should.fail();
} catch (e) {
Expand All @@ -213,11 +215,12 @@ describe('PasswordGrantType integration', function() {
getUser: () => should.fail(),
saveToken: () => should.fail()
};
const client = { id: 'foobar' };
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, method: {}, query: {} });

try {
await grantType.getUser(request);
await grantType.getUser(request, client);

should.fail();
} catch (e) {
Expand All @@ -231,11 +234,12 @@ describe('PasswordGrantType integration', function() {
getUser: () => should.fail(),
saveToken: () => should.fail()
};
const client = { id: 'foobar' };
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, method: {}, query: {} });

try {
await grantType.getUser(request);
await grantType.getUser(request, client);

should.fail();
} catch (e) {
Expand All @@ -249,11 +253,12 @@ describe('PasswordGrantType integration', function() {
getUser: async () => undefined,
saveToken: () => should.fail()
};
const client = { id: 'foobar' };
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} });

try {
await grantType.getUser(request);
await grantType.getUser(request, client);
should.fail();
} catch (e) {
e.should.be.an.instanceOf(InvalidGrantError);
Expand All @@ -263,6 +268,7 @@ describe('PasswordGrantType integration', function() {

it('should return a user', async function() {
const user = { email: '[email protected]' };
const client = { id: 'foobar' };
const model = {
getUser: function(username, password) {
username.should.equal('foo');
Expand All @@ -274,32 +280,34 @@ describe('PasswordGrantType integration', function() {
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} });

const data = await grantType.getUser(request);
const data = await grantType.getUser(request, client);
data.should.equal(user);
});

it('should support promises', function() {
const user = { email: '[email protected]' };
const client = { id: 'foobar' };
const model = {
getUser: async function() { return user; },
saveToken: () => should.fail()
};
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} });

grantType.getUser(request).should.be.an.instanceOf(Promise);
grantType.getUser(request, client).should.be.an.instanceOf(Promise);
});

it('should support non-promises', function() {
const user = { email: '[email protected]' };
const client = { id: 'foobar' };
const model = {
getUser: function() { return user; },
saveToken: () => should.fail()
};
const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model });
const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} });

grantType.getUser(request).should.be.an.instanceOf(Promise);
grantType.getUser(request, client).should.be.an.instanceOf(Promise);
});
});

Expand Down
5 changes: 3 additions & 2 deletions test/unit/grant-types/password-grant-type_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ describe('PasswordGrantType', function() {
getUser: sinon.stub().returns(true),
saveToken: function() {}
};
const client = { id: 'foobar' };
const handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model });
const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} });

return handler.getUser(request)
return handler.getUser(request, client)
.then(function() {
model.getUser.callCount.should.equal(1);
model.getUser.firstCall.args.should.have.length(2);
model.getUser.firstCall.args.should.have.length(3);
model.getUser.firstCall.args[0].should.equal('foo');
model.getUser.firstCall.args[1].should.equal('bar');
model.getUser.firstCall.thisValue.should.equal(model);
Expand Down