Skip to content

Commit

Permalink
chore: bump issAuthResp draft to -04
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Dec 5, 2021
1 parent 05ac3a8 commit a8ee83b
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ The following draft specifications are implemented by oidc-provider:
- [JWT Response for OAuth Token Introspection - draft 10][jwt-introspection]
- [JWT Secured Authorization Response Mode for OAuth 2.0 (JARM) - Implementer's Draft 01][jarm]
- [Financial-grade API: Client Initiated Backchannel Authentication Profile (FAPI-CIBA) - Implementer's Draft 01][fapi-ciba]
- [OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response - draft 01][iss-auth-resp]
- [OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response - draft 04][iss-auth-resp]
- [OAuth 2.0 Demonstration of Proof-of-Possession at the Application Layer (DPoP) - draft 03][dpop]
- [OpenID Connect Back-Channel Logout 1.0 - draft 06][backchannel-logout]
- [OpenID Connect RP-Initiated Logout 1.0 - draft 01][rpinitiated-logout]
Expand Down Expand Up @@ -147,7 +147,7 @@ actions and i.e. emit metrics that react to specific triggers. See the list of a
[support-sponsor]: https://github.com/sponsors/panva
[par]: https://www.rfc-editor.org/rfc/rfc9126.html
[rpinitiated-logout]: https://openid.net/specs/openid-connect-rpinitiated-1_0-01.html
[iss-auth-resp]: https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-01
[iss-auth-resp]: https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-04
[fapi]: https://openid.net/specs/openid-financial-api-part-2-1_0.html
[ciba]: https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0-final.html
[fapi-ciba]: https://openid.net/specs/openid-financial-api-ciba-ID1.html
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,7 @@ async function introspectionAllowedPolicy(ctx, client, token) {

### features.issAuthResp

[draft-ietf-oauth-iss-auth-resp-01](https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-01) - OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response
[draft-ietf-oauth-iss-auth-resp-04](https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-04) - OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response

Enables `iss` authorization response parameter for responses without existing countermeasures against mix-up attacks.

Expand Down
2 changes: 1 addition & 1 deletion lib/actions/authorization/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = async function respond(ctx, next) {
out.state = params.state;
}

if (instance(ctx.oidc.provider).configuration('features.issAuthResp.enabled')) {
if (!out.id_token && instance(ctx.oidc.provider).configuration('features.issAuthResp.enabled')) {
out.iss = ctx.oidc.provider.issuer;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ function getDefaults() {
/*
* features.issAuthResp
*
* title: [draft-ietf-oauth-iss-auth-resp-01](https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-01) - OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response
* title: [draft-ietf-oauth-iss-auth-resp-04](https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-04) - OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response
*
* description: Enables `iss` authorization response parameter for responses without
* existing countermeasures against mix-up attacks.
Expand Down
6 changes: 3 additions & 3 deletions lib/helpers/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ const DRAFTS = new Map(Object.entries({
version: [0, 'id-00', 'individual-draft-00'],
},
issAuthResp: {
name: 'OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response - draft 01',
name: 'OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response - draft 04',
type: 'IETF OAuth Working Group draft',
url: 'https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-01',
version: ['draft-00', 'draft-01'],
url: 'https://tools.ietf.org/html/draft-ietf-oauth-iss-auth-resp-04',
version: ['draft-00', 'draft-01', 'draft-02', 'draft-03', 'draft-04'],
},
}));

Expand Down
29 changes: 29 additions & 0 deletions test/iss/iss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const cloneDeep = require('lodash/cloneDeep');
const merge = require('lodash/merge');

const config = cloneDeep(require('../default.config'));

merge(config.features, {
issAuthResp: { enabled: true },
jwtResponseModes: { enabled: true },
});

module.exports = {
config,
clients: [{
client_id: 'client',
token_endpoint_auth_method: 'none',
redirect_uris: ['https://client.example.com/cb'],
grant_types: ['authorization_code', 'implicit'],
scope: 'openid',
response_types: [
'code id_token token',
'code id_token',
'code token',
'code',
'id_token token',
'id_token',
'none',
],
}],
};
179 changes: 179 additions & 0 deletions test/iss/iss.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
const { expect } = require('chai');

const bootstrap = require('../test_helper');

describe('features.issAuthResp', () => {
before(bootstrap(__dirname));

describe('enriched discovery', () => {
it('shows the url now', function () {
return this.agent.get('/.well-known/openid-configuration')
.expect(200)
.expect((response) => {
expect(response.body).to.have.property('authorization_response_iss_parameter_supported', true);
});
});
});

describe('OAuth 2.0 Authorization Server Issuer Identifier in Authorization Response', () => {
before(function () { return this.login(); });

it('response_type=code', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['iss'], false))
.expect(auth.validateClientLocation)
.expect(auth.validateIss);
});

it('response_type=code token', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code token',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['iss'], false))
.expect(auth.validateClientLocation)
.expect(auth.validateIss);
});

it('response_type=code id_token', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code id_token',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['code', 'state', 'id_token']))
.expect(auth.validateClientLocation);
});

it('response_type=code id_token token', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code id_token token',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['code', 'state', 'id_token', 'access_token', 'token_type', 'expires_in', 'scope']))
.expect(auth.validateClientLocation);
});

it('response_type=id_token token', function () {
const auth = new this.AuthorizationRequest({
response_type: 'id_token token',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['state', 'id_token', 'access_token', 'token_type', 'expires_in', 'scope']))
.expect(auth.validateClientLocation);
});

it('response_type=id_token', function () {
const auth = new this.AuthorizationRequest({
response_type: 'id_token',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['state', 'id_token']))
.expect(auth.validateClientLocation);
});

it('response_type=none', function () {
const auth = new this.AuthorizationRequest({
response_type: 'none',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['state', 'iss']))
.expect(auth.validateClientLocation)
.expect(auth.validateIss);
});

it('response_mode=jwt', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code',
response_mode: 'jwt',
scope: 'openid',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['response']))
.expect(auth.validateClientLocation);
});

it('error with regular response modes', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code',
scope: 'openid profile',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['error', 'iss'], false))
.expect(auth.validateClientLocation)
.expect(auth.validateIss);
});

it('error with response_type none', function () {
const auth = new this.AuthorizationRequest({
response_type: 'none',
scope: 'openid profile',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['error', 'iss'], false))
.expect(auth.validateClientLocation)
.expect(auth.validateIss);
});

it('error with response_mode=jwt', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code',
response_mode: 'jwt',
scope: 'openid profile',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validatePresence(['response']))
.expect(auth.validateClientLocation);
});

it('error with response_mode=jwt fragment', function () {
const auth = new this.AuthorizationRequest({
response_type: 'code id_token',
response_mode: 'jwt',
scope: 'openid profile',
});

return this.wrap({ route: '/auth', verb: 'get', auth })
.expect(303)
.expect(auth.validateFragment)
.expect(auth.validatePresence(['response']))
.expect(auth.validateClientLocation);
});
});
});
7 changes: 7 additions & 0 deletions test/test_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ module.exports = function testHelper(dir, {
},
});

Object.defineProperty(this, 'validateIss', {
value: (response) => {
const { query: { iss } } = parse(response.headers.location, true);
expect(iss).to.equal(issuerIdentifier);
},
});

Object.defineProperty(this, 'validateInteractionRedirect', {
value: (response) => {
const { hostname, search, query } = parse(response.headers.location);
Expand Down

0 comments on commit a8ee83b

Please sign in to comment.