Merge pull request #557 from hashicorp/feature-oidc-state-change
feat: 🎸 add OIDC change state custom method
This commit is contained in:
4 files changed
+167
-2
No files matched your search
@@ -44,4 +44,29 @@ export default class AuthMethodModel extends GeneratedAuthMethodModel {
|
||||
get isOIDC() {
|
||||
return this.type === 'oidc';
|
||||
}
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Change the active and visibility state of an OIDC auth method
|
||||
* given its ID.
|
||||
* For OIDC auth methods only.
|
||||
* @param {[string]} state
|
||||
* @param {object} options
|
||||
* @param {object} options.adapterOptions
|
||||
* @return {Promise}
|
||||
*/
|
||||
changeState(state, options = { adapterOptions: {} }) {
|
||||
const defaultAdapterOptions = {
|
||||
method: 'change-state',
|
||||
state,
|
||||
};
|
||||
return this.save({
|
||||
...options,
|
||||
adapterOptions: {
|
||||
...defaultAdapterOptions,
|
||||
...options.adapterOptions,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,63 @@
|
||||
import ApplicationSerializer from './application';
|
||||
|
||||
export default class AuthMethodSerializer extends ApplicationSerializer {
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Delegates to a type-specific serialization, or default.
|
||||
* @override
|
||||
* @param {Snapshot} snapshot
|
||||
* @return {object}
|
||||
*/
|
||||
serialize(snapshot) {
|
||||
switch (snapshot.record.type) {
|
||||
case 'oidc':
|
||||
return this.serializeOIDC(...arguments);
|
||||
default:
|
||||
return this.serializeDefault(...arguments);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default serialization omits `attributes`.
|
||||
* @return {object}
|
||||
*/
|
||||
serializeDefault() {
|
||||
let serialized = super.serialize(...arguments);
|
||||
delete serialized.attributes;
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* If `adapterOptions.state` is set, the serialization should
|
||||
* include **only state** and version. Normally, this is not serialized.
|
||||
* @param {Snapshot} snapshot
|
||||
* @return {object}
|
||||
*/
|
||||
serializeOIDC(snapshot) {
|
||||
let serialized = super.serialize(...arguments);
|
||||
const state = snapshot?.adapterOptions?.state;
|
||||
if (state) {
|
||||
serialized = this.serializeOIDCWithState(snapshot, state);
|
||||
} else {
|
||||
delete serialized.attributes.state;
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a payload containing only state and version.
|
||||
* @param {Snapshot} snapshot
|
||||
* @param {string} state
|
||||
* @return {object}
|
||||
*/
|
||||
serializeOIDCWithState(snapshot, state) {
|
||||
return {
|
||||
version: snapshot.attr('version'),
|
||||
attributes: { state },
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the array in order of "is_primary" such that the primary method
|
||||
* appears first. The "natural" order of auth methods places primary first.
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
|
||||
module('Unit | Model | auth method', function (hooks) {
|
||||
setupTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
// Replace this with your real tests.
|
||||
test('it exists', function (assert) {
|
||||
@@ -10,4 +12,39 @@ module('Unit | Model | auth method', function (hooks) {
|
||||
let model = store.createRecord('auth-method', {});
|
||||
assert.ok(model);
|
||||
});
|
||||
|
||||
test('it has a `changeState` method that targets a specific POST API endpoint and serialization', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.server.post(
|
||||
'/v1/auth-methods/123abc:change-state',
|
||||
(schema, request) => {
|
||||
const body = JSON.parse(request.requestBody);
|
||||
assert.deepEqual(body, {
|
||||
attributes: {
|
||||
state: 'foobar',
|
||||
},
|
||||
version: 1,
|
||||
});
|
||||
return { id: '123abc' };
|
||||
}
|
||||
);
|
||||
const store = this.owner.lookup('service:store');
|
||||
store.push({
|
||||
data: {
|
||||
id: '123abc',
|
||||
type: 'auth-method',
|
||||
attributes: {
|
||||
type: 'oidc',
|
||||
state: 'foobar',
|
||||
version: 1,
|
||||
scope: {
|
||||
scope_id: 'o_1',
|
||||
type: 'scope',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const model = store.peekRecord('auth-method', '123abc');
|
||||
await model.changeState('foobar');
|
||||
});
|
||||
});
|
||||
@@ -12,13 +12,59 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
assert.ok(serializer);
|
||||
});
|
||||
|
||||
test('it serializes records', function (assert) {
|
||||
test('it serializes password records', function (assert) {
|
||||
assert.expect(2);
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('auth-method', {});
|
||||
let record = store.createRecord('auth-method', { type: 'password' });
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
assert.notOk(
|
||||
serializedRecord.attributes,
|
||||
'Password should not have attributes'
|
||||
);
|
||||
});
|
||||
|
||||
test('it serializes OIDC records without state', function (assert) {
|
||||
assert.expect(3);
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('auth-method', {
|
||||
type: 'oidc',
|
||||
attributes: {
|
||||
state: 'foo',
|
||||
},
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.ok(serializedRecord);
|
||||
assert.ok(serializedRecord.attributes, 'OIDC should have attributes');
|
||||
assert.notOk(serializedRecord.attributes.state);
|
||||
});
|
||||
|
||||
test('it serializes OIDC records with only state and version when `adapterOptions.state` is passed', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('auth-method');
|
||||
const record = store.createRecord('auth-method', {
|
||||
type: 'oidc',
|
||||
attributes: {
|
||||
state: 'foo',
|
||||
},
|
||||
version: 1,
|
||||
});
|
||||
const snapshot = record._createSnapshot();
|
||||
snapshot.adapterOptions = {
|
||||
state: 'bar',
|
||||
};
|
||||
const serializedRecord = serializer.serialize(snapshot);
|
||||
assert.deepEqual(serializedRecord, {
|
||||
attributes: {
|
||||
state: 'bar',
|
||||
},
|
||||
version: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test('it sorts primary first in normalizeArrayResponse', function (assert) {
|
||||
|
||||
Reference in new issue
Block a user