From d88a4ac103a712d19d9790f7e07ae2c53cebc8a0 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 25 May 2021 12:55:43 -0400 Subject: [PATCH 1/6] fix: logo-app.svg should load properly --- ui/admin/app/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/admin/app/index.html b/ui/admin/app/index.html index a56a21e63..1af9cc9af 100644 --- a/ui/admin/app/index.html +++ b/ui/admin/app/index.html @@ -12,7 +12,7 @@ - + {{content-for "head-footer"}} From b91f8c1661951894bbdd6df9c3848b0668b5cc70 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 25 May 2021 13:14:32 -0400 Subject: [PATCH 2/6] chore: add meta description --- ui/admin/app/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/admin/app/index.html b/ui/admin/app/index.html index a56a21e63..1362f8b65 100644 --- a/ui/admin/app/index.html +++ b/ui/admin/app/index.html @@ -4,7 +4,7 @@ Admin - + {{content-for "head"}} From 8d00730653d018c31a36b1e333e5ce0dff2c36a8 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Tue, 25 May 2021 14:52:20 -0400 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20=F0=9F=A4=96=20fix=20imports=20tha?= =?UTF-8?q?t=20don't=20make=20sense?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/core/app/helpers/app-name.js | 2 +- addons/core/app/helpers/company-copyright.js | 2 +- addons/core/app/helpers/company-name.js | 2 +- addons/core/app/helpers/doc-url.js | 2 +- .../core/app/helpers/format-date-iso-human.js | 5 +-- addons/core/app/helpers/format-date-iso.js | 2 +- addons/core/app/helpers/is-loading.js | 2 +- .../rose/app/components/rose/layout/tabs.js | 1 - addons/rose/app/components/rose/tab.js | 1 - yarn.lock | 33 ++++++++++++++----- 10 files changed, 32 insertions(+), 20 deletions(-) delete mode 100644 addons/rose/app/components/rose/layout/tabs.js delete mode 100644 addons/rose/app/components/rose/tab.js diff --git a/addons/core/app/helpers/app-name.js b/addons/core/app/helpers/app-name.js index ee117ad2f..6caf08d2e 100644 --- a/addons/core/app/helpers/app-name.js +++ b/addons/core/app/helpers/app-name.js @@ -1 +1 @@ -export { default, appName } from 'core/helpers/app-name'; +export { default } from 'core/helpers/app-name'; diff --git a/addons/core/app/helpers/company-copyright.js b/addons/core/app/helpers/company-copyright.js index d76da80c8..c846d26c1 100644 --- a/addons/core/app/helpers/company-copyright.js +++ b/addons/core/app/helpers/company-copyright.js @@ -1 +1 @@ -export { default, companyCopyright } from 'core/helpers/company-copyright'; +export { default } from 'core/helpers/company-copyright'; diff --git a/addons/core/app/helpers/company-name.js b/addons/core/app/helpers/company-name.js index da699e089..01921c115 100644 --- a/addons/core/app/helpers/company-name.js +++ b/addons/core/app/helpers/company-name.js @@ -1 +1 @@ -export { default, companyName } from 'core/helpers/company-name'; +export { default } from 'core/helpers/company-name'; diff --git a/addons/core/app/helpers/doc-url.js b/addons/core/app/helpers/doc-url.js index a8f150ce1..ae356804f 100644 --- a/addons/core/app/helpers/doc-url.js +++ b/addons/core/app/helpers/doc-url.js @@ -1 +1 @@ -export { default, docUrl } from 'core/helpers/doc-url'; +export { default } from 'core/helpers/doc-url'; diff --git a/addons/core/app/helpers/format-date-iso-human.js b/addons/core/app/helpers/format-date-iso-human.js index 947f5e926..3ed9c0ca2 100644 --- a/addons/core/app/helpers/format-date-iso-human.js +++ b/addons/core/app/helpers/format-date-iso-human.js @@ -1,4 +1 @@ -export { - default, - formatDateIsoHuman, -} from 'core/helpers/format-date-iso-human'; +export { default } from 'core/helpers/format-date-iso-human'; diff --git a/addons/core/app/helpers/format-date-iso.js b/addons/core/app/helpers/format-date-iso.js index f82d799e1..ef7aab468 100644 --- a/addons/core/app/helpers/format-date-iso.js +++ b/addons/core/app/helpers/format-date-iso.js @@ -1 +1 @@ -export { default, formatDateIso } from 'core/helpers/format-date-iso'; +export { default } from 'core/helpers/format-date-iso'; diff --git a/addons/core/app/helpers/is-loading.js b/addons/core/app/helpers/is-loading.js index 0645984c8..27b232c3d 100644 --- a/addons/core/app/helpers/is-loading.js +++ b/addons/core/app/helpers/is-loading.js @@ -1 +1 @@ -export { default, isLoading } from 'core/helpers/is-loading'; +export { default } from 'core/helpers/is-loading'; diff --git a/addons/rose/app/components/rose/layout/tabs.js b/addons/rose/app/components/rose/layout/tabs.js deleted file mode 100644 index 9de968192..000000000 --- a/addons/rose/app/components/rose/layout/tabs.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'rose/components/rose/layout/tabs'; diff --git a/addons/rose/app/components/rose/tab.js b/addons/rose/app/components/rose/tab.js deleted file mode 100644 index 37b6e680c..000000000 --- a/addons/rose/app/components/rose/tab.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from 'rose/components/rose/tab'; diff --git a/yarn.lock b/yarn.lock index d89874aa1..4c7c107d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7578,7 +7578,7 @@ debug@~4.1.0: dependencies: ms "^2.1.1" -debuglog@^1.0.1: +debuglog@*, debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -12387,7 +12387,7 @@ import-lazy@^4.0.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== -imurmurhash@^0.1.4: +imurmurhash@*, imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -14085,6 +14085,11 @@ lodash._baseflatten@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" +lodash._baseindexof@*: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" + integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= + lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -14093,11 +14098,16 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@^3.0.0: +lodash._bindcallback@*, lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= +lodash._cacheindexof@*: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" + integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= + lodash._createassigner@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" @@ -14107,12 +14117,19 @@ lodash._createassigner@^3.0.0: lodash._isiterateecall "^3.0.0" lodash.restparam "^3.0.0" +lodash._createcache@*: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" + integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= + dependencies: + lodash._getnative "^3.0.0" + lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@^3.0.0: +lodash._getnative@*, lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= @@ -14330,7 +14347,7 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.restparam@^3.0.0: +lodash.restparam@*, lodash.restparam@^3.0.0: version "3.6.1" resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= @@ -21834,9 +21851,9 @@ xmldom@^0.5.0: integrity sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA== xmlhttprequest-ssl@^1.6.2, xmlhttprequest-ssl@~1.5.4: - version "1.6.2" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.2.tgz#dd6899bfbcf684b554e393c30b13b9f3b001a7ee" - integrity sha512-tYOaldF/0BLfKuoA39QMwD4j2m8lq4DIncqj1yuNELX4vz9+z/ieG/vwmctjJce+boFHXstqhWnHSxc4W8f4qg== + version "1.6.3" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6" + integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q== xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" From 28d18e389c8a3dd6a4e7a78d8e798c9816133af2 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 1 Jun 2021 12:55:35 -0400 Subject: [PATCH 4/6] chore: Fix js lint errors --- addons/api/addon/services/storage.js | 5 +++-- addons/auth/addon/authenticators/base.js | 7 +++---- addons/core/addon/authenticators/oidc.js | 4 ++-- addons/core/addon/authenticators/password.js | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/api/addon/services/storage.js b/addons/api/addon/services/storage.js index ea1b7138d..d9b7aa495 100644 --- a/addons/api/addon/services/storage.js +++ b/addons/api/addon/services/storage.js @@ -76,8 +76,9 @@ export default class StorageService extends Service { const inMemory = get(config, 'storage.memory'); // Get the global context object (window) via service lookup, // because just reaching for a global is icky - const globalContext = getOwner(this).lookup('service:-document') - .documentElement.parentNode.defaultView; + const globalContext = + getOwner(this).lookup('service:-document').documentElement.parentNode + .defaultView; // If memory storage enabled, return the memory storage instance, // otherwise return localStorage. return inMemory ? this.#memoryStorage : globalContext.localStorage; diff --git a/addons/auth/addon/authenticators/base.js b/addons/auth/addon/authenticators/base.js index bdc69d504..deeea5a0d 100644 --- a/addons/auth/addon/authenticators/base.js +++ b/addons/auth/addon/authenticators/base.js @@ -72,10 +72,9 @@ export default class BaseAuthenticator extends SimpleAuthBaseAuthenticator { */ async restore(data) { if (!data) return reject(); - return this.validateToken( - data.attributes.token, - data.attributes.id - ).then(() => this.normalizeData(data)); + return this.validateToken(data.attributes.token, data.attributes.id).then( + () => this.normalizeData(data) + ); } /** diff --git a/addons/core/addon/authenticators/oidc.js b/addons/core/addon/authenticators/oidc.js index f159fa87f..245dc97cd 100644 --- a/addons/core/addon/authenticators/oidc.js +++ b/addons/core/addon/authenticators/oidc.js @@ -76,8 +76,8 @@ export default class OIDCAuthenticator extends BaseOIDCAuthenticator { * @param {string} token */ addTokenToAuthorization(token) { - const adapterPrototype = this.store.adapterFor('application').constructor - .prototype; + const adapterPrototype = + this.store.adapterFor('application').constructor.prototype; const headers = adapterPrototype?.headers; if (!headers) adapterPrototype.headers = {}; adapterPrototype.headers.Authorization = null; diff --git a/addons/core/addon/authenticators/password.js b/addons/core/addon/authenticators/password.js index 186731a7d..a2dfc8131 100644 --- a/addons/core/addon/authenticators/password.js +++ b/addons/core/addon/authenticators/password.js @@ -91,8 +91,8 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator { * @param {string} token */ addTokenToAuthorization(token) { - const adapterPrototype = this.store.adapterFor('application').constructor - .prototype; + const adapterPrototype = + this.store.adapterFor('application').constructor.prototype; const headers = adapterPrototype?.headers; if (!headers) adapterPrototype.headers = {}; adapterPrototype.headers.Authorization = null; From 77d71871167271342e8bbf3bf7101fa5abdbc570 Mon Sep 17 00:00:00 2001 From: Carlos Alcaide Date: Tue, 1 Jun 2021 11:07:48 -0700 Subject: [PATCH 5/6] =?UTF-8?q?chore:=20=F0=9F=A4=96=20Fix=20lint=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix lint errors --- addons/api/addon/services/storage.js | 5 ++--- addons/auth/addon/authenticators/base.js | 7 ++++--- addons/core/addon/authenticators/oidc.js | 4 ++-- addons/core/addon/authenticators/password.js | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/api/addon/services/storage.js b/addons/api/addon/services/storage.js index d9b7aa495..ea1b7138d 100644 --- a/addons/api/addon/services/storage.js +++ b/addons/api/addon/services/storage.js @@ -76,9 +76,8 @@ export default class StorageService extends Service { const inMemory = get(config, 'storage.memory'); // Get the global context object (window) via service lookup, // because just reaching for a global is icky - const globalContext = - getOwner(this).lookup('service:-document').documentElement.parentNode - .defaultView; + const globalContext = getOwner(this).lookup('service:-document') + .documentElement.parentNode.defaultView; // If memory storage enabled, return the memory storage instance, // otherwise return localStorage. return inMemory ? this.#memoryStorage : globalContext.localStorage; diff --git a/addons/auth/addon/authenticators/base.js b/addons/auth/addon/authenticators/base.js index deeea5a0d..bdc69d504 100644 --- a/addons/auth/addon/authenticators/base.js +++ b/addons/auth/addon/authenticators/base.js @@ -72,9 +72,10 @@ export default class BaseAuthenticator extends SimpleAuthBaseAuthenticator { */ async restore(data) { if (!data) return reject(); - return this.validateToken(data.attributes.token, data.attributes.id).then( - () => this.normalizeData(data) - ); + return this.validateToken( + data.attributes.token, + data.attributes.id + ).then(() => this.normalizeData(data)); } /** diff --git a/addons/core/addon/authenticators/oidc.js b/addons/core/addon/authenticators/oidc.js index 245dc97cd..f159fa87f 100644 --- a/addons/core/addon/authenticators/oidc.js +++ b/addons/core/addon/authenticators/oidc.js @@ -76,8 +76,8 @@ export default class OIDCAuthenticator extends BaseOIDCAuthenticator { * @param {string} token */ addTokenToAuthorization(token) { - const adapterPrototype = - this.store.adapterFor('application').constructor.prototype; + const adapterPrototype = this.store.adapterFor('application').constructor + .prototype; const headers = adapterPrototype?.headers; if (!headers) adapterPrototype.headers = {}; adapterPrototype.headers.Authorization = null; diff --git a/addons/core/addon/authenticators/password.js b/addons/core/addon/authenticators/password.js index a2dfc8131..186731a7d 100644 --- a/addons/core/addon/authenticators/password.js +++ b/addons/core/addon/authenticators/password.js @@ -91,8 +91,8 @@ export default class PasswordAuthenticator extends BasePasswordAuthenticator { * @param {string} token */ addTokenToAuthorization(token) { - const adapterPrototype = - this.store.adapterFor('application').constructor.prototype; + const adapterPrototype = this.store.adapterFor('application').constructor + .prototype; const headers = adapterPrototype?.headers; if (!headers) adapterPrototype.headers = {}; adapterPrototype.headers.Authorization = null; From c14be070f759ba0c4dedc39a5e129d39198af050 Mon Sep 17 00:00:00 2001 From: Susmitha Girumala Date: Tue, 1 Jun 2021 22:29:19 -0400 Subject: [PATCH 6/6] feat: Add oidc status change dropdown to auth method actions --- addons/api/addon/models/auth-method.js | 4 +- addons/api/mirage/config.js | 29 +++- addons/api/mirage/route-handlers/auth.js | 2 +- addons/api/mirage/scenarios/default.js | 6 + addons/core/translations/resources/en-us.yaml | 1 + addons/core/translations/states/en-us.yaml | 6 + .../scopes/scope/auth-methods/auth-method.js | 16 +++ .../auth-methods/auth-method/-actions.hbs | 34 ++++- .../acceptance/auth-methods/oidc-test.js | 134 ++++++++++++++++++ 9 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 ui/admin/tests/acceptance/auth-methods/oidc-test.js diff --git a/addons/api/addon/models/auth-method.js b/addons/api/addon/models/auth-method.js index dc03abc0d..1ba8050a9 100644 --- a/addons/api/addon/models/auth-method.js +++ b/addons/api/addon/models/auth-method.js @@ -3,7 +3,7 @@ import { fragment } from 'ember-data-model-fragments/attributes'; import { equal } from '@ember/object/computed'; /** - * Enum ptions per auth method type and field. + * Enum options per auth method type and field. */ export const options = { oidc: { @@ -27,6 +27,8 @@ export const options = { }; export default class AuthMethodModel extends GeneratedAuthMethodModel { + STATES_ENUM = options.oidc.state; + // =attributes /** diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 769e7e810..d34110910 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -1,6 +1,6 @@ import Ember from 'ember'; import config from '../config/environment'; -import { authHandler, deauthHandler } from './route-handlers/auth'; +import { deauthHandler } from './route-handlers/auth'; import { pickRandomStatusString } from './factories/session'; import { Response } from 'miragejs'; import initializeMockIPC from './scenarios/ipc'; @@ -71,6 +71,31 @@ export default function () { } return new Response(202); }); + this.post('/auth-methods/:idMethod', function (schema, request) { + const idMethod = request.params.idMethod; + const id = idMethod.split(':')[0]; + const method = idMethod.split(':')[1]; + + if (method === 'authenticate') { + schema.authHandler.call(this, schema, request); + return; + } + + const attrs = this.normalizedRequestAttrs(); + const authMethods = schema.authMethods; + const authMethod = authMethods.find(id); + let updatedAttrs = {}; + + if (method === 'change-state') { + updatedAttrs = { + attributes: { + state: attrs.attributes.state, + }, + }; + } + + return authMethod.update(updatedAttrs); + }); // Auth Method Accounts this.get( @@ -107,7 +132,7 @@ export default function () { ); // Authenticate/deauthenticate routes - this.post('/auth-methods/:id_method', authHandler); + // this.post('/auth-methods/:id_method', authHandler); this.post('/scopes/:id_method', deauthHandler); // IAM : Users diff --git a/addons/api/mirage/route-handlers/auth.js b/addons/api/mirage/route-handlers/auth.js index bd4fca7ac..522ac0b52 100644 --- a/addons/api/mirage/route-handlers/auth.js +++ b/addons/api/mirage/route-handlers/auth.js @@ -109,7 +109,7 @@ const commandHandlers = { export function authHandler({ scopes, authMethods }, request) { const payload = JSON.parse(request.requestBody); - const [, id] = request.params.id_method.match(/(?.[^:]*)/); + const [, id] = request.params.idMethod.match(/(?.[^:]*)/); const { command } = payload; const authMethod = authMethods.find(id); const scope = scopes.find(authMethod.scopeId); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index 62018788c..1f2595bb8 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -1,3 +1,5 @@ +import { authHandler } from '../route-handlers/auth'; + export default function (server) { // Scope resources @@ -50,4 +52,8 @@ export default function (server) { server.createList('target', 2, { scope }, 'withRandomHostSets'); server.createList('session', 4, { scope }, 'withAssociations'); }); + + // Authenticate route handler + // TODO: Better way to pass-in auth handler + server.schema.authHandler = authHandler; } diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 7432ac466..aa42e8d53 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -38,6 +38,7 @@ auth-method: delete: Delete Auth Method make-primary: Make Primary remove-as-primary: Remove as Primary + change-state: State notifications: make-primary-success: Auth method successfully elected to primary. remove-as-primary-success: Auth method successfully removed as primary. diff --git a/addons/core/translations/states/en-us.yaml b/addons/core/translations/states/en-us.yaml index aa8e846bd..23a92c6cf 100644 --- a/addons/core/translations/states/en-us.yaml +++ b/addons/core/translations/states/en-us.yaml @@ -8,3 +8,9 @@ connection: success: description: "Local proxy address ({protocol}): {address}:{port}" primary: Primary +auth-method: + oidc: + states: + inactive: Inactive + active-private: Active Private + active-public: Active Public diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method.js index 3c608f660..c492fed7b 100644 --- a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method.js +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method.js @@ -1,4 +1,6 @@ import Route from '@ember/routing/route'; +import { action } from '@ember/object'; +import { notifySuccess, notifyError } from 'core/decorators/notify'; export default class ScopesScopeAuthMethodsAuthMethodRoute extends Route { // =methods @@ -36,4 +38,18 @@ export default class ScopesScopeAuthMethodsAuthMethodRoute extends Route { outlet: 'actions', }); } + + // =actions + + /** + * Update state of OIDC auth method + * @param {string} state - "inactive", "active-private", "active-public" + */ + @action + @notifyError(({ message }) => message) + @notifySuccess('notifications.save-success') + async changeState(state) { + const model = this.modelFor('scopes.scope.auth-methods.auth-method'); + await model.changeState(state); + } } diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs index c46e656f8..5b05d127a 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs @@ -1,3 +1,35 @@ +{{#if @model.isOIDC}} + + + + + {{#each @model.STATES_ENUM as |state|}} + + + + {{/each}} + + + + +{{/if}} + {{t 'resources.auth-method.actions.delete'}} - \ No newline at end of file + diff --git a/ui/admin/tests/acceptance/auth-methods/oidc-test.js b/ui/admin/tests/acceptance/auth-methods/oidc-test.js new file mode 100644 index 000000000..75b89edeb --- /dev/null +++ b/ui/admin/tests/acceptance/auth-methods/oidc-test.js @@ -0,0 +1,134 @@ +import { module, test } from 'qunit'; +import { + visit, + currentURL, + click, + // fillIn, + find, + // 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'; +import { Response } from 'miragejs'; +import { + authenticateSession, + // These are left here intentionally for future reference. + //currentSession, + //invalidateSession, +} from 'ember-simple-auth/test-support'; + +module('Acceptance | auth methods | oidc', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + const instances = { + scopes: { + global: null, + org: null, + }, + authMethod: null, + }; + const urls = { + orgScope: null, + authMethods: null, + authMethod: null, + }; + + hooks.beforeEach(function () { + authenticateSession({}); + instances.scopes.global = this.server.create('scope', { id: 'global' }); + instances.scopes.org = this.server.create('scope', { + type: 'org', + scope: { id: 'global', type: 'global' }, + }); + instances.authMethod = this.server.create('auth-method', { + scope: instances.scopes.org, + type: 'oidc', + }); + + urls.orgScope = `/scopes/${instances.scopes.org.id}`; + urls.authMethods = `${urls.orgScope}/auth-methods`; + urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`; + }); + + test('visiting oidc auth method', async function (assert) { + assert.expect(1); + await visit(urls.authMethod); + await a11yAudit(); + assert.equal(currentURL(), urls.authMethod); + }); + + test('can view oidc state', async function(assert) { + assert.expect(1); + await visit(urls.authMethod); + await click('.rose-layout-page-actions .rose-dropdown-trigger'); + assert.equal( + find('.rose-dropdown[open] input[aria-checked=true]').value, + instances.authMethod.attributes.state + ); + }); + + test('can update oidc state', async function(assert) { + assert.expect(1); + const updateValue = 'inactive'; + await visit(urls.authMethod); + await click('.rose-layout-page-actions .rose-dropdown-trigger'); + await click(`.rose-dropdown[open] input[value="${updateValue}"]`); + const authMethod = this.server.db.authMethods.find(instances.authMethod.id); + assert.equal(authMethod.attributes.state, updateValue); + }); + + test('can update oidc state to active-private', async function(assert) { + assert.expect(1); + const updateValue = 'active-private'; + await visit(urls.authMethod); + await click('.rose-layout-page-actions .rose-dropdown-trigger'); + await click(`.rose-dropdown[open] input[value="${updateValue}"]`); + const authMethod = this.server.db.authMethods.find(instances.authMethod.id); + assert.equal(authMethod.attributes.state, updateValue); + }); + + test('can update oidc state to active-public', async function(assert) { + assert.expect(1); + // Update default 'active-public' state to inactive + instances.authMethod.attributes.state = 'inactive'; + const updateValue = 'active-public'; + await visit(urls.authMethod); + await click('.rose-layout-page-actions .rose-dropdown-trigger'); + await click(`.rose-dropdown[open] input[value="${updateValue}"]`); + const authMethod = this.server.db.authMethods.find(instances.authMethod.id); + assert.equal(authMethod.attributes.state, updateValue); + }); + + test('errors are displayed when state update fails', async function (assert) { + assert.expect(2); + const newState = 'inactive'; + await visit(urls.authMethod); + await click('.rose-layout-page-actions .rose-dropdown-trigger'); + // Load page before mocking update + this.server.post('/auth-methods/:idMethod', () => { + return new Response( + 400, + {}, + { + status: 400, + code: 'error', + message: 'Sorry!', + } + ); + }); + await click(`.rose-dropdown[open] input[value="${newState}"]`); + const authMethod = this.server.db.authMethods.find(instances.authMethod.id); + assert.notEqual( + newState, + authMethod.attributes.state, + 'Auth method state is not be updated.' + ); + assert.ok( + find('[role="alert"]').textContent.trim(), + 'Sorry!', + 'Displays error message.' + ); + }); +});