Skip to content
This repository has been archived by the owner on Jul 31, 2021. It is now read-only.

Commit

Permalink
[MFA-311] Support guardian policies, phone selected-provider and mess…
Browse files Browse the repository at this point in the history
…age-types (#96)

* feat: add support for guardian policies

* feat: add support for guardian phone factor selected provider

* feat: add support for guardian phone factor message types

* chore: bump to v4.1.0
  • Loading branch information
pmalouin authored Jul 2, 2020
1 parent 60748e0 commit 64cb4b0
Show file tree
Hide file tree
Showing 11 changed files with 426 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "auth0-source-control-extension-tools",
"version": "4.0.7",
"version": "4.1.0",
"description": "Supporting tools for the Source Control extensions",
"main": "lib/index.js",
"scripts": {
Expand Down
52 changes: 52 additions & 0 deletions src/auth0/handlers/guardianPhoneFactorMessageTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import DefaultHandler from './default';
import constants from '../../constants';

export const schema = {
type: 'object',
properties: {
message_types: {
type: 'array',
items: {
type: 'string',
enum: constants.GUARDIAN_PHONE_MESSAGE_TYPES
}
}
},
required: [ 'message_types' ],
additionalProperties: false
};


export default class GuardianPhoneMessageTypesHandler extends DefaultHandler {
constructor(options) {
super({
...options,
type: 'guardianPhoneFactorMessageTypes'
});
}

async getType() {
// in case client version does not support the operation
if (!this.client.guardian || typeof this.client.guardian.getPhoneFactorMessageTypes !== 'function') {
return null;
}

if (this.existing) return this.existing;
this.existing = await this.client.guardian.getPhoneFactorMessageTypes();
return this.existing;
}

async processChanges(assets) {
// No API to delete or create guardianPhoneFactorMessageTypes, we can only update.
const { guardianPhoneFactorMessageTypes } = assets;

// Do nothing if not set
if (!guardianPhoneFactorMessageTypes) return;

const params = {};
const data = guardianPhoneFactorMessageTypes;
await this.client.guardian.updatePhoneFactorMessageTypes(params, data);
this.updated += 1;
this.didUpdate(guardianPhoneFactorMessageTypes);
}
}
49 changes: 49 additions & 0 deletions src/auth0/handlers/guardianPhoneFactorSelectedProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import DefaultHandler from './default';
import constants from '../../constants';

export const schema = {
type: 'object',
properties: {
provider: {
type: 'string',
enum: constants.GUARDIAN_PHONE_PROVIDERS
}
},
required: [ 'provider' ],
additionalProperties: false
};


export default class GuardianPhoneSelectedProviderHandler extends DefaultHandler {
constructor(options) {
super({
...options,
type: 'guardianPhoneFactorSelectedProvider'
});
}

async getType() {
// in case client version does not support the operation
if (!this.client.guardian || typeof this.client.guardian.getPhoneFactorSelectedProvider !== 'function') {
return null;
}

if (this.existing) return this.existing;
this.existing = await this.client.guardian.getPhoneFactorSelectedProvider();
return this.existing;
}

async processChanges(assets) {
// No API to delete or create guardianPhoneFactorSelectedProvider, we can only update.
const { guardianPhoneFactorSelectedProvider } = assets;

// Do nothing if not set
if (!guardianPhoneFactorSelectedProvider) return;

const params = {};
const data = guardianPhoneFactorSelectedProvider;
await this.client.guardian.updatePhoneFactorSelectedProvider(params, data);
this.updated += 1;
this.didUpdate(guardianPhoneFactorSelectedProvider);
}
}
47 changes: 47 additions & 0 deletions src/auth0/handlers/guardianPolicies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import DefaultHandler from './default';
import constants from '../../constants';

export const schema = {
type: 'array',
items: {
type: 'string',
enum: constants.GUARDIAN_POLICIES
},
minLength: 0,
maxLength: 1
};


export default class GuardianPoliciesHandler extends DefaultHandler {
constructor(options) {
super({
...options,
type: 'guardianPolicies'
});
}

async getType() {
// in case client version does not support the operation
if (!this.client.guardian || typeof this.client.guardian.getPolicies !== 'function') {
return null;
}

if (this.existing) return this.existing;
this.existing = await this.client.guardian.getPolicies();
return this.existing;
}

async processChanges(assets) {
// No API to delete or create guardianPolicies, we can only update.
const { guardianPolicies } = assets;

// Do nothing if not set
if (!guardianPolicies) return;

const params = {};
const data = guardianPolicies;
await this.client.guardian.updatePolicies(params, data);
this.updated += 1;
this.didUpdate(guardianPolicies);
}
}
6 changes: 6 additions & 0 deletions src/auth0/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import * as clientGrants from './clientGrants';
import * as guardianFactors from './guardianFactors';
import * as guardianFactorProviders from './guardianFactorProviders';
import * as guardianFactorTemplates from './guardianFactorTemplates';
import * as guardianPolicies from './guardianPolicies';
import * as guardianPhoneFactorSelectedProvider from './guardianPhoneFactorSelectedProvider';
import * as guardianPhoneFactorMessageTypes from './guardianPhoneFactorMessageTypes';
import * as roles from './roles';
import * as branding from './branding';
import * as prompts from './prompts';
Expand All @@ -33,6 +36,9 @@ export {
guardianFactors,
guardianFactorProviders,
guardianFactorTemplates,
guardianPolicies,
guardianPhoneFactorSelectedProvider,
guardianPhoneFactorMessageTypes,
roles,
branding,
prompts
Expand Down
13 changes: 13 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ constants.GUARDIAN_FACTORS = [
'email',
'duo'
];
constants.GUARDIAN_POLICIES = [
'all-applications',
'confidence-score'
];
constants.GUARDIAN_PHONE_PROVIDERS = [
'auth0',
'twilio',
'phone-message-hook'
];
constants.GUARDIAN_PHONE_MESSAGE_TYPES = [
'sms',
'voice'
];

constants.GUARDIAN_FACTOR_TEMPLATES = [
'sms'
Expand Down
68 changes: 68 additions & 0 deletions tests/auth0/handlers/guardianPhoneFactorMessageTypes.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { expect } = require('chai');
const guardianPhoneFactorMessageTypes = require('../../../src/auth0/handlers/guardianPhoneFactorMessageTypes');

describe('#guardianPhoneFactorMessageTypes handler', () => {
describe('#getType', () => {
it('should support older version of auth0 client', async () => {
const auth0 = {
guardian: {
// omitting getPhoneFactorMessageTypes()
}
};

const handler = new guardianPhoneFactorMessageTypes.default({ client: auth0 });
const data = await handler.getType();
expect(data).to.deep.equal(null);
});

it('should get guardian phone factor message types', async () => {
const auth0 = {
guardian: {
getPhoneFactorMessageTypes: () => ({ message_types: [ 'sms', 'voice' ] })
}
};

const handler = new guardianPhoneFactorMessageTypes.default({ client: auth0 });
const data = await handler.getType();
expect(data).to.deep.equal({ message_types: [ 'sms', 'voice' ] });
});
});

describe('#processChanges', () => {
it('should update guardian phone factor message types', async () => {
const auth0 = {
guardian: {
updatePhoneFactorMessageTypes: (params, data) => {
expect(data).to.eql({ message_types: [ 'sms', 'voice' ] });
return Promise.resolve(data);
}
}
};

const handler = new guardianPhoneFactorMessageTypes.default({ client: auth0 });
const stageFn = Object.getPrototypeOf(handler).processChanges;

await stageFn.apply(handler, [
{ guardianPhoneFactorMessageTypes: { message_types: [ 'sms', 'voice' ] } }
]);
});

it('should skip processing if assets are empty', async () => {
const auth0 = {
guardian: {
updatePhoneFactorMessageTypes: () => {
const err = new Error('updatePhoneFactorMessageTypes() should not have been called');
return Promise.reject(err);
}
}
};

const handler = new guardianPhoneFactorMessageTypes.default({ client: auth0 });
const stageFn = Object.getPrototypeOf(handler).processChanges;

await stageFn.apply(handler, [
{ guardianPhoneFactorMessageTypes: null }
]);
});
});
});
68 changes: 68 additions & 0 deletions tests/auth0/handlers/guardianPhoneFactorSelectedProvider.tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { expect } = require('chai');
const guardianPhoneFactorSelectedProvider = require('../../../src/auth0/handlers/guardianPhoneFactorSelectedProvider');

describe('#guardianPhoneFactorSelectedProvider handler', () => {
describe('#getType', () => {
it('should support older version of auth0 client', async () => {
const auth0 = {
guardian: {
// omitting getPhoneFactorSelectedProvider()
}
};

const handler = new guardianPhoneFactorSelectedProvider.default({ client: auth0 });
const data = await handler.getType();
expect(data).to.deep.equal(null);
});

it('should get guardian phone factor selected provider', async () => {
const auth0 = {
guardian: {
getPhoneFactorSelectedProvider: () => ({ provider: 'twilio' })
}
};

const handler = new guardianPhoneFactorSelectedProvider.default({ client: auth0 });
const data = await handler.getType();
expect(data).to.deep.equal({ provider: 'twilio' });
});
});

describe('#processChanges', () => {
it('should update guardian phone factor selected provider', async () => {
const auth0 = {
guardian: {
updatePhoneFactorSelectedProvider: (params, data) => {
expect(data).to.eql({ provider: 'twilio' });
return Promise.resolve(data);
}
}
};

const handler = new guardianPhoneFactorSelectedProvider.default({ client: auth0 });
const stageFn = Object.getPrototypeOf(handler).processChanges;

await stageFn.apply(handler, [
{ guardianPhoneFactorSelectedProvider: { provider: 'twilio' } }
]);
});

it('should skip processing if assets are empty', async () => {
const auth0 = {
guardian: {
updatePhoneFactorSelectedProvider: () => {
const err = new Error('updatePhoneFactorSelectedProvider() should not have been called');
return Promise.reject(err);
}
}
};

const handler = new guardianPhoneFactorSelectedProvider.default({ client: auth0 });
const stageFn = Object.getPrototypeOf(handler).processChanges;

await stageFn.apply(handler, [
{ guardianPhoneFactorSelectedProvider: null }
]);
});
});
});
Loading

0 comments on commit 64cb4b0

Please sign in to comment.