diff --git a/addons/api/addon/models/account.js b/addons/api/addon/models/account.js
index e5f702541..9412e18aa 100644
--- a/addons/api/addon/models/account.js
+++ b/addons/api/addon/models/account.js
@@ -26,15 +26,10 @@ export default class AccountModel extends GeneratedAccountModel {
* Convenience for getting username in account.
* @type {string}
*/
- @computed('type', 'attributes.login_name')
- get username() {
- let username = '';
- switch (this.type) {
- case 'password':
- username = this.attributes.login_name;
- break;
- }
- return username;
+ @computed('attributes.{email,full_name,login_name}')
+ get accountName() {
+ const { email, full_name, login_name } = this.attributes;
+ return email || full_name || login_name;
}
// =methods
diff --git a/addons/api/addon/serializers/account.js b/addons/api/addon/serializers/account.js
index 939aceb70..128fa10e2 100644
--- a/addons/api/addon/serializers/account.js
+++ b/addons/api/addon/serializers/account.js
@@ -23,9 +23,28 @@ export default class AccountSerializer extends ApplicationSerializer {
switch (snapshot.record.type) {
case 'password':
return this.serializePassword(...arguments);
+ case 'oidc':
+ return this.serializeOIDC(...arguments);
}
}
+ /**
+ * OIDC serialization limits the `attributes` posted on create and omits
+ * `attributes` entirely on update.
+ */
+ serializeOIDC(snapshot) {
+ const { isNew } = snapshot?.record;
+ let serialized = super.serialize(...arguments);
+ delete serialized.attributes;
+ if (isNew) {
+ serialized.attributes = {};
+ const { issuer, subject } = snapshot.attr('attributes').record;
+ if (issuer) serialized.attributes.issuer = issuer;
+ if (subject) serialized.attributes.subject = subject;
+ }
+ return serialized;
+ }
+
/**
* Password serialization omits `attributes` and handles password-related
* custom methods.
diff --git a/addons/api/mirage/factories/account.js b/addons/api/mirage/factories/account.js
index 5908d0a21..5c49f96b5 100644
--- a/addons/api/mirage/factories/account.js
+++ b/addons/api/mirage/factories/account.js
@@ -1,3 +1,18 @@
import factory from '../generated/factories/account';
+import { random, internet } from 'faker';
-export default factory.extend();
+export default factory.extend({
+ attributes() {
+ switch (this.type) {
+ case 'password':
+ return { login_name: random.words() };
+ case 'oidc':
+ return {
+ issuer: internet.ip(),
+ subject: 'sub',
+ email: internet.email(),
+ full_name: random.words(),
+ };
+ }
+ },
+});
diff --git a/addons/api/mirage/factories/auth-method.js b/addons/api/mirage/factories/auth-method.js
index b7dc8ddda..fd8e705fd 100644
--- a/addons/api/mirage/factories/auth-method.js
+++ b/addons/api/mirage/factories/auth-method.js
@@ -14,9 +14,9 @@ export default factory.extend({
*/
withAccountsAndUsers: trait({
afterCreate(authMethod, server) {
- const { scope } = authMethod;
+ const { scope, type } = authMethod;
server.createList('user', 5, { scope }).map((user) => {
- const { id } = server.create('account', { scope, authMethod });
+ const { id } = server.create('account', { scope, type, authMethod });
user.update({ accountIds: [id] });
});
},
diff --git a/addons/api/mirage/generated/factories/account.js b/addons/api/mirage/generated/factories/account.js
index bc5a33c02..92a515a73 100644
--- a/addons/api/mirage/generated/factories/account.js
+++ b/addons/api/mirage/generated/factories/account.js
@@ -1,15 +1,14 @@
import { Factory } from 'ember-cli-mirage';
-import { random, date, datatype } from 'faker';
+import { date, datatype } from 'faker';
/**
* GeneratedAccountFactory
*/
export default Factory.extend({
type: 'password',
- name: () => random.words(),
- description: () => random.words(),
+ // name: () => random.words(),
+ // description: () => random.words(),
created_time: () => date.recent(),
updated_time: () => date.recent(),
version: () => datatype.number(),
- attributes: () => ({ login_name: random.words() }),
});
diff --git a/addons/api/tests/unit/models/account-test.js b/addons/api/tests/unit/models/account-test.js
index 33021e295..4a4b3b0d4 100644
--- a/addons/api/tests/unit/models/account-test.js
+++ b/addons/api/tests/unit/models/account-test.js
@@ -10,15 +10,14 @@ module('Unit | Model | account', function (hooks) {
assert.ok(model);
});
- test('it has an username attribute for password account', function (assert) {
+ test('it has an accountName attribute for password account', function (assert) {
assert.expect(2);
const store = this.owner.lookup('service:store');
let model = store.createRecord('account', {
- name: 'name',
type: 'password',
});
- assert.notOk(model.username);
- model.attributes.login_name = 'username';
- assert.equal(model.username, 'username');
+ assert.notOk(model.accountName);
+ model.attributes.login_name = 'foobar';
+ assert.equal(model.accountName, 'foobar');
});
});
diff --git a/addons/api/tests/unit/serializers/account-test.js b/addons/api/tests/unit/serializers/account-test.js
index 4d5646e08..7af6a504f 100644
--- a/addons/api/tests/unit/serializers/account-test.js
+++ b/addons/api/tests/unit/serializers/account-test.js
@@ -4,7 +4,75 @@ import { setupTest } from 'ember-qunit';
module('Unit | Serializer | account', function (hooks) {
setupTest(hooks);
- test('it serializes normally', function (assert) {
+ test('it serializes OIDC-type with only issuer and subject in `attributes` on create', function (assert) {
+ assert.expect(1);
+ const store = this.owner.lookup('service:store');
+ const serializer = store.serializerFor('account');
+ const record = store.createRecord('account', {
+ type: 'oidc',
+ name: 'Name',
+ auth_method_id: '1',
+ description: 'Description',
+ attributes: {
+ issuer: 'issuer',
+ subject: 'sub',
+ full_name: 'full_name',
+ email: 'email',
+ },
+ version: 1,
+ });
+ const snapshot = record._createSnapshot();
+ const serializedRecord = serializer.serialize(snapshot);
+ assert.deepEqual(serializedRecord, {
+ type: 'oidc',
+ name: 'Name',
+ auth_method_id: '1',
+ description: 'Description',
+ version: 1,
+ attributes: {
+ issuer: 'issuer',
+ subject: 'sub',
+ },
+ });
+ });
+
+ test('it serializes OIDC-type without `attributes` on update', function (assert) {
+ assert.expect(2);
+ const store = this.owner.lookup('service:store');
+ const serializer = store.serializerFor('account');
+ store.push({
+ data: {
+ id: '1',
+ type: 'account',
+ attributes: {
+ type: 'oidc',
+ name: 'Name',
+ auth_method_id: '1',
+ description: 'Description',
+ attributes: {
+ issuer: 'issuer',
+ subject: 'sub',
+ full_name: 'full_name',
+ email: 'email',
+ },
+ version: 1,
+ },
+ },
+ });
+ const record = store.peekRecord('account', '1');
+ const snapshot = record._createSnapshot();
+ const serializedRecord = serializer.serialize(snapshot);
+ assert.notOk(serializedRecord.attributes);
+ assert.deepEqual(serializedRecord, {
+ type: 'oidc',
+ name: 'Name',
+ auth_method_id: '1',
+ description: 'Description',
+ version: 1,
+ });
+ });
+
+ test('it serializes password-type normally', function (assert) {
assert.expect(1);
const store = this.owner.lookup('service:store');
const serializer = store.serializerFor('account');
@@ -19,7 +87,6 @@ module('Unit | Serializer | account', function (hooks) {
version: 1,
});
const snapshot = record._createSnapshot();
- snapshot.adapterOptions = {};
const serializedRecord = serializer.serialize(snapshot);
assert.deepEqual(serializedRecord, {
type: 'password',
diff --git a/ui/admin/app/components/form/account/index.hbs b/ui/admin/app/components/form/account/index.hbs
new file mode 100644
index 000000000..baf4e23fd
--- /dev/null
+++ b/ui/admin/app/components/form/account/index.hbs
@@ -0,0 +1,8 @@
+{{#if @model.type}}
+ {{component
+ (concat 'form/account/' @model.type)
+ model=@model
+ submit=@submit
+ cancel=@cancel
+ }}
+{{/if}}
\ No newline at end of file
diff --git a/ui/admin/app/components/form/account/oidc/index.hbs b/ui/admin/app/components/form/account/oidc/index.hbs
new file mode 100644
index 000000000..b3a2dd8a7
--- /dev/null
+++ b/ui/admin/app/components/form/account/oidc/index.hbs
@@ -0,0 +1,127 @@
+
{{account.auth_method_id}}
{{account.description}}
+{{account.attributes.issuer}}
@@ -31,6 +38,9 @@
{{account.description}}
-{{account.description}}
{{account.description}}