feat: 🎸 Allow prompts in oidc auth method form (#2007)
* feat: 🎸 Allow prompts in OIDC auth method form
This commit is contained in:
1 parent
02a89bd7ba
commit
3f2f2ba756
12 files changed
+115
-2
No files matched your search
@@ -158,6 +158,13 @@ export default class GeneratedAuthMethodModel extends BaseModel {
|
||||
})
|
||||
account_claim_maps;
|
||||
|
||||
@attr('string-array', {
|
||||
for: 'oidc',
|
||||
emptyArrayIfMissing: true,
|
||||
isNestedAttribute: true,
|
||||
})
|
||||
prompts;
|
||||
|
||||
// =attributes(ldap)
|
||||
|
||||
@attr('boolean', {
|
||||
|
||||
@@ -37,6 +37,7 @@ export const options = {
|
||||
account_claim_maps: {
|
||||
to: ['sub', 'name', 'email'],
|
||||
},
|
||||
prompts: ['none', 'consent', 'select_account', 'login'],
|
||||
},
|
||||
ldap: {
|
||||
account_attribute_maps: {
|
||||
|
||||
@@ -42,6 +42,7 @@ export default Factory.extend({
|
||||
signing_algorithms: ['RS256', 'RS384'],
|
||||
allowed_audiences: ['www.alice.com', 'www.alice.com/admin'],
|
||||
idp_ca_certs: ['certificate-1234', 'certificate-5678'],
|
||||
prompts: ['consent'],
|
||||
};
|
||||
break;
|
||||
case TYPE_AUTH_METHOD_LDAP:
|
||||
|
||||
@@ -165,6 +165,7 @@ module('Unit | Serializer | application', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: [{ value: 'consent' }],
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
@@ -186,6 +187,7 @@ module('Unit | Serializer | application', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: ['consent'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,6 +65,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: [{ value: 'none' }],
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
@@ -86,6 +87,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: ['none'],
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -180,6 +182,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: [{ value: 'consent' }],
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
@@ -200,6 +203,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
dry_run: true,
|
||||
issuer: 'http://www.example.net',
|
||||
max_age: 500,
|
||||
prompts: ['consent'],
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -397,6 +401,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
issuer: issuer,
|
||||
max_age: maxAge,
|
||||
client_secret: 'secret123',
|
||||
prompts: ['consent'],
|
||||
},
|
||||
version: 1,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
@@ -410,6 +415,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
allowed_audiences,
|
||||
signing_algorithms,
|
||||
idp_ca_certs,
|
||||
prompts,
|
||||
} = record;
|
||||
assert.deepEqual(account_claim_maps, [
|
||||
{ from: 'from', to: 'to' },
|
||||
@@ -429,6 +435,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
{ value: 'certificate-5678' },
|
||||
]);
|
||||
assert.strictEqual(record.api_url_prefix, apiUrlPrefix);
|
||||
assert.deepEqual(prompts, [{ value: 'consent' }]);
|
||||
assert.strictEqual(record.client_id, clientId);
|
||||
assert.strictEqual(
|
||||
record.disable_discovered_config_validation,
|
||||
|
||||
@@ -119,6 +119,9 @@ to_claim:
|
||||
signing_algorithms:
|
||||
label: Signing Algorithms
|
||||
help: The signing algorithms allowed for the auth method.
|
||||
prompts:
|
||||
label: Prompts
|
||||
help: The prompts allowed for an oidc auth method.
|
||||
algorithm:
|
||||
label: Algorithm
|
||||
subject:
|
||||
|
||||
@@ -147,6 +147,18 @@ auth-method:
|
||||
account_attribute_maps:
|
||||
label: Account Attribute Maps
|
||||
help: Attribute maps from custom attributes to the standard fullname and email account attributes. These maps are represented as key=value where the key equals the from_attribute, and the value equals the to_attribute. For example, "preferredName=fullName".
|
||||
consent:
|
||||
label: Consent
|
||||
help: Always require the user to explicitly consent to scopes requested
|
||||
select_account:
|
||||
label: Select Account
|
||||
help: Allow the user to select from multiple accounts from this provider
|
||||
login:
|
||||
label: Login
|
||||
help: Always require the user to log in to this auth provider
|
||||
none:
|
||||
label: None
|
||||
help: Skip prompts if the user is already signed in and has granted consent
|
||||
section:
|
||||
connection:
|
||||
title: Connection
|
||||
|
||||
@@ -528,6 +528,34 @@
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<Hds::Form::Checkbox::Group
|
||||
class='oidc-prompts'
|
||||
@isOptional={{true}}
|
||||
@name='prompts'
|
||||
disabled={{form.disabled}}
|
||||
as |G|
|
||||
>
|
||||
<G.Legend>{{t 'form.prompts.label'}}</G.Legend>
|
||||
<G.HelperText>{{t 'form.prompts.help'}}</G.HelperText>
|
||||
|
||||
{{#each this.prompts as |prompt|}}
|
||||
<G.Checkbox::Field
|
||||
@id={{prompt}}
|
||||
checked={{includes prompt this.selectedPrompts}}
|
||||
{{on 'change' (fn this.updatePrompt prompt)}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>
|
||||
{{t (concat 'resources.auth-method.form.' prompt '.label')}}
|
||||
</F.Label>
|
||||
<F.HelperText>
|
||||
{{t (concat 'resources.auth-method.form.' prompt '.help')}}
|
||||
</F.HelperText>
|
||||
</G.Checkbox::Field>
|
||||
{{/each}}
|
||||
|
||||
</Hds::Form::Checkbox::Group>
|
||||
|
||||
{{#unless @model.isNew}}
|
||||
<form.input
|
||||
@value={{@model.callback_url}}
|
||||
@@ -537,6 +565,7 @@
|
||||
@disabled={{true}}
|
||||
/>
|
||||
{{/unless}}
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { options } from 'api/models/auth-method';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
export default class FormAuthMethodOidcComponent extends Component {
|
||||
// =attributes
|
||||
@@ -27,4 +29,41 @@ export default class FormAuthMethodOidcComponent extends Component {
|
||||
* @type {string}
|
||||
*/
|
||||
newSigningAlgorithm = options.oidc.signing_algorithms[0];
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
prompts = options.oidc.prompts;
|
||||
|
||||
@tracked selectedPrompts = this.parsePromptsArray();
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
parsePromptsArray() {
|
||||
return this.args.model.prompts?.map((item) => item.value) ?? [];
|
||||
}
|
||||
|
||||
//actions
|
||||
|
||||
/**
|
||||
* @param {string} option
|
||||
* @param {object} event
|
||||
*/
|
||||
@action
|
||||
updatePrompt(value, event) {
|
||||
const currentSelection = { value };
|
||||
const previousSelection = this.args.model.prompts || [];
|
||||
|
||||
// Add the selected option to the model, only when the checkbox is in checked state
|
||||
if (event.target.checked) {
|
||||
this.args.model.prompts = [...previousSelection, currentSelection];
|
||||
} else {
|
||||
// When the checkbox is unchecked, remove the option form the exisiting list
|
||||
const removeSelection = previousSelection.filter(
|
||||
(prompt) => prompt.value !== value,
|
||||
);
|
||||
this.args.model.prompts = [...removeSelection];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,6 +317,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
.oidc-prompts {
|
||||
.hds-form-group__control-field {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
/* stylelint-enable selector-class-pattern */
|
||||
|
||||
.worker-create-section {
|
||||
border: sizing.rems(xxxxs) solid var(--ui-gray-subtler-3);
|
||||
border-radius: sizing.rems(xxs);
|
||||
|
||||
@@ -108,7 +108,7 @@ module('Acceptance | auth-methods | create', function (hooks) {
|
||||
});
|
||||
|
||||
test('Users can create new oidc auth method', async function (assert) {
|
||||
assert.expect(12);
|
||||
assert.expect(13);
|
||||
const count = getAuthMethodsCount();
|
||||
|
||||
await visit(`${urls.authMethods}/new?type=oidc`);
|
||||
@@ -134,6 +134,7 @@ module('Acceptance | auth-methods | create', function (hooks) {
|
||||
await click(IDP_CERTS_BTN_SELECTOR);
|
||||
await fillIn('[name="max_age"]', '5');
|
||||
await fillIn('[name="api_url_prefix"]', 'api_url_prefix');
|
||||
await click('[id="consent"]', 'consent');
|
||||
await click(SAVE_BTN_SELECTOR);
|
||||
|
||||
assert.strictEqual(getAuthMethodsCount(), count + 1);
|
||||
@@ -153,6 +154,7 @@ module('Acceptance | auth-methods | create', function (hooks) {
|
||||
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');
|
||||
assert.deepEqual(authMethod.attributes.prompts, ['consent']);
|
||||
});
|
||||
|
||||
test('Users can create a new ldap auth method', async function (assert) {
|
||||
|
||||
@@ -108,7 +108,7 @@ module('Acceptance | auth-methods | update', function (hooks) {
|
||||
});
|
||||
|
||||
test('can update an oidc auth method and save changes', async function (assert) {
|
||||
assert.expect(11);
|
||||
assert.expect(12);
|
||||
instances.authMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
@@ -173,6 +173,7 @@ module('Acceptance | auth-methods | update', function (hooks) {
|
||||
await click(IDP_CERTS_BTN_SELECTOR);
|
||||
await fillIn('[name="max_age"]', '5');
|
||||
await fillIn('[name="api_url_prefix"]', 'api_url_prefix');
|
||||
await click('[id="none"]', 'none');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
|
||||
const authMethod = this.server.schema.authMethods.findBy({ name });
|
||||
@@ -191,6 +192,7 @@ module('Acceptance | auth-methods | update', function (hooks) {
|
||||
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');
|
||||
assert.deepEqual(authMethod.attributes.prompts, ['consent', 'none']);
|
||||
});
|
||||
|
||||
test('can update an ldap auth method and save changes', async function (assert) {
|
||||
|
||||
Reference in new issue
Block a user