Skip to content

Commit

Permalink
refactor: merge interactions and interactionUrl configuration
Browse files Browse the repository at this point in the history
BREAKING CHANGE: `interactionUrl` configuration option is now
`interactions.url`, `interactions` configuration option is now
`interactions.policy`
  • Loading branch information
panva committed Jun 23, 2019
1 parent 6227e82 commit 1193719
Show file tree
Hide file tree
Showing 27 changed files with 75 additions and 68 deletions.
32 changes: 18 additions & 14 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ If you or your business use oidc-provider, please consider becoming a [Patron][s
- [formats](#formats)
- [httpOptions](#httpoptions)
- [interactions](#interactions)
- [interactionUrl](#interactionurl)
- [introspectionEndpointAuthMethods](#introspectionendpointauthmethods)
- [issueRefreshToken](#issuerefreshtoken)
- [logoutSource](#logoutsource)
Expand Down Expand Up @@ -1967,21 +1966,14 @@ To change all request's timeout configure the httpOptions as a function like so:
```
</details>

### interactionUrl
### interactions

Helper used by the OP to determine where to redirect User-Agent for necessary interaction, can return both absolute and relative urls
TODO


_**default value**_:
```js
async interactionUrl(ctx, interaction) {
return `/interaction/${ctx.oidc.uid}`;
}
```

### interactions
### interactions.policy

structure of Prompts and their checks formed by Prompt and Check class instances. The default you can modify and the classes are available under `Provider.interaction`.
structure of Prompts and their checks formed by Prompt and Check class instances. The default you can modify and the classes are available under `Provider.interactionPolicy`.



Expand Down Expand Up @@ -2044,7 +2036,7 @@ _**default value**_:
return true;
}

if (oidc.session.past(oidc.params.max_age)) {
if (oidc.session.past(oidc.params.max_age) && (!ctx.oidc.result || !ctx.oidc.result.login)) {
return true;
}

Expand Down Expand Up @@ -2281,7 +2273,7 @@ _**default value**_:
<br>

```js
const { interaction: { Prompt, Check, DEFAULT } } = require('oidc-provider');
const { interactionPolicy: { Prompt, Check, DEFAULT } } = require('oidc-provider');
// DEFAULT.get(name) => returns a Prompt instance by its name
// DEFAULT.remove(name) => removes a Prompt instance by its name
// DEFAULT.add(prompt, index) => adds a Prompt instance to a specific index, default is to last index
Expand All @@ -2291,6 +2283,18 @@ const { interaction: { Prompt, Check, DEFAULT } } = require('oidc-provider');
```
</details>

### interactions.url

Helper used by the OP to determine where to redirect User-Agent for necessary interaction, can return both absolute and relative urls.


_**default value**_:
```js
async url(ctx, interaction) {
return `/interaction/${ctx.oidc.uid}`;
}
```

### introspectionEndpointAuthMethods

Array of Client Authentication methods supported by this OP's Introspection Endpoint. If no configuration value is provided the same values as for tokenEndpointAuthMethods will be used. Supported values list is the same as for tokenEndpointAuthMethods.
Expand Down
2 changes: 1 addition & 1 deletion docs/checks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
return true;
}

if (oidc.session.past(oidc.params.max_age)) {
if (oidc.session.past(oidc.params.max_age) && (!ctx.oidc.result || !ctx.oidc.result.login)) {
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion docs/update-configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ const props = [
case 'undefined':
case 'object': {
let output;
if (block === 'interactions') {
if (block === 'interactions.policy') {
output = readFileSync('./docs/checks.txt');
}
output = output || inspect(value, { compact: false, sorted: true });
Expand Down
6 changes: 4 additions & 2 deletions lib/actions/authorization/interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ module.exports = async function interactions(resumeRouteName, ctx, next) {
let failedCheck;
let prompt;

for (const { name, checks, details: promptDetails } of instance(oidc.provider).configuration('interactions')) {
const { policy, url: interactionUrl } = instance(oidc.provider).configuration('interactions');

for (const { name, checks, details: promptDetails } of policy) {
let results = (await Promise.all([...checks].map(async ({
reason, description, error, details, check,
}) => {
Expand Down Expand Up @@ -114,7 +116,7 @@ module.exports = async function interactions(resumeRouteName, ctx, next) {

await interactionSession.save(cookieOptions.maxAge / 1000);

const destination = await instance(oidc.provider).configuration('interactionUrl')(ctx, interactionSession);
const destination = await interactionUrl(ctx, interactionSession);

ctx.cookies.set(
oidc.provider.cookieName('interaction'),
Expand Down
8 changes: 2 additions & 6 deletions lib/helpers/client_schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,7 @@ module.exports = function getSchema(provider) {
}
}

const responseTypes = _.chain(this.response_types)
.map(rt => rt.split(' '))
.flatten()
.uniq()
.value();
const responseTypes = [...new Set(this.response_types.map(rt => rt.split(' ')).flat(1))];

if (this.grant_types.some(type => ['authorization_code', 'implicit'].includes(type)) && !this.response_types.length) {
invalidate('response_types must contain members');
Expand Down Expand Up @@ -394,7 +390,7 @@ module.exports = function getSchema(provider) {
if (!Array.isArray(this[prop])) {
invalidate(`${prop} must be an array`);
}
this[prop] = _.uniq(this[prop]);
this[prop] = [...new Set(this[prop])];
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ module.exports = class Configuration {

collectPrompts() {
this.prompts = new Set(['none']);
this.interactions.forEach(({ name, requestable }) => {
this.interactions.policy.forEach(({ name, requestable }) => {
if (requestable) {
this.prompts.add(name);
}
Expand Down
62 changes: 34 additions & 28 deletions lib/helpers/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { DEV_KEYSTORE } = require('../consts');

const attention = require('./attention');
const nanoid = require('./nanoid');
const { DEFAULT: defaultInteractions } = require('./interaction');
const { DEFAULT: defaultInteractions } = require('./interaction_policy');

const warned = new Set();
function shouldChange(name, msg) {
Expand Down Expand Up @@ -1714,37 +1714,43 @@ const DEFAULTS = {
</html>`;
},


/*
* interactions
*
* description: structure of Prompts and their checks formed by Prompt and Check class instances.
* The default you can modify and the classes are available under `Provider.interaction`.
*
* example: configuring prompts
* ```js
* const { interaction: { Prompt, Check, DEFAULT } } = require('oidc-provider');
*
* // DEFAULT.get(name) => returns a Prompt instance by its name
* // DEFAULT.remove(name) => removes a Prompt instance by its name
* // DEFAULT.add(prompt, index) => adds a Prompt instance to a specific index, default is to last index
*
* // prompt.checks.get(reason) => returns a Check instance by its reason
* // prompt.checks.remove(reason) => removes a Check instance by its reason
* // prompt.checks.add(check, index) => adds a Check instance to a specific index, default is to last index
* ```
* description: TODO
* @nodefault
*/
interactions: defaultInteractions,

interactions: {
/*
* interactions.policy
*
* description: structure of Prompts and their checks formed by Prompt and Check class instances.
* The default you can modify and the classes are available under `Provider.interactionPolicy`.
*
* example: configuring prompts
* ```js
* const { interactionPolicy: { Prompt, Check, DEFAULT } } = require('oidc-provider');
*
* // DEFAULT.get(name) => returns a Prompt instance by its name
* // DEFAULT.remove(name) => removes a Prompt instance by its name
* // DEFAULT.add(prompt, index) => adds a Prompt instance to a specific index, default is to last index
*
* // prompt.checks.get(reason) => returns a Check instance by its reason
* // prompt.checks.remove(reason) => removes a Check instance by its reason
* // prompt.checks.add(check, index) => adds a Check instance to a specific index, default is to last index
* ```
*/
policy: defaultInteractions,

/*
* interactionUrl
*
* description: Helper used by the OP to determine where to redirect User-Agent for necessary
* interaction, can return both absolute and relative urls
*/
async interactionUrl(ctx, interaction) { // eslint-disable-line no-unused-vars
shouldChange('interactionUrl', 'specify where the user interactions should take place');
return `/interaction/${ctx.oidc.uid}`;
/*
* interactions.url
*
* description: Helper used by the OP to determine where to redirect User-Agent for necessary
* interaction, can return both absolute and relative urls.
*/
async url(ctx, interaction) { // eslint-disable-line no-unused-vars
return `/interaction/${ctx.oidc.uid}`;
},
},


Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ const { DYNAMIC_SCOPE_LABEL } = require('./consts');
module.exports = Provider;
module.exports.errors = errors;
module.exports.DYNAMIC_SCOPE_LABEL = DYNAMIC_SCOPE_LABEL;
module.exports.interaction = require('./helpers/interaction');
module.exports.interactionPolicy = require('./helpers/interaction_policy');
4 changes: 2 additions & 2 deletions test/configuration/interaction_url.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ describe('pathFor related behaviors', () => {
},
});

const interactionUrl = await i(provider).configuration('interactionUrl')({
const url = await i(provider).configuration('interactions.url')({
oidc: {
uid: 'foobar',
},
});

expect(interactionUrl).to.equal('/interaction/foobar');
expect(url).to.equal('/interaction/foobar');
});
});
8 changes: 4 additions & 4 deletions test/core/basic/basic.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const { cloneDeep } = require('lodash');

const config = cloneDeep(require('../../default.config'));
const { Prompt, Check, DEFAULT } = require('../../../lib/helpers/interaction');
const { Prompt, Check, DEFAULT } = require('../../../lib/helpers/interaction_policy');

config.extraParams = ['triggerCustomFail'];
config.features = { requestUri: { enabled: false } };

config.interactions = cloneDeep(DEFAULT);
config.interactions = { policy: cloneDeep(DEFAULT) };

const check = new Check(
'reason_foo',
Expand All @@ -20,8 +20,8 @@ const check = new Check(
},
);

config.interactions[0].checks.push(check);
config.interactions.push(new Prompt({ name: 'unrequestable', requestable: false }));
config.interactions.policy[0].checks.push(check);
config.interactions.policy.push(new Prompt({ name: 'unrequestable', requestable: false }));

module.exports = {
config,
Expand Down
10 changes: 5 additions & 5 deletions test/interaction/interaction.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const { cloneDeep } = require('lodash');

const config = cloneDeep(require('../default.config'));
const { Check, Prompt, DEFAULT } = require('../../lib/helpers/interaction');
const { Check, Prompt, DEFAULT } = require('../../lib/helpers/interaction_policy');

config.extraParams = ['triggerCustomFail', 'triggerUnrequestable'];
config.features = { sessionManagement: { enabled: true } };

config.interactions = cloneDeep(DEFAULT);
config.interactions = { policy: cloneDeep(DEFAULT) };

const check = new Check(
'reason_foo',
Expand All @@ -20,9 +20,9 @@ const check = new Check(
},
);

config.interactions[0].checks.push(check);
config.interactions.push(new Prompt({ name: 'custom', requestable: true }));
config.interactions.unshift(new Prompt({ name: 'unrequestable', requestable: false }, new Check('un_foo', 'un_foo_desc', 'un_foo_err', (ctx) => {
config.interactions.policy[0].checks.push(check);
config.interactions.policy.push(new Prompt({ name: 'custom', requestable: true }));
config.interactions.policy.unshift(new Prompt({ name: 'unrequestable', requestable: false }, new Check('un_foo', 'un_foo_desc', 'un_foo_err', (ctx) => {
if (ctx.oidc.params.triggerUnrequestable && (!ctx.oidc.result || !('foo' in ctx.oidc.result))) {
return true;
}
Expand Down
5 changes: 2 additions & 3 deletions test/test_helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ const { parse } = require('url');
const path = require('path');
const querystring = require('querystring');

const _ = require('lodash');
const sinon = require('sinon');
const { agent: supertest } = require('supertest');
const { expect } = require('chai');
Expand Down Expand Up @@ -400,9 +399,9 @@ module.exports.passInteractionChecks = (...reasons) => {

context('', () => {
before(function () {
const { interactions } = i(this.provider).configuration();
const { policy } = i(this.provider).configuration('interactions');

const iChecks = _.flattenDeep([interactions.map(i => i.checks)]);
const iChecks = [policy.map(i => i.checks)].flat(Infinity);

iChecks
.filter(check => reasons.includes(check.reason))
Expand Down

0 comments on commit 1193719

Please sign in to comment.