Icu 6794 refactor attributes using the newer is nested attribute annotation (#1481)
This commit is contained in:
1 parent
ff6e2bb4cf
commit
ff7a1fedea
15 files changed
+325
-259
No files matched your search
@@ -49,4 +49,26 @@ export default class GeneratedAuthMethodModel extends BaseModel {
|
||||
description: 'Current version number of this resource.',
|
||||
})
|
||||
version;
|
||||
|
||||
@attr('string', { readOnly: true, isNestedAttribute: true }) state;
|
||||
|
||||
@attr('string', { isNestedAttribute: true }) issuer;
|
||||
|
||||
@attr('string', { isNestedAttribute: true }) client_id;
|
||||
|
||||
@attr('string', { isNestedAttribute: true }) client_secret;
|
||||
|
||||
@attr('string', { readOnly: true, isNestedAttribute: true })
|
||||
client_secret_hmac;
|
||||
|
||||
@attr('number', { isNestedAttribute: true }) max_age;
|
||||
|
||||
@attr('string', { isNestedAttribute: true }) api_url_prefix;
|
||||
|
||||
@attr('string', { readOnly: true, isNestedAttribute: true }) callback_url;
|
||||
|
||||
@attr('boolean', { isNestedAttribute: true })
|
||||
disable_discovered_config_validation;
|
||||
|
||||
@attr('boolean', { isNestedAttribute: true }) dry_run;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import GeneratedAuthMethodModel from '../generated/models/auth-method';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { fragment } from 'ember-data-model-fragments/attributes';
|
||||
import { fragmentArray } from 'ember-data-model-fragments/attributes';
|
||||
import { equal } from '@ember/object/computed';
|
||||
|
||||
/**
|
||||
@@ -28,33 +27,37 @@ export const options = {
|
||||
};
|
||||
|
||||
export default class AuthMethodModel extends GeneratedAuthMethodModel {
|
||||
// =error attributes
|
||||
// These attributes exist solely to capture errors on nested fields.
|
||||
// See the application adapter's error normalization method for
|
||||
// more information.
|
||||
|
||||
@attr('string', { readOnly: true }) attributes_state;
|
||||
@attr('string', { readOnly: true }) attributes_issuer;
|
||||
@attr('string', { readOnly: true }) attributes_client_id;
|
||||
@attr('string', { readOnly: true }) attributes_client_secret;
|
||||
@attr('string', { readOnly: true }) attributes_max_age;
|
||||
@attr('string', { readOnly: true }) attributes_api_url_prefix;
|
||||
@attr('string', { readOnly: true })
|
||||
attributes_disable_discovered_config_validation;
|
||||
@attr('string', { readOnly: true }) attributes_dry_run;
|
||||
@attr('string', { readOnly: true }) attributes_account_claim_maps;
|
||||
@attr('string', { readOnly: true }) attributes_claims_scopes;
|
||||
@attr('string', { readOnly: true }) attributes_signing_algorithms;
|
||||
@attr('string', { readOnly: true }) attributes_allowed_audiences;
|
||||
@attr('string', { readOnly: true }) attributes_idp_ca_certs;
|
||||
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* Attributes of this resource, if any, represented as a JSON fragment.
|
||||
* @type {FragmentAuthMethodAttributesModel}
|
||||
*/
|
||||
@fragment('fragment-auth-method-attributes', { defaultValue: {} }) attributes;
|
||||
@fragmentArray('fragment-auth-method-attributes-account-claim-map', {
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
account_claim_maps;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
claims_scopes;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
signing_algorithms;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
allowed_audiences;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
idp_ca_certs;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
@@ -81,21 +84,21 @@ export default class AuthMethodModel extends GeneratedAuthMethodModel {
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isInactive() {
|
||||
return this.attributes.state === 'inactive';
|
||||
return this.state === 'inactive';
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPrivate() {
|
||||
return this.attributes.state === 'active-private';
|
||||
return this.state === 'active-private';
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPublic() {
|
||||
return this.attributes.state === 'active-public';
|
||||
return this.state === 'active-public';
|
||||
}
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import Fragment from 'ember-data-model-fragments/fragment';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { fragmentArray } from 'ember-data-model-fragments/attributes';
|
||||
|
||||
export default class FragmentAuthMethodAttributesModel extends Fragment {
|
||||
// =attributes (OIDC)
|
||||
|
||||
@attr('string', { readOnly: true }) state;
|
||||
@attr('string') issuer;
|
||||
@attr('string') client_id;
|
||||
@attr('string') client_secret;
|
||||
@attr('string', { readOnly: true }) client_secret_hmac;
|
||||
@attr('number') max_age;
|
||||
@attr('string') api_url_prefix;
|
||||
@attr('string', { readOnly: true }) callback_url;
|
||||
@attr('boolean') disable_discovered_config_validation;
|
||||
@attr('boolean') dry_run;
|
||||
|
||||
@fragmentArray('fragment-auth-method-attributes-account-claim-map', {
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
account_claim_maps;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
claims_scopes;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
signing_algorithms;
|
||||
|
||||
@fragmentArray('fragment-string', {
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
allowed_audiences;
|
||||
|
||||
@fragmentArray('fragment-string', { emptyArrayIfMissing: true }) idp_ca_certs;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import JSONSerializer from '@ember-data/serializer/json';
|
||||
|
||||
export default class FragmentAuthMethodAttributesSerializer extends JSONSerializer {
|
||||
/**
|
||||
* If an attribute is annotated as readOnly in the model, don't serialize it.
|
||||
* Otherwise delegate to default attribute serializer.
|
||||
*
|
||||
* @override
|
||||
* @method serializeAttribute
|
||||
* @param {Snapshot} snapshot
|
||||
* @param {Object} json
|
||||
* @param {String} key
|
||||
* @param {Object} attribute
|
||||
*/
|
||||
serializeAttribute(snapshot, json, key, attribute) {
|
||||
const { type, options } = attribute;
|
||||
let value = super.serializeAttribute(...arguments);
|
||||
// Convert empty strings to null.
|
||||
if (type === 'string' && json[key] === '') json[key] = null;
|
||||
// Do not serialize read-only attributes.
|
||||
if (options.readOnly) delete json[key];
|
||||
// Client secret cannot be unset. If it's falsy, it must be removed.
|
||||
if (key === 'client_secret' && !json[key]) delete json[key];
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from 'api/models/fragment-auth-method-attributes';
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from 'api/serializers/fragment-auth-method-attributes';
|
||||
@@ -1,12 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Model | fragment auth method attributes', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let model = store.createRecord('fragment-auth-method-attributes', {});
|
||||
assert.ok(model);
|
||||
});
|
||||
});
|
||||
@@ -33,27 +33,25 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
let record = store.createRecord('auth-method', {
|
||||
type: 'oidc',
|
||||
name: 'OIDC Auth Method',
|
||||
attributes: {
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
{ value: 'www.alice.com' },
|
||||
{ value: 'www.alice.com/admin' },
|
||||
],
|
||||
idp_ca_certs: [
|
||||
{ value: 'certificate-1234' },
|
||||
{ value: 'certificate-5678' },
|
||||
],
|
||||
api_url_prefix: 'protocol://host:port/foo',
|
||||
client_id: 'id123',
|
||||
client_secret: 'secret456',
|
||||
disable_discovered_config_validation: true,
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
},
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
{ value: 'www.alice.com' },
|
||||
{ value: 'www.alice.com/admin' },
|
||||
],
|
||||
idp_ca_certs: [
|
||||
{ value: 'certificate-1234' },
|
||||
{ value: 'certificate-5678' },
|
||||
],
|
||||
api_url_prefix: 'protocol://host:port/foo',
|
||||
client_id: 'id123',
|
||||
client_secret: 'secret456',
|
||||
disable_discovered_config_validation: true,
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
@@ -148,19 +146,56 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
|
||||
test('it normalizes OIDC records', async function (assert) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
|
||||
const apiUrlPrefix = 'protocol://host:port/foo';
|
||||
const clientId = 'id123';
|
||||
const clientSecret = 'secret456';
|
||||
const disableDiscoveredConfigValidation = true;
|
||||
const dryRun = true;
|
||||
const issuer = 'http://www.example.net';
|
||||
const maxAge = 500;
|
||||
this.server.get('/v1/auth-methods/oidc123', () => ({
|
||||
attributes: {
|
||||
account_claim_maps: ['from=to', 'foo=bar'],
|
||||
claims_scopes: [{ value: 'profile' }, { value: 'email' }],
|
||||
signing_algorithms: [{ value: 'RS256' }, { value: 'RS384' }],
|
||||
allowed_audiences: [
|
||||
{ value: 'www.alice.com' },
|
||||
{ value: 'www.alice.com/admin' },
|
||||
],
|
||||
idp_ca_certs: [
|
||||
{ value: 'certificate-1234' },
|
||||
{ value: 'certificate-5678' },
|
||||
],
|
||||
api_url_prefix: apiUrlPrefix,
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
disable_discovered_config_validation: disableDiscoveredConfigValidation,
|
||||
dry_run: dryRun,
|
||||
issuer: issuer,
|
||||
max_age: maxAge,
|
||||
},
|
||||
version: 1,
|
||||
type: 'oidc',
|
||||
id: 'oidc123',
|
||||
}));
|
||||
|
||||
const record = await store.findRecord('auth-method', 'oidc123');
|
||||
const { account_claim_maps } = record.attributes;
|
||||
const { account_claim_maps } = record;
|
||||
|
||||
assert.strictEqual(account_claim_maps.firstObject.from, 'from');
|
||||
assert.strictEqual(account_claim_maps.firstObject.to, 'to');
|
||||
assert.strictEqual(account_claim_maps.lastObject.from, 'foo');
|
||||
assert.strictEqual(account_claim_maps.lastObject.to, 'bar');
|
||||
assert.strictEqual(record.api_url_prefix, apiUrlPrefix);
|
||||
assert.strictEqual(record.client_id, clientId);
|
||||
assert.strictEqual(record.client_secret, clientSecret);
|
||||
assert.strictEqual(
|
||||
record.disable_discovered_config_validation,
|
||||
disableDiscoveredConfigValidation
|
||||
);
|
||||
assert.strictEqual(record.dry_run, dryRun);
|
||||
assert.strictEqual(record.issuer, issuer);
|
||||
assert.strictEqual(record.max_age, maxAge);
|
||||
});
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
|
||||
module('Unit | Serializer | fragment auth method attributes', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
test('it serializes empty strings to null', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const record = store.createRecord('user', {
|
||||
name: '',
|
||||
description: '',
|
||||
version: null,
|
||||
});
|
||||
let serializedRecord = record.serialize();
|
||||
assert.deepEqual(serializedRecord, {
|
||||
name: null,
|
||||
description: null,
|
||||
});
|
||||
});
|
||||
|
||||
test('it does not serialize client_secret if present but falsy', function (assert) {
|
||||
assert.expect(1);
|
||||
const store = this.owner.lookup('service:store');
|
||||
const record = store.createRecord('user', {
|
||||
name: '',
|
||||
description: '',
|
||||
version: null,
|
||||
client_secret: false,
|
||||
});
|
||||
let serializedRecord = record.serialize();
|
||||
assert.deepEqual(serializedRecord, {
|
||||
name: null,
|
||||
description: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{{#if @model.isOIDC}}
|
||||
<Rose::Dropdown
|
||||
@text={{t (concat 'states.' @model.attributes.state)}}
|
||||
@text={{t (concat 'states.' @model.state)}}
|
||||
@icon={{if
|
||||
@model.isInactive
|
||||
'flight-icons/svg/x-circle-16'
|
||||
@@ -17,7 +17,7 @@
|
||||
<Rose::Form as |form|>
|
||||
<form.radioGroup
|
||||
@name='theme'
|
||||
@selectedValue={{@model.attributes.state}}
|
||||
@selectedValue={{@model.state}}
|
||||
@changed={{route-action 'changeState'}}
|
||||
as |radioGroup|
|
||||
>
|
||||
|
||||
@@ -59,16 +59,16 @@
|
||||
<form.input
|
||||
@name='issuer'
|
||||
@type='text'
|
||||
@value={{@model.attributes.issuer}}
|
||||
@value={{@model.issuer}}
|
||||
@label={{t 'form.issuer.label'}}
|
||||
@helperText={{t 'form.issuer.help'}}
|
||||
@error={{@model.errors.attributes_issuer}}
|
||||
@error={{@model.errors.issuer}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.attributes_issuer}}
|
||||
{{#if @model.errors.issuer}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.attributes_issuer as |error|}}
|
||||
{{#each @model.errors.issuer as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
@@ -78,26 +78,26 @@
|
||||
<form.checkbox
|
||||
@label={{t 'form.disable_discovered_config_validation.label'}}
|
||||
@helperText={{t 'form.disable_discovered_config_validation.help'}}
|
||||
@checked={{@model.attributes.disable_discovered_config_validation}}
|
||||
@checked={{@model.disable_discovered_config_validation}}
|
||||
@onChange={{fn
|
||||
(mut @model.attributes.disable_discovered_config_validation)
|
||||
(if @model.attributes.disable_discovered_config_validation false true)
|
||||
(mut @model.disable_discovered_config_validation)
|
||||
(if @model.disable_discovered_config_validation false true)
|
||||
}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='client_id'
|
||||
@type='text'
|
||||
@value={{@model.attributes.client_id}}
|
||||
@value={{@model.client_id}}
|
||||
@label={{t 'form.client_id.label'}}
|
||||
@helperText={{t 'form.client_id.help'}}
|
||||
@error={{@model.errors.attributes_client_id}}
|
||||
@error={{@model.errors.client_id}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.attributes_client_id}}
|
||||
{{#if @model.errors.client_id}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.attributes_client_id as |error|}}
|
||||
{{#each @model.errors.client_id as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
@@ -107,16 +107,16 @@
|
||||
<form.input
|
||||
@name='client_secret'
|
||||
@type='password'
|
||||
@value={{@model.attributes.client_secret}}
|
||||
@value={{@model.client_secret}}
|
||||
@label={{t 'form.client_secret.label'}}
|
||||
@helperText={{t 'form.client_secret.help'}}
|
||||
@error={{@model.errors.attributes_client_secret}}
|
||||
@error={{@model.errors.client_secret}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.attributes_client_secret}}
|
||||
{{#if @model.errors.client_secret}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.attributes_client_secret as |error|}}
|
||||
{{#each @model.errors.client_secret as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
@@ -125,7 +125,7 @@
|
||||
|
||||
{{#unless @model.isNew}}
|
||||
<form.input
|
||||
@value={{@model.attributes.client_secret_hmac}}
|
||||
@value={{@model.client_secret_hmac}}
|
||||
@label={{t 'form.client_secret_hmac.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
@@ -137,9 +137,9 @@
|
||||
<:title>{{t 'form.signing_algorithms.label'}}</:title>
|
||||
<:description>{{t 'form.signing_algorithms.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.attributes_signing_algorithms}}
|
||||
{{#if @model.errors.signing_algorithms}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.attributes_signing_algorithms as |error|}}
|
||||
{{#each @model.errors.signing_algorithms as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
@@ -152,13 +152,13 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.attributes.signing_algorithms as |algorithm i|}}
|
||||
{{#each @model.signing_algorithms as |algorithm i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
|
||||
<Hds::Form::Select::Field
|
||||
@value={{algorithm.value}}
|
||||
@isInvalid={{@model.errors.attributes_signing_algorithms}}
|
||||
@isInvalid={{@model.errors.signing_algorithms}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' (set-from-event algorithm 'value')}}
|
||||
as |F|
|
||||
@@ -187,10 +187,7 @@
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'attributes.signing_algorithms' i)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'signing_algorithms' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
@@ -233,9 +230,7 @@
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'attributes.signing_algorithms'
|
||||
this.newSigningAlgorithm
|
||||
@addStringItem 'signing_algorithms' this.newSigningAlgorithm
|
||||
)
|
||||
}}
|
||||
>
|
||||
@@ -253,9 +248,9 @@
|
||||
<:title>{{t 'form.allowed_audiences.label'}}</:title>
|
||||
<:description>{{t 'form.allowed_audiences.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.attributes_allowed_audiences}}
|
||||
{{#if @model.errors.allowed_audiences}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.attributes_allowed_audiences as |error|}}
|
||||
{{#each @model.errors.allowed_audiences as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
@@ -268,13 +263,14 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.attributes.allowed_audiences as |audience i|}}
|
||||
{{#each @model.allowed_audiences as |audience i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='allowed_audiences'
|
||||
@value={{audience.value}}
|
||||
@error={{@model.errors.attributes_allowed_audiences}}
|
||||
@error={{@model.errors.allowed_audiences}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
@@ -292,10 +288,7 @@
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'attributes.allowed_audiences' i)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'allowed_audiences' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
@@ -307,6 +300,7 @@
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='allowed_audiences'
|
||||
@value={{this.newAllowedAudience}}
|
||||
@label={{t 'resources.auth-method.titles.new-allowed-audience'}}
|
||||
/>
|
||||
@@ -323,9 +317,7 @@
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'attributes.allowed_audiences'
|
||||
this.newAllowedAudience
|
||||
@addStringItem 'allowed_audiences' this.newAllowedAudience
|
||||
)
|
||||
}}
|
||||
>
|
||||
@@ -343,9 +335,9 @@
|
||||
<:title>{{t 'form.claims_scopes.label'}}</:title>
|
||||
<:description>{{t 'form.claims_scopes.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.attributes_claims_scopes}}
|
||||
{{#if @model.errors.claims_scopes}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.attributes_claims_scopes as |error|}}
|
||||
{{#each @model.errors.claims_scopes as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
@@ -358,13 +350,14 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.attributes.claims_scopes as |claimsScope i|}}
|
||||
{{#each @model.claims_scopes as |claimsScope i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='claims_scopes'
|
||||
@value={{claimsScope.value}}
|
||||
@error={{@model.errors.attributes_claims_scopes}}
|
||||
@error={{@model.errors.claims_scopes}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
@@ -382,10 +375,7 @@
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'attributes.claims_scopes' i)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'claims_scopes' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
@@ -397,6 +387,7 @@
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='claims_scopes'
|
||||
@value={{this.newClaimsScope}}
|
||||
@label={{t 'resources.auth-method.titles.new-claims-scope'}}
|
||||
/>
|
||||
@@ -412,11 +403,7 @@
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem
|
||||
'attributes.claims_scopes'
|
||||
this.newClaimsScope
|
||||
)
|
||||
(fn @addStringItem 'claims_scopes' this.newClaimsScope)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
@@ -433,9 +420,9 @@
|
||||
<:title>{{t 'form.account_claim_maps.label'}}</:title>
|
||||
<:description>{{t 'form.account_claim_maps.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.attributes_account_claim_maps}}
|
||||
{{#if @model.errors.account_claim_maps}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.attributes_account_claim_maps as |error|}}
|
||||
{{#each @model.errors.account_claim_maps as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
@@ -449,13 +436,14 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.attributes.account_claim_maps as |claimMap i|}}
|
||||
{{#each @model.account_claim_maps as |claimMap i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='from_claim'
|
||||
@value={{claimMap.from}}
|
||||
@error={{@model.errors.attributes_account_claim_maps}}
|
||||
@error={{@model.errors.account_claim_maps}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
@@ -467,7 +455,7 @@
|
||||
|
||||
<Hds::Form::Select::Field
|
||||
@value={{claimMap.to}}
|
||||
@isInvalid={{@model.errors.attributes_account_claim_maps}}
|
||||
@isInvalid={{@model.errors.account_claim_maps}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' (set-from-event claimMap 'to')}}
|
||||
as |F|
|
||||
@@ -494,10 +482,7 @@
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'attributes.account_claim_maps' i)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'account_claim_maps' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
@@ -509,6 +494,7 @@
|
||||
<row.cell>
|
||||
<form.input
|
||||
@type='text'
|
||||
@name='from_claim'
|
||||
@value={{this.newFromClaim}}
|
||||
@label={{t 'resources.auth-method.titles.new-from-claim'}}
|
||||
/>
|
||||
@@ -563,9 +549,9 @@
|
||||
<:title>{{t 'form.idp_ca_certs.label'}}</:title>
|
||||
<:description>{{t 'form.idp_ca_certs.help'}}</:description>
|
||||
<:body>
|
||||
{{#if @model.errors.attributes_idp_ca_certs}}
|
||||
{{#if @model.errors.idp_ca_certs}}
|
||||
<Rose::Form::Errors as |errors|>
|
||||
{{#each @model.errors.attributes_idp_ca_certs as |error|}}
|
||||
{{#each @model.errors.idp_ca_certs as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</Rose::Form::Errors>
|
||||
@@ -578,12 +564,12 @@
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.attributes.idp_ca_certs as |cert i|}}
|
||||
{{#each @model.idp_ca_certs as |cert i|}}
|
||||
<body.row as |row|>
|
||||
<row.cell>
|
||||
<form.textarea
|
||||
@value={{cert.value}}
|
||||
@error={{@model.errors.attributes_idp_ca_certs}}
|
||||
@error={{@model.errors.idp_ca_certs}}
|
||||
@contextual={{true}}
|
||||
as |field|
|
||||
>
|
||||
@@ -601,10 +587,7 @@
|
||||
false
|
||||
(if form.isEditable false true)
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn @removeItemByIndex 'attributes.idp_ca_certs' i)
|
||||
}}
|
||||
{{on 'click' (fn @removeItemByIndex 'idp_ca_certs' i)}}
|
||||
>
|
||||
{{t 'actions.remove'}}
|
||||
</Rose::Button>
|
||||
@@ -630,9 +613,7 @@
|
||||
}}
|
||||
{{on
|
||||
'click'
|
||||
(fn
|
||||
@addStringItem 'attributes.idp_ca_certs' this.newCertificate
|
||||
)
|
||||
(fn @addStringItem 'idp_ca_certs' this.newCertificate)
|
||||
}}
|
||||
>
|
||||
{{t 'actions.add'}}
|
||||
@@ -647,18 +628,18 @@
|
||||
<form.input
|
||||
@name='max_age'
|
||||
@type='number'
|
||||
@value={{@model.attributes.max_age}}
|
||||
@value={{@model.max_age}}
|
||||
@label={{t 'form.max_age.label'}}
|
||||
@helperText={{t 'form.max_age.help'}}
|
||||
@error={{@model.errors.attributes_max_age}}
|
||||
@error={{@model.errors.max_age}}
|
||||
readonly={{false}}
|
||||
step='1'
|
||||
min='0'
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.attributes_max_age}}
|
||||
{{#if @model.errors.max_age}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.attributes_max_age as |error|}}
|
||||
{{#each @model.errors.max_age as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
@@ -668,16 +649,16 @@
|
||||
<form.input
|
||||
@name='api_url_prefix'
|
||||
@type='test'
|
||||
@value={{@model.attributes.api_url_prefix}}
|
||||
@value={{@model.api_url_prefix}}
|
||||
@label={{t 'form.api_url_prefix.label'}}
|
||||
@helperText={{t 'form.api_url_prefix.help'}}
|
||||
@error={{@model.errors.attributes_api_url_prefix}}
|
||||
@error={{@model.errors.api_url_prefix}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.attributes_api_url_prefix}}
|
||||
{{#if @model.errors.api_url_prefix}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.attributes_api_url_prefix as |error|}}
|
||||
{{#each @model.errors.api_url_prefix as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
@@ -686,7 +667,7 @@
|
||||
|
||||
{{#unless @model.isNew}}
|
||||
<form.input
|
||||
@value={{@model.attributes.callback_url}}
|
||||
@value={{@model.callback_url}}
|
||||
@label={{t 'form.callback_url.label'}}
|
||||
@helperText={{t 'form.callback_url.help'}}
|
||||
readonly={{true}}
|
||||
|
||||
@@ -9,7 +9,7 @@ export default class ScopesScopeAuthenticateMethodOidcController extends Control
|
||||
// =attributes
|
||||
|
||||
/**
|
||||
* Authetnication URL for the pending OIDC flow, if any.
|
||||
* Authentication URL for the pending OIDC flow, if any.
|
||||
* @type {?string}
|
||||
*/
|
||||
get authURL() {
|
||||
|
||||
@@ -191,7 +191,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
*/
|
||||
@action
|
||||
async addAccountClaimMapItem(authMethod, from, to) {
|
||||
const array = authMethod.attributes.account_claim_maps;
|
||||
const array = authMethod.account_claim_maps;
|
||||
const value = { from, to };
|
||||
array.addObject(value);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click, find, fillIn } from '@ember/test-helpers';
|
||||
import {
|
||||
visit,
|
||||
currentURL,
|
||||
click,
|
||||
find,
|
||||
fillIn,
|
||||
select,
|
||||
} from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { Response } from 'miragejs';
|
||||
@@ -14,6 +21,7 @@ module('Acceptance | auth-methods | create ', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let getAuthMethodsCount;
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
@@ -56,16 +64,65 @@ module('Acceptance | auth-methods | create ', function (hooks) {
|
||||
urls.authMethods = `${urls.orgScope}/auth-methods`;
|
||||
urls.newAuthMethod = `${urls.authMethods}/new?type=password`;
|
||||
urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`;
|
||||
getAuthMethodsCount = () =>
|
||||
this.server.schema.authMethods.all().models.length;
|
||||
});
|
||||
|
||||
test('Users can create new auth method', async function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethodsCount = this.server.db.authMethods.length;
|
||||
const count = getAuthMethodsCount();
|
||||
|
||||
await visit(urls.newAuthMethod);
|
||||
await fillIn('[name="name"]', 'AuthMethod name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
assert.strictEqual(this.server.db.authMethods.length, authMethodsCount + 1);
|
||||
assert.strictEqual(getAuthMethodsCount(), count + 1);
|
||||
});
|
||||
|
||||
test('Users can create new oidc auth method', async function (assert) {
|
||||
assert.expect(13);
|
||||
const count = getAuthMethodsCount();
|
||||
|
||||
await visit(`${urls.authMethods}/new?type=oidc`);
|
||||
const name = 'oidc name';
|
||||
await fillIn('[name="name"]', name);
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await fillIn('[name="issuer"]', 'issuer');
|
||||
await fillIn('[name="client_id"]', 'client_id');
|
||||
await fillIn('[name="client_secret"]', 'client_secret');
|
||||
await select('form fieldset:nth-of-type(1) select', 'RS384');
|
||||
await click('form fieldset:nth-of-type(1) [title="Add"]');
|
||||
await fillIn('[name="allowed_audiences"]', 'allowed_audiences');
|
||||
await click('form fieldset:nth-of-type(2) [title="Add"]');
|
||||
await fillIn('[name="claims_scopes"]', 'claims_scopes');
|
||||
await click('form fieldset:nth-of-type(3) [title="Add"]');
|
||||
await fillIn('[name="from_claim"]', 'from_claim');
|
||||
await select('form fieldset:nth-of-type(4) select', 'email');
|
||||
await click('form fieldset:nth-of-type(4) [title="Add"]');
|
||||
await fillIn('form fieldset:nth-of-type(5) textarea', 'certificates');
|
||||
await click('form fieldset:nth-of-type(5) [title="Add"]');
|
||||
await fillIn('[name="max_age"]', '5');
|
||||
await fillIn('[name="api_url_prefix"]', 'api_url_prefix');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
|
||||
assert.strictEqual(getAuthMethodsCount(), count + 1);
|
||||
const authMethod = this.server.schema.authMethods.findBy({ name });
|
||||
assert.strictEqual(authMethod.name, name);
|
||||
assert.strictEqual(authMethod.description, 'description');
|
||||
assert.strictEqual(authMethod.attributes.issuer, 'issuer');
|
||||
assert.strictEqual(authMethod.attributes.client_id, 'client_id');
|
||||
assert.strictEqual(authMethod.attributes.client_secret, 'client_secret');
|
||||
assert.deepEqual(authMethod.attributes.signing_algorithms, ['RS384']);
|
||||
assert.deepEqual(authMethod.attributes.allowed_audiences, [
|
||||
'allowed_audiences',
|
||||
]);
|
||||
assert.deepEqual(authMethod.attributes.claims_scopes, ['claims_scopes']);
|
||||
assert.deepEqual(authMethod.attributes.account_claim_maps, [
|
||||
'from_claim=email',
|
||||
]);
|
||||
assert.deepEqual(authMethod.attributes.idp_ca_certs, ['certificates']);
|
||||
assert.strictEqual(authMethod.attributes.max_age, 5);
|
||||
assert.strictEqual(authMethod.attributes.api_url_prefix, 'api_url_prefix');
|
||||
});
|
||||
|
||||
test('Users can navigate to new auth-methods route with proper authorization', async function (assert) {
|
||||
@@ -97,12 +154,12 @@ module('Acceptance | auth-methods | create ', function (hooks) {
|
||||
|
||||
test('can cancel new auth method creation', async function (assert) {
|
||||
assert.expect(2);
|
||||
const authMethodsCount = this.server.db.authMethods.length;
|
||||
const count = getAuthMethodsCount();
|
||||
await visit(urls.newAuthMethod);
|
||||
await fillIn('[name="name"]', 'AuthMethod name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.strictEqual(this.server.db.authMethods.length, authMethodsCount);
|
||||
assert.strictEqual(getAuthMethodsCount(), count);
|
||||
assert.strictEqual(currentURL(), urls.authMethods);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, click, find, fillIn } from '@ember/test-helpers';
|
||||
import {
|
||||
visit,
|
||||
click,
|
||||
find,
|
||||
fillIn,
|
||||
select,
|
||||
findAll,
|
||||
} from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
@@ -57,6 +64,84 @@ module('Acceptance | auth methods | update', function (hooks) {
|
||||
assert.strictEqual(this.server.db.authMethods[0].name, 'update name');
|
||||
});
|
||||
|
||||
test('can update an oidc auth method and save changes', async function (assert) {
|
||||
assert.expect(12);
|
||||
instances.authMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: 'oidc',
|
||||
});
|
||||
await visit(`${urls.authMethods}/${instances.authMethod.id}`);
|
||||
await click('form [type="button"]:not(:disabled)', 'Activate edit mode');
|
||||
const name = 'oidc name';
|
||||
await fillIn('[name="name"]', name);
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await fillIn('[name="issuer"]', 'issuer');
|
||||
await fillIn('[name="client_id"]', 'client_id');
|
||||
await fillIn('[name="client_secret"]', 'client_secret');
|
||||
// Remove all signing algorithms
|
||||
await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(1) [title="Remove"]').map((element) =>
|
||||
click(element)
|
||||
)
|
||||
);
|
||||
await select('form fieldset:nth-of-type(1) select', 'RS384');
|
||||
await click('form fieldset:nth-of-type(1) [title="Add"]');
|
||||
// Remove all allowed audiences
|
||||
await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(2) [title="Remove"]').map((element) =>
|
||||
click(element)
|
||||
)
|
||||
);
|
||||
await fillIn('[name="allowed_audiences"]', 'allowed_audiences');
|
||||
await click('form fieldset:nth-of-type(2) [title="Add"]');
|
||||
// Remove all claims scopes
|
||||
await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(3) [title="Remove"]').map((element) =>
|
||||
click(element)
|
||||
)
|
||||
);
|
||||
await fillIn('[name="claims_scopes"]', 'claims_scopes');
|
||||
await click('form fieldset:nth-of-type(3) [title="Add"]');
|
||||
// Remove all claim maps
|
||||
await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(4) [title="Remove"]').map((element) =>
|
||||
click(element)
|
||||
)
|
||||
);
|
||||
await fillIn('[name="from_claim"]', 'from_claim');
|
||||
await select('form fieldset:nth-of-type(4) select', 'email');
|
||||
await click('form fieldset:nth-of-type(4) [title="Add"]');
|
||||
// Remove all certificates
|
||||
await Promise.all(
|
||||
findAll('form fieldset:nth-of-type(5) [title="Remove"]').map((element) =>
|
||||
click(element)
|
||||
)
|
||||
);
|
||||
await fillIn('form fieldset:nth-of-type(5) textarea', 'certificates');
|
||||
await click('form fieldset:nth-of-type(5) [title="Add"]');
|
||||
await fillIn('[name="max_age"]', '5');
|
||||
await fillIn('[name="api_url_prefix"]', 'api_url_prefix');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
|
||||
const authMethod = this.server.schema.authMethods.findBy({ name });
|
||||
assert.strictEqual(authMethod.name, name);
|
||||
assert.strictEqual(authMethod.description, 'description');
|
||||
assert.strictEqual(authMethod.attributes.issuer, 'issuer');
|
||||
assert.strictEqual(authMethod.attributes.client_id, 'client_id');
|
||||
assert.strictEqual(authMethod.attributes.client_secret, 'client_secret');
|
||||
assert.deepEqual(authMethod.attributes.signing_algorithms, ['RS384']);
|
||||
assert.deepEqual(authMethod.attributes.allowed_audiences, [
|
||||
'allowed_audiences',
|
||||
]);
|
||||
assert.deepEqual(authMethod.attributes.claims_scopes, ['claims_scopes']);
|
||||
assert.deepEqual(authMethod.attributes.account_claim_maps, [
|
||||
'from_claim=email',
|
||||
]);
|
||||
assert.deepEqual(authMethod.attributes.idp_ca_certs, ['certificates']);
|
||||
assert.strictEqual(authMethod.attributes.max_age, 5);
|
||||
assert.strictEqual(authMethod.attributes.api_url_prefix, 'api_url_prefix');
|
||||
});
|
||||
|
||||
test('can update an auth method and cancel changes', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.authMethod);
|
||||
|
||||
Reference in new issue
Block a user