oauth2orize-jwt-to-bearer
Version:
JSON Web Token (JWT) Bearer Token Exchange Middleware for OAuth2orize.
285 lines (227 loc) • 9.35 kB
JavaScript
;
const chai = require('chai');
const sinonChai = require('sinon-chai');
const TokenError = require('oauth2orize/lib/errors/tokenerror');
const jwtBearer = require('../lib/oauth2orize-jwt-to-bearer').Exchange;
const mock = require('./Mocks');
chai.use(sinonChai);
const { expect } = chai;
let jwtBearerExchange;
let req;
let res;
function setUpJWTBearerExchangeMiddleware(options, issue) {
jwtBearerExchange = jwtBearer(issue, options);
}
function getDefaultIssueFunction() {
return (client, scope, jwt, done) => {
if (client.id === 'c123' && jwt === 'header.claimSet.signature') {
return done(null, 's3cr1t');
}
return done(new Error('something is wrong'));
};
}
function getIssueReturningRefreshTokenFunction() {
return (client, scope, jwt, done) => {
if (client.id === 'c123' && jwt === 'header.claimSet.signature') {
return done(null, 's3cr1t', 'R3fr3SHs3cr1t');
}
return done(new Error('something is wrong'));
};
}
function getIssueMergingCustomParamsFunction(params) {
return (client, scope, jwt, done) => {
if (client.id === 'c123' && jwt === 'header.claimSet.signature') {
return done(null, 's3cr1t', null, params);
}
return done(new Error('something is wrong'));
};
}
describe('exchange middleware', () => {
it('should return a function', () => {
const jwtBearerFunction = jwtBearer(() => {
});
expect(jwtBearerFunction).to.be.a('Function');
});
describe('Request Validation', () => {
beforeEach(() => {
res = new mock.Response();
setUpJWTBearerExchangeMiddleware({}, getDefaultIssueFunction());
});
it('Should throw TokenError if no assertion is found', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = {};
function next(err) {
expect(err).to.be.an.instanceof(TokenError);
expect(err.status).to.equal(400);
expect(err.code).to.eql('invalid_request');
expect(err.message).to.eql('missing assertion parameter');
done();
}
jwtBearerExchange(req, res, next);
});
it('Should throw TokenError if scope parameter is not a string', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature', scope: {} };
function next(err) {
expect(err).to.be.an.instanceof(TokenError);
expect(err.status).to.equal(400);
expect(err.code).to.eql('invalid_request');
expect(err.message).to.eql('Invalid parameter: scope must be a string');
done();
}
jwtBearerExchange(req, res, next);
});
it('Should use userProperty configuration to get client', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.userOptional = { id: 'c12345', name: 'Example Optional' };
req.body = { assertion: 'header.claimSet.signature' };
setUpJWTBearerExchangeMiddleware({}, (client) => {
expect(client).to.deep.equal({ id: 'c123', name: 'Example' });
return done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should modify userProperty configuration from options to get client', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.userOptional = { id: 'c12345', name: 'Example Optional' };
req.body = { assertion: 'header.claimSet.signature' };
setUpJWTBearerExchangeMiddleware({ userProperty: 'userOptional' }, (client) => {
expect(client).to.deep.equal({ id: 'c12345', name: 'Example Optional' });
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should use scopeSeparator configuration to split scope', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature', scope:'scope1:read scope2:write scope3' };
setUpJWTBearerExchangeMiddleware({}, (client, scope) => {
expect(scope).to.deep.equal(['scope1:read', 'scope2:write', 'scope3']);
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should use scopeSeparator configuration to split scope', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature', scope:'scope1:read.scope2:write.scope3' };
setUpJWTBearerExchangeMiddleware({ scopeSeparator:':' }, (client, scope) => {
expect(scope).to.deep.equal(['scope1', 'read.scope2', 'write.scope3']);
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should send empty array if no scope is in body', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature' };
setUpJWTBearerExchangeMiddleware({ scopeSeparator:':' }, (client, scope) => {
expect(scope).to.deep.equal([]);
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should send empty array if scope is an empty string', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature', scope:'' };
setUpJWTBearerExchangeMiddleware({ scopeSeparator:':' }, (client, scope) => {
// eslint-disable-next-line no-unused-expressions
expect(scope).to.be.empty;
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('Should give back assertion as is from body', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature' };
setUpJWTBearerExchangeMiddleware({}, (client, scope, assertion) => {
expect(assertion).to.equal('header.claimSet.signature');
done();
});
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
});
describe('Response', () => {
beforeEach(() => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = { assertion: 'header.claimSet.signature' };
res = new mock.Response();
setUpJWTBearerExchangeMiddleware({}, getDefaultIssueFunction());
});
it('Should not send response if error is sent to issued function', (done) => {
req = new mock.Request();
req.user = { id: 'c123', name: 'Example' };
req.body = {};
res.end = () => {
done(new Error('Shouldn\'t have call end() of response'));
};
function next(err) {
expect(err).to.be.an.instanceof(Error);
done();
}
jwtBearerExchange(req, res, next);
});
it('should set Content-Type header to application/json', (done) => {
res.end = () => {
expect(res._headers['Content-Type']).to.eql('application/json');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should set Cache-Control header to no-store', (done) => {
res.end = () => {
expect(res._headers['Cache-Control']).to.eql('no-store');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should set Pragma header to no-cache', (done) => {
res.end = () => {
expect(res._headers.Pragma).to.eql('no-cache');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should set access token in response', (done) => {
res.done = () => {
expect(res._data).to.eql('{"access_token":"s3cr1t","token_type":"Bearer"}');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should set refresh token in response', (done) => {
setUpJWTBearerExchangeMiddleware({}, getIssueReturningRefreshTokenFunction());
res.done = () => {
expect(res._data).to.eql('{"access_token":"s3cr1t","refresh_token":"R3fr3SHs3cr1t","token_type":"Bearer"}');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should merge custom params in response', (done) => {
setUpJWTBearerExchangeMiddleware({}, getIssueMergingCustomParamsFunction({ test: 'testValue' }));
res.done = () => {
expect(res._data).to.eql('{"access_token":"s3cr1t","test":"testValue","token_type":"Bearer"}');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
it('should overwrite params while merging custom params in response', (done) => {
setUpJWTBearerExchangeMiddleware({}, getIssueMergingCustomParamsFunction({
access_token: 'overwrite.access.token',
test: 'testValue',
}));
res.done = () => {
expect(res._data).to.eql('{"access_token":"overwrite.access.token","test":"testValue","token_type":"Bearer"}');
done();
};
jwtBearerExchange(req, res, (err) => { if (err) done(err); });
});
});
});