Merge pull request #252 from hashicorp/oss/merge-main-3b3d6ab50fb690e307479b925302ad08f13d2732
[main] OSS to ENT merge of (3b3d6ab)
This commit is contained in:
commit
bd0361d611
14 files changed
+424
-67
No files matched your search
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import ModelAbility from './model';
|
||||
/**
|
||||
* Provides abilities for auth method.
|
||||
*/
|
||||
export default class AuthMethodAbility extends ModelAbility {
|
||||
// =permissions
|
||||
|
||||
/**
|
||||
* Only "known" auth method types may be read.
|
||||
* @type {boolean}
|
||||
*/
|
||||
get canRead() {
|
||||
return !this.model.isUnknown && this.hasAuthorizedAction('read');
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,16 @@
|
||||
import GeneratedAuthMethodModel from '../generated/models/auth-method';
|
||||
import { equal } from '@ember/object/computed';
|
||||
|
||||
export const TYPE_AUTH_METHOD_PASSWORD = 'password';
|
||||
export const TYPE_AUTH_METHOD_OIDC = 'oidc';
|
||||
export const TYPE_AUTH_METHOD_LDAP = 'ldap';
|
||||
|
||||
export const TYPES_AUTH_METHOD = Object.freeze([
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
]);
|
||||
|
||||
/**
|
||||
* Enum options per auth method type and field.
|
||||
*/
|
||||
@@ -44,14 +54,28 @@ export default class AuthMethodModel extends GeneratedAuthMethodModel {
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isPassword() {
|
||||
return this.type === 'password';
|
||||
return this.type === TYPE_AUTH_METHOD_PASSWORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isOIDC() {
|
||||
return this.type === 'oidc';
|
||||
return this.type === TYPE_AUTH_METHOD_OIDC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isLDAP() {
|
||||
return this.type === TYPE_AUTH_METHOD_LDAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isUnknown() {
|
||||
return !TYPES_AUTH_METHOD.includes(this.type);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
import ApplicationSerializer from './application';
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
|
||||
export default class AuthMethodSerializer extends ApplicationSerializer {
|
||||
// =methods
|
||||
|
||||
@@ -15,7 +17,7 @@ export default class AuthMethodSerializer extends ApplicationSerializer {
|
||||
*/
|
||||
serialize(snapshot) {
|
||||
switch (snapshot.record.type) {
|
||||
case 'oidc':
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
return this.serializeOIDC(...arguments);
|
||||
default:
|
||||
return this.serializeDefault(...arguments);
|
||||
|
||||
@@ -8,7 +8,10 @@ import { trait } from 'miragejs';
|
||||
import permissions from '../helpers/permissions';
|
||||
import generateId from '../helpers/id';
|
||||
|
||||
const types = ['password', 'oidc'];
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPES_AUTH_METHOD,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default factory.extend({
|
||||
authorized_actions: () =>
|
||||
@@ -29,7 +32,7 @@ export default factory.extend({
|
||||
id: () => generateId('am_'),
|
||||
|
||||
// Cycle through available types
|
||||
type: (i) => types[i % types.length],
|
||||
type: (i) => TYPES_AUTH_METHOD[i % TYPES_AUTH_METHOD.length],
|
||||
|
||||
/**
|
||||
* Adds accounts (with associated users) to auth method and managed groups.
|
||||
@@ -43,7 +46,7 @@ export default factory.extend({
|
||||
user.update({ accountIds: [id] });
|
||||
});
|
||||
|
||||
if (type === 'oidc') {
|
||||
if (type === TYPE_AUTH_METHOD_OIDC) {
|
||||
server
|
||||
.createList('managed-group', 2, { scope, authMethod })
|
||||
.map((managedGroup) => {
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
import { Factory } from 'miragejs';
|
||||
import { faker } from '@faker-js/faker';
|
||||
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
/**
|
||||
* GeneratedAuthMethodModelFactory
|
||||
*/
|
||||
export default Factory.extend({
|
||||
type: 'password',
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
name: () => faker.random.words(),
|
||||
description: () => faker.random.words(),
|
||||
created_time: () => faker.date.recent(),
|
||||
@@ -20,7 +25,7 @@ export default Factory.extend({
|
||||
attributes: function () {
|
||||
let attrs;
|
||||
switch (this.type) {
|
||||
case 'oidc':
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
attrs = {
|
||||
api_url_prefix: 'http://127.0.0.1:9200',
|
||||
callback_url:
|
||||
|
||||
@@ -6,13 +6,23 @@
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Unit | Model | auth method', function (hooks) {
|
||||
setupTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let store;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
store = this.owner.lookup('service:store');
|
||||
});
|
||||
|
||||
test('it exists', function (assert) {
|
||||
let store = this.owner.lookup('service:store');
|
||||
let model = store.createRecord('auth-method', {});
|
||||
assert.ok(model);
|
||||
});
|
||||
@@ -32,13 +42,12 @@ module('Unit | Model | auth method', function (hooks) {
|
||||
return { id: '123abc' };
|
||||
}
|
||||
);
|
||||
const store = this.owner.lookup('service:store');
|
||||
store.push({
|
||||
data: {
|
||||
id: '123abc',
|
||||
type: 'auth-method',
|
||||
attributes: {
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
state: 'foobar',
|
||||
version: 1,
|
||||
scope: {
|
||||
@@ -51,4 +60,72 @@ module('Unit | Model | auth method', function (hooks) {
|
||||
const model = store.peekRecord('auth-method', '123abc');
|
||||
await model.changeState('foobar');
|
||||
});
|
||||
|
||||
test('it has isPassword property and returns the expected values', async function (assert) {
|
||||
assert.expect(3);
|
||||
const modelA = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
const modelB = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
const modelC = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
assert.true(modelA.isPassword);
|
||||
assert.false(modelB.isPassword);
|
||||
assert.false(modelC.isPassword);
|
||||
});
|
||||
|
||||
test('it has isOIDC property and returns the expected values', async function (assert) {
|
||||
assert.expect(3);
|
||||
const modelA = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
const modelB = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
const modelC = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
assert.true(modelA.isOIDC);
|
||||
assert.false(modelB.isOIDC);
|
||||
assert.false(modelC.isOIDC);
|
||||
});
|
||||
|
||||
test('it has isLDAP property and returns the expected values', async function (assert) {
|
||||
assert.expect(3);
|
||||
const modelA = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
const modelB = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
const modelC = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
assert.true(modelA.isLDAP);
|
||||
assert.false(modelB.isLDAP);
|
||||
assert.false(modelC.isLDAP);
|
||||
});
|
||||
|
||||
test('it has isUnknown property and returns the expected values', async function (assert) {
|
||||
assert.expect(4);
|
||||
const modelA = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
const modelB = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
const modelC = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
const modelD = store.createRecord('auth-method', {
|
||||
type: 'no-such-type',
|
||||
});
|
||||
assert.false(modelA.isUnknown);
|
||||
assert.false(modelB.isUnknown);
|
||||
assert.false(modelC.isUnknown);
|
||||
assert.true(modelD.isUnknown);
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,11 @@ import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Unit | Serializer | auth method', function (hooks) {
|
||||
setupTest(hooks);
|
||||
setupMirage(hooks);
|
||||
@@ -21,7 +26,9 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
test('it serializes password records', function (assert) {
|
||||
assert.expect(2);
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('auth-method', { type: 'password' });
|
||||
let record = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
@@ -36,7 +43,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
assert.expect(1);
|
||||
let store = this.owner.lookup('service:store');
|
||||
let record = store.createRecord('auth-method', {
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
name: 'OIDC Auth Method',
|
||||
state: 'foo',
|
||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||
@@ -62,7 +69,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
let serializedRecord = record.serialize();
|
||||
|
||||
assert.deepEqual(serializedRecord, {
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
name: 'OIDC Auth Method',
|
||||
description: null,
|
||||
attributes: {
|
||||
@@ -87,7 +94,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
const store = this.owner.lookup('service:store');
|
||||
const serializer = store.serializerFor('auth-method');
|
||||
const record = store.createRecord('auth-method', {
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
attributes: {
|
||||
state: 'foo',
|
||||
},
|
||||
@@ -175,7 +182,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
||||
max_age: maxAge,
|
||||
},
|
||||
version: 1,
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
id: 'oidc123',
|
||||
}));
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import AuthMethodAbility from 'api/abilities/auth-method';
|
||||
|
||||
export default class OverrideAuthMethodAbility extends AuthMethodAbility {
|
||||
/**
|
||||
* These override abilities are temporary and just part of Phase 1
|
||||
* of LDAP auth method implementation.
|
||||
*/
|
||||
|
||||
get canRead() {
|
||||
return !this.model.isLDAP && super.canRead;
|
||||
}
|
||||
|
||||
get canMakePrimary() {
|
||||
return !this.model.isLDAP;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { resourceFilter } from 'core/decorators/resource-filter';
|
||||
import { TYPES_AUTH_METHOD } from 'api/models/auth-method';
|
||||
|
||||
export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
// =services
|
||||
@@ -23,7 +24,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||
|
||||
// =attributes
|
||||
|
||||
@resourceFilter({ allowed: ['password', 'oidc'] }) type;
|
||||
@resourceFilter({ allowed: TYPES_AUTH_METHOD }) type;
|
||||
|
||||
// =methods
|
||||
|
||||
|
||||
@@ -9,6 +9,11 @@ import { getOwner } from '@ember/application';
|
||||
import { action } from '@ember/object';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifyError } from 'core/decorators/notify';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
// =services
|
||||
@@ -62,8 +67,8 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
const authenticatorName = `authenticator:${authMethod.type}`;
|
||||
const requestCookies = false;
|
||||
switch (authMethod.type) {
|
||||
case 'password':
|
||||
case 'ldap':
|
||||
case TYPE_AUTH_METHOD_PASSWORD:
|
||||
case TYPE_AUTH_METHOD_LDAP:
|
||||
await this.session.authenticate(
|
||||
authenticatorName,
|
||||
creds,
|
||||
@@ -72,7 +77,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||
);
|
||||
this.router.transitionTo('index');
|
||||
break;
|
||||
case 'oidc':
|
||||
case TYPE_AUTH_METHOD_OIDC:
|
||||
await this.startOIDCAuthentication(authenticatorName, {
|
||||
scope,
|
||||
authMethod,
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
{{#each @model as |authMethod|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell>
|
||||
{{#if (can 'read model' authMethod)}}
|
||||
{{#if (can 'read auth-method' authMethod)}}
|
||||
<LinkTo
|
||||
@route='scopes.scope.auth-methods.auth-method'
|
||||
@model={{authMethod.id}}
|
||||
@@ -154,29 +154,34 @@
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Rose::Dropdown
|
||||
@text={{t 'actions.manage'}}
|
||||
@dropdownRight={{true}}
|
||||
@iconOnly={{true}}
|
||||
@showCaret={{false}}
|
||||
@icon='flight-icons/svg/more-horizontal-16'
|
||||
as |dropdown|
|
||||
>
|
||||
{{#unless authMethod.isPrimary}}
|
||||
<dropdown.button
|
||||
{{on 'click' (route-action 'makePrimary' authMethod)}}
|
||||
>
|
||||
{{t 'resources.auth-method.actions.make-primary'}}
|
||||
</dropdown.button>
|
||||
{{/unless}}
|
||||
{{#if authMethod.isPrimary}}
|
||||
<dropdown.button
|
||||
{{on 'click' (route-action 'removeAsPrimary' authMethod)}}
|
||||
>
|
||||
{{t 'resources.auth-method.actions.remove-as-primary'}}
|
||||
</dropdown.button>
|
||||
{{/if}}
|
||||
</Rose::Dropdown>
|
||||
{{#if (can 'makePrimary auth-method' authMethod)}}
|
||||
<Rose::Dropdown
|
||||
@text={{t 'actions.manage'}}
|
||||
@dropdownRight={{true}}
|
||||
@iconOnly={{true}}
|
||||
@showCaret={{false}}
|
||||
@icon='flight-icons/svg/more-horizontal-16'
|
||||
as |dropdown|
|
||||
>
|
||||
{{#unless authMethod.isPrimary}}
|
||||
<dropdown.button
|
||||
{{on 'click' (route-action 'makePrimary' authMethod)}}
|
||||
>
|
||||
{{t 'resources.auth-method.actions.make-primary'}}
|
||||
</dropdown.button>
|
||||
{{/unless}}
|
||||
{{#if authMethod.isPrimary}}
|
||||
<dropdown.button
|
||||
{{on
|
||||
'click'
|
||||
(route-action 'removeAsPrimary' authMethod)
|
||||
}}
|
||||
>
|
||||
{{t 'resources.auth-method.actions.remove-as-primary'}}
|
||||
</dropdown.button>
|
||||
{{/if}}
|
||||
</Rose::Dropdown>
|
||||
{{/if}}
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
//invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | auth methods | oidc', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
@@ -49,7 +51,7 @@ module('Acceptance | auth methods | oidc', function (hooks) {
|
||||
});
|
||||
instances.authMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: 'oidc',
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
|
||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click, find } from '@ember/test-helpers';
|
||||
import { visit, currentURL, click } 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';
|
||||
@@ -14,23 +14,44 @@ import {
|
||||
// //currentSession,
|
||||
// //invalidateSession,
|
||||
} from 'ember-simple-auth/test-support';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_PASSWORD,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | auth methods | read', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
const AUTH_LINK_SELECTOR =
|
||||
'main tbody .rose-table-header-cell:nth-child(1) a';
|
||||
const AUTH_TYPE_SELECTOR =
|
||||
'tbody .rose-table-row:nth-child(1) .rose-table-cell';
|
||||
const AUTH_ACTIONS_SELECTOR =
|
||||
'tbody .rose-table-row:nth-child(1) .rose-table-cell:last-child .rose-dropdown';
|
||||
const LDAP_AUTH_LINK_SELECTOR = 'tbody .rose-table-row:nth-child(2) a';
|
||||
const LDAP_AUTH_TYPE_SELECTOR =
|
||||
'tbody .rose-table-row:nth-child(2) .rose-table-cell';
|
||||
const LDAP_AUTH_ACTIONS_SELECTOR =
|
||||
'tbody .rose-table-row:nth-child(2) .rose-table-cell:last-child .rose-dropdown';
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authMethod: null,
|
||||
passwordAuthMethodOrg: null,
|
||||
oidcAuthMethodGlobal: null,
|
||||
ldapAuthMethod: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
globalScope: null,
|
||||
orgScope: null,
|
||||
authMethods: null,
|
||||
newAuthMethod: null,
|
||||
authMethod: null,
|
||||
orgAuthMethods: null,
|
||||
globalAuthMethods: null,
|
||||
passwordAuthMethodOrg: null,
|
||||
oidcAuthMethodGlobal: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -41,37 +62,126 @@ module('Acceptance | auth methods | read', function (hooks) {
|
||||
type: 'org',
|
||||
scope: { id: 'global', type: 'global' },
|
||||
});
|
||||
instances.authMethod = this.server.create('auth-method', {
|
||||
instances.passwordAuthMethodOrg = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||
});
|
||||
instances.oidcAuthMethodGlobal = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
|
||||
// Generate route URLs for resources
|
||||
urls.globalScope = `/scopes/global`;
|
||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||
urls.authMethods = `${urls.orgScope}/auth-methods`;
|
||||
urls.newAuthMethod = `${urls.authMethods}/new?type=password`;
|
||||
urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`;
|
||||
urls.orgAuthMethods = `${urls.orgScope}/auth-methods`;
|
||||
urls.globalAuthMethods = `${urls.globalScope}/auth-methods`;
|
||||
urls.passwordAuthMethodOrg = `${urls.orgAuthMethods}/${instances.passwordAuthMethodOrg.id}`;
|
||||
urls.oidcAuthMethodGlobal = `${urls.globalAuthMethods}/${instances.oidcAuthMethodGlobal.id}`;
|
||||
});
|
||||
|
||||
test('visiting auth methods', async function (assert) {
|
||||
test('visiting auth methods in org scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.authMethods);
|
||||
await visit(urls.orgScope);
|
||||
|
||||
await click(`[href="${urls.orgAuthMethods}"]`);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(currentURL(), urls.authMethods);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.orgAuthMethods);
|
||||
});
|
||||
|
||||
test('can navigate to an auth method form', async function (assert) {
|
||||
test('visiting auth methods in global scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.authMethods);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
await visit(urls.globalScope);
|
||||
|
||||
await click(`[href="${urls.globalAuthMethods}"]`);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(currentURL(), urls.authMethod);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.globalAuthMethods);
|
||||
});
|
||||
|
||||
test('cannot navigate to an auth method form without proper authorization', async function (assert) {
|
||||
test('can navigate to an auth method form in org scope', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.orgScope);
|
||||
|
||||
await click(`[href="${urls.orgAuthMethods}"]`);
|
||||
|
||||
assert.dom(AUTH_TYPE_SELECTOR).hasText('Password');
|
||||
assert.dom(AUTH_ACTIONS_SELECTOR).exists();
|
||||
|
||||
await click(AUTH_LINK_SELECTOR);
|
||||
await a11yAudit();
|
||||
|
||||
assert.strictEqual(currentURL(), urls.passwordAuthMethodOrg);
|
||||
});
|
||||
|
||||
test('can navigate to an auth method form in global scope', async function (assert) {
|
||||
assert.expect(3);
|
||||
await visit(urls.globalScope);
|
||||
|
||||
await click(`[href="${urls.globalAuthMethods}"]`);
|
||||
|
||||
assert.dom(AUTH_TYPE_SELECTOR).hasText('OIDC');
|
||||
assert.dom(AUTH_ACTIONS_SELECTOR).exists();
|
||||
|
||||
await click(AUTH_LINK_SELECTOR);
|
||||
await a11yAudit();
|
||||
|
||||
assert.strictEqual(currentURL(), urls.oidcAuthMethodGlobal);
|
||||
});
|
||||
|
||||
test('cannot navigate to an auth method form without proper authorization in org scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.authMethod.authorized_actions =
|
||||
instances.authMethod.authorized_actions.filter((item) => item !== 'read');
|
||||
await visit(urls.authMethod);
|
||||
assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a'));
|
||||
instances.passwordAuthMethodOrg.authorized_actions =
|
||||
instances.passwordAuthMethodOrg.authorized_actions.filter(
|
||||
(item) => item !== 'read'
|
||||
);
|
||||
await visit(urls.orgScope);
|
||||
|
||||
await click(`[href="${urls.orgAuthMethods}"]`);
|
||||
|
||||
assert.dom(AUTH_LINK_SELECTOR).doesNotExist();
|
||||
});
|
||||
|
||||
test('cannot navigate to an auth method form without proper authorization in global scope', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.oidcAuthMethodGlobal.authorized_actions =
|
||||
instances.oidcAuthMethodGlobal.authorized_actions.filter(
|
||||
(item) => item !== 'read'
|
||||
);
|
||||
await visit(urls.globalScope);
|
||||
|
||||
await click(`[href="${urls.globalAuthMethods}"]`);
|
||||
|
||||
assert.dom(AUTH_LINK_SELECTOR).doesNotExist();
|
||||
});
|
||||
|
||||
test('cannot navigate to an ldap auth method form in global scope', async function (assert) {
|
||||
assert.expect(3);
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.global,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
await visit(urls.globalScope);
|
||||
|
||||
await click(`[href="${urls.globalAuthMethods}"]`);
|
||||
|
||||
assert.dom(LDAP_AUTH_LINK_SELECTOR).doesNotExist();
|
||||
assert.dom(LDAP_AUTH_TYPE_SELECTOR).hasText('LDAP');
|
||||
assert.dom(LDAP_AUTH_ACTIONS_SELECTOR).doesNotExist();
|
||||
});
|
||||
|
||||
test('cannot navigate to an ldap auth method form in org scope', async function (assert) {
|
||||
assert.expect(3);
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
await visit(urls.orgScope);
|
||||
|
||||
await click(`[href="${urls.orgAuthMethods}"]`);
|
||||
|
||||
assert.dom(LDAP_AUTH_LINK_SELECTOR).doesNotExist();
|
||||
assert.dom(LDAP_AUTH_TYPE_SELECTOR).hasText('LDAP');
|
||||
assert.dom(LDAP_AUTH_ACTIONS_SELECTOR).doesNotExist();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Unit | Abilities | auth-method', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
let canService;
|
||||
let store;
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
canService = this.owner.lookup('service:can');
|
||||
store = this.owner.lookup('service:store');
|
||||
});
|
||||
|
||||
test('cannot read LDAP auth-method when authorized', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
authorized_actions: ['read'],
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
assert.false(canService.can('read auth-method', authMethod));
|
||||
});
|
||||
|
||||
test('cannot read LDAP auth-method when unauthorized', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
authorized_actions: [],
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
assert.false(canService.can('read auth-method', authMethod));
|
||||
});
|
||||
|
||||
test('can read non-LDAP auth-method when authorized', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
authorized_actions: ['read'],
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
assert.true(canService.can('read auth-method', authMethod));
|
||||
});
|
||||
|
||||
test('cannot read non-LDAP auth-method when unauthorized', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
authorized_actions: [],
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
assert.false(canService.can('read auth-method', authMethod));
|
||||
});
|
||||
|
||||
test('cannot make LDAP auth-method primary', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
assert.false(canService.can('makePrimary auth-method', authMethod));
|
||||
});
|
||||
|
||||
test('can make non-LDAP auth-method primary', function (assert) {
|
||||
assert.expect(1);
|
||||
const authMethod = store.createRecord('auth-method', {
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
assert.true(canService.can('makePrimary auth-method', authMethod));
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user