Skip to content

Fix: ValidateIdToken method and unit tests #58

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
merged 2 commits into from
Oct 22, 2019
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
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@
},
"homepage": "https://github.com/intuit/oauth-jsclient",
"dependencies": {
"csrf": "^3.0.4",
"atob": "2.1.2",
"csrf": "^3.0.4",
"es6-promise": "^4.2.5",
"events": "^3.0.0",
"idtoken-verifier": "^1.2.0",
Expand All @@ -83,6 +83,7 @@
},
"devDependencies": {
"body-parser": "^1.15.2",
"btoa": "^1.2.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chance": "^1.1.3",
Expand Down
7 changes: 3 additions & 4 deletions src/OAuthClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,8 @@ OAuthClient.prototype.validateIdToken = function validateIdToken(params = {}) {
// Step 1 : First check if the issuer is as mentioned in "issuer"
if (id_token_payload.iss !== 'https://oauth.platform.intuit.com/op/v1') return false;

// Step 2 : check if the aud field in idToken is same as application's clientId
if (id_token_payload.aud !== this.clientId) return false;
// Step 2 : check if the aud field in idToken contains application's clientId
if (!id_token_payload.aud.find(audience => (audience === this.clientId))) return false;

// Step 3 : ensure the timestamp has not elapsed
if (id_token_payload.exp < Date.now() / 1000) return false;
Expand Down Expand Up @@ -507,8 +507,7 @@ OAuthClient.prototype.getKeyFromJWKsURI = function getKeyFromJWKsURI(id_token, k
return (new Promise(((resolve) => {
resolve(this.loadResponse(request));
}))).then((response) => {
if (response.status !== '200') throw new Error('Could not reach JWK endpoint');

if (Number(response.status) !== 200) throw new Error('Could not reach JWK endpoint');
// Find the key by KID
const responseBody = JSON.parse(response.body);
const key = responseBody.keys.find(el => (el.kid === kid));
Expand Down
35 changes: 26 additions & 9 deletions test/OAuthClientTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const nock = require('nock');
const sinon = require('sinon');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const btoa = require('btoa');
const jwt = require('jsonwebtoken');

// eslint-disable-next-line no-unused-vars
const getPem = require('rsa-pem-from-mod-exp');
Expand All @@ -23,11 +25,14 @@ const expectedTokenResponse = require('./mocks/tokenResponse.json');
const expectedUserInfo = require('./mocks/userInfo.json');
const expectedMakeAPICall = require('./mocks/makeAPICallResponse.json');
const expectedjwkResponseCall = require('./mocks/jwkResponse.json');
const expectedvalidateIdToken = require('./mocks/validateIdToken.json');
const expectedOpenIDToken = require('./mocks/openID-token.json');
// var expectedErrorResponse = require('./mocks/errorResponse.json');
const expectedMigrationResponse = require('./mocks/authResponse.json');

require.cache[require.resolve('rsa-pem-from-mod-exp')] = {
exports: sinon.stub().returns(3),
};

const oauthClient = new OAuthClientTest({
clientId: 'clientID',
clientSecret: 'clientSecret',
Expand Down Expand Up @@ -338,9 +343,6 @@ describe('Tests for OAuthClient', () => {
});

describe('getPublicKey', () => {
require.cache[require.resolve('rsa-pem-from-mod-exp')] = {
exports: sinon.mock().returns(3),
};
const pem = oauthClient.getPublicKey(3, 4);
expect(pem).to.be.equal(3);
});
Expand Down Expand Up @@ -373,7 +375,7 @@ describe('Validate Id Token ', () => {
before(() => {
nock('https://oauth.platform.intuit.com').persist()
.get('/op/v1/jwks')
.reply(200, expectedjwkResponseCall, {
.reply(200, expectedjwkResponseCall.body, {
'content-type': 'application/json;charset=UTF-8',
'content-length': '264',
connection: 'close',
Expand All @@ -383,26 +385,41 @@ describe('Validate Id Token ', () => {
'cache-control': 'no-cache, no-store',
pragma: 'no-cache',
});
sinon.stub(jwt, 'verify').returns(true);
});

const mockIdTokenPayload = {
sub: 'b053d994-07d5-468d-b7ee-22e349d2e739',
aud: ['clientID'],
realmid: '1108033471',
auth_time: 1462554475,
iss: 'https://oauth.platform.intuit.com/op/v1',
exp: Date.now() + 60000,
iat: 1462557728,
};

const tokenParts = expectedOpenIDToken.id_token.split('.');
const encodedMockIdTokenPayload = tokenParts[0].concat('.', btoa(JSON.stringify(mockIdTokenPayload)));
const mockToken = Object.assign({}, expectedOpenIDToken, { id_token: encodedMockIdTokenPayload });

it('validate id token returns error if id_token missing', async () => {
delete oauthClient.getToken().id_token;
await expect(oauthClient.validateIdToken()).to.be.rejectedWith(Error);
});

it('Validate Id Token', () => {
oauthClient.getToken().setToken(expectedOpenIDToken);
oauthClient.getToken().setToken(mockToken);
oauthClient.validateIdToken()
.then((response) => {
expect(response).to.be.equal(expectedvalidateIdToken);
expect(response).to.be.equal(true);
});
});

it('Validate Id Token alternative', () => {
oauthClient.setToken(expectedOpenIDToken);
oauthClient.setToken(mockToken);
oauthClient.validateIdToken()
.then((response) => {
expect(response).to.be.equal(expectedOpenIDToken);
expect(response).to.be.equal(true);
});
});
});
Expand Down
4 changes: 2 additions & 2 deletions test/mocks/jwkResponse.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"body":"{\"keys\": [{\"kty\":\"sample_value_kty\",\"e\":\"sample_value_e\",\"use\":\"sample_value_use\",\"kid\":\"sample_value_kid\",\"alg\":\"sample_value_alg\",\"n\":\"sample_value_n\"}]}"
}
"body":"{\"keys\": [{\"kty\":\"sample_value_kty\",\"e\":\"sample_value_e\",\"use\":\"sample_value_use\",\"kid\":\"r4p5SbL2qaFehFzhj8gI\",\"alg\":\"sample_value_alg\",\"n\":\"sample_value_n\"}]}"
}