Skip to content

Commit

Permalink
fix: device flow refresh tokens for public clients are now be certifi…
Browse files Browse the repository at this point in the history
…cate bound as well
  • Loading branch information
panva committed Jul 3, 2019
1 parent e918ca3 commit 904ad2d
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 4 deletions.
4 changes: 4 additions & 0 deletions lib/actions/grants/device_code.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ module.exports.handler = async function deviceCodeHandler(ctx, next) {
sid: code.sid,
});

if (ctx.oidc.client.tlsClientCertificateBoundAccessTokens && ctx.oidc.client.tokenEndpointAuthMethod === 'none') {
rt.setS256Thumbprint(cert);
}

ctx.oidc.entity('RefreshToken', rt);
refreshToken = await rt.save();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = {
client_id: 'client-none',
grant_types: [
'authorization_code',
'urn:ietf:params:oauth:grant-type:device_code',
'refresh_token',
],
response_types: ['code'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('features.certificateBoundAccessTokens', () => {
});

this.TestAdapter.for('DeviceCode').syncUpdate(this.getTokenJti(this.dc), {
scope: 'openid',
scope: 'openid offline_access',
accountId: 'account',
});
});
Expand All @@ -104,8 +104,9 @@ describe('features.certificateBoundAccessTokens', () => {
.expect(200);

expect(spy).to.have.property('calledOnce', true);
const { oidc: { entities: { AccessToken } } } = spy.args[0][0];
const { oidc: { entities: { AccessToken, RefreshToken } } } = spy.args[0][0];
expect(AccessToken).to.have.property('x5t#S256', expectedS256);
expect(RefreshToken).not.to.have.property('x5t#S256');
});

it('verifies the request made with mutual-TLS', function () {
Expand All @@ -119,6 +120,31 @@ describe('features.certificateBoundAccessTokens', () => {
.expect(400)
.expect({ error: 'invalid_request', error_description: 'mutual TLS client certificate not provided' });
});

it('binds the refresh token to the certificate for public clients', async function () {
const spy = sinon.spy();
this.provider.once('grant.success', spy);

// changes the code to client-none and
this.TestAdapter.for('DeviceCode').syncUpdate(this.getTokenJti(this.dc), {
clientId: 'client-none',
});

await this.agent.post('/token')
.send({
client_id: 'client-none',
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: this.dc,
})
.type('form')
.set('x-ssl-client-cert', crt.replace(RegExp('\\r?\\n', 'g'), ''))
.expect(200);

expect(spy).to.have.property('calledOnce', true);
const { oidc: { entities: { AccessToken, RefreshToken } } } = spy.args[0][0];
expect(AccessToken).to.have.property('x5t#S256', expectedS256);
expect(RefreshToken).to.have.property('x5t#S256', expectedS256);
});
});

describe('authorization flow', () => {
Expand Down
3 changes: 1 addition & 2 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ async function run() {
await new Promise((resolve, reject) => {
const mocha = new Mocha();
mocha.files = files;
mocha.reporter('min');
// mocha.bail();

if (process.env.CI) {
mocha.reporter('min');
mocha.retries(1); // retry flaky time comparison tests
mocha.forbidOnly(); // force suite fail on encountered only test
mocha.forbidPending(); // force suite fail on encountered skip test
Expand Down

0 comments on commit 904ad2d

Please sign in to comment.