Icu 9202 disable all actions for ldap auth method (#1683)
* refactor: 💡 disable all actions for ldap auth-method ✅ Closes: ICU-9202
This commit is contained in:
1 parent
4c80f8d8ff
commit
3b3d6ab50f
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 GeneratedAuthMethodModel from '../generated/models/auth-method';
|
||||||
import { equal } from '@ember/object/computed';
|
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.
|
* Enum options per auth method type and field.
|
||||||
*/
|
*/
|
||||||
@@ -44,14 +54,28 @@ export default class AuthMethodModel extends GeneratedAuthMethodModel {
|
|||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get isPassword() {
|
get isPassword() {
|
||||||
return this.type === 'password';
|
return this.type === TYPE_AUTH_METHOD_PASSWORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
get isOIDC() {
|
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 ApplicationSerializer from './application';
|
||||||
|
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||||
|
|
||||||
export default class AuthMethodSerializer extends ApplicationSerializer {
|
export default class AuthMethodSerializer extends ApplicationSerializer {
|
||||||
// =methods
|
// =methods
|
||||||
|
|
||||||
@@ -15,7 +17,7 @@ export default class AuthMethodSerializer extends ApplicationSerializer {
|
|||||||
*/
|
*/
|
||||||
serialize(snapshot) {
|
serialize(snapshot) {
|
||||||
switch (snapshot.record.type) {
|
switch (snapshot.record.type) {
|
||||||
case 'oidc':
|
case TYPE_AUTH_METHOD_OIDC:
|
||||||
return this.serializeOIDC(...arguments);
|
return this.serializeOIDC(...arguments);
|
||||||
default:
|
default:
|
||||||
return this.serializeDefault(...arguments);
|
return this.serializeDefault(...arguments);
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ import { trait } from 'miragejs';
|
|||||||
import permissions from '../helpers/permissions';
|
import permissions from '../helpers/permissions';
|
||||||
import generateId from '../helpers/id';
|
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({
|
export default factory.extend({
|
||||||
authorized_actions: () =>
|
authorized_actions: () =>
|
||||||
@@ -29,7 +32,7 @@ export default factory.extend({
|
|||||||
id: () => generateId('am_'),
|
id: () => generateId('am_'),
|
||||||
|
|
||||||
// Cycle through available types
|
// 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.
|
* Adds accounts (with associated users) to auth method and managed groups.
|
||||||
@@ -43,7 +46,7 @@ export default factory.extend({
|
|||||||
user.update({ accountIds: [id] });
|
user.update({ accountIds: [id] });
|
||||||
});
|
});
|
||||||
|
|
||||||
if (type === 'oidc') {
|
if (type === TYPE_AUTH_METHOD_OIDC) {
|
||||||
server
|
server
|
||||||
.createList('managed-group', 2, { scope, authMethod })
|
.createList('managed-group', 2, { scope, authMethod })
|
||||||
.map((managedGroup) => {
|
.map((managedGroup) => {
|
||||||
|
|||||||
@@ -6,11 +6,16 @@
|
|||||||
import { Factory } from 'miragejs';
|
import { Factory } from 'miragejs';
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
|
|
||||||
|
import {
|
||||||
|
TYPE_AUTH_METHOD_PASSWORD,
|
||||||
|
TYPE_AUTH_METHOD_OIDC,
|
||||||
|
} from 'api/models/auth-method';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GeneratedAuthMethodModelFactory
|
* GeneratedAuthMethodModelFactory
|
||||||
*/
|
*/
|
||||||
export default Factory.extend({
|
export default Factory.extend({
|
||||||
type: 'password',
|
type: TYPE_AUTH_METHOD_PASSWORD,
|
||||||
name: () => faker.random.words(),
|
name: () => faker.random.words(),
|
||||||
description: () => faker.random.words(),
|
description: () => faker.random.words(),
|
||||||
created_time: () => faker.date.recent(),
|
created_time: () => faker.date.recent(),
|
||||||
@@ -20,7 +25,7 @@ export default Factory.extend({
|
|||||||
attributes: function () {
|
attributes: function () {
|
||||||
let attrs;
|
let attrs;
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case 'oidc':
|
case TYPE_AUTH_METHOD_OIDC:
|
||||||
attrs = {
|
attrs = {
|
||||||
api_url_prefix: 'http://127.0.0.1:9200',
|
api_url_prefix: 'http://127.0.0.1:9200',
|
||||||
callback_url:
|
callback_url:
|
||||||
|
|||||||
@@ -6,13 +6,23 @@
|
|||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupTest } from 'ember-qunit';
|
import { setupTest } from 'ember-qunit';
|
||||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
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) {
|
module('Unit | Model | auth method', function (hooks) {
|
||||||
setupTest(hooks);
|
setupTest(hooks);
|
||||||
setupMirage(hooks);
|
setupMirage(hooks);
|
||||||
|
|
||||||
|
let store;
|
||||||
|
|
||||||
|
hooks.beforeEach(function () {
|
||||||
|
store = this.owner.lookup('service:store');
|
||||||
|
});
|
||||||
|
|
||||||
test('it exists', function (assert) {
|
test('it exists', function (assert) {
|
||||||
let store = this.owner.lookup('service:store');
|
|
||||||
let model = store.createRecord('auth-method', {});
|
let model = store.createRecord('auth-method', {});
|
||||||
assert.ok(model);
|
assert.ok(model);
|
||||||
});
|
});
|
||||||
@@ -32,13 +42,12 @@ module('Unit | Model | auth method', function (hooks) {
|
|||||||
return { id: '123abc' };
|
return { id: '123abc' };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const store = this.owner.lookup('service:store');
|
|
||||||
store.push({
|
store.push({
|
||||||
data: {
|
data: {
|
||||||
id: '123abc',
|
id: '123abc',
|
||||||
type: 'auth-method',
|
type: 'auth-method',
|
||||||
attributes: {
|
attributes: {
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
state: 'foobar',
|
state: 'foobar',
|
||||||
version: 1,
|
version: 1,
|
||||||
scope: {
|
scope: {
|
||||||
@@ -51,4 +60,72 @@ module('Unit | Model | auth method', function (hooks) {
|
|||||||
const model = store.peekRecord('auth-method', '123abc');
|
const model = store.peekRecord('auth-method', '123abc');
|
||||||
await model.changeState('foobar');
|
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 { setupTest } from 'ember-qunit';
|
||||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
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) {
|
module('Unit | Serializer | auth method', function (hooks) {
|
||||||
setupTest(hooks);
|
setupTest(hooks);
|
||||||
setupMirage(hooks);
|
setupMirage(hooks);
|
||||||
@@ -21,7 +26,9 @@ module('Unit | Serializer | auth method', function (hooks) {
|
|||||||
test('it serializes password records', function (assert) {
|
test('it serializes password records', function (assert) {
|
||||||
assert.expect(2);
|
assert.expect(2);
|
||||||
let store = this.owner.lookup('service:store');
|
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();
|
let serializedRecord = record.serialize();
|
||||||
|
|
||||||
@@ -36,7 +43,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
|||||||
assert.expect(1);
|
assert.expect(1);
|
||||||
let store = this.owner.lookup('service:store');
|
let store = this.owner.lookup('service:store');
|
||||||
let record = store.createRecord('auth-method', {
|
let record = store.createRecord('auth-method', {
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
name: 'OIDC Auth Method',
|
name: 'OIDC Auth Method',
|
||||||
state: 'foo',
|
state: 'foo',
|
||||||
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
account_claim_maps: [{ from: 'foo', to: 'bar' }],
|
||||||
@@ -62,7 +69,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
|||||||
let serializedRecord = record.serialize();
|
let serializedRecord = record.serialize();
|
||||||
|
|
||||||
assert.deepEqual(serializedRecord, {
|
assert.deepEqual(serializedRecord, {
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
name: 'OIDC Auth Method',
|
name: 'OIDC Auth Method',
|
||||||
description: null,
|
description: null,
|
||||||
attributes: {
|
attributes: {
|
||||||
@@ -87,7 +94,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
|||||||
const store = this.owner.lookup('service:store');
|
const store = this.owner.lookup('service:store');
|
||||||
const serializer = store.serializerFor('auth-method');
|
const serializer = store.serializerFor('auth-method');
|
||||||
const record = store.createRecord('auth-method', {
|
const record = store.createRecord('auth-method', {
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
attributes: {
|
attributes: {
|
||||||
state: 'foo',
|
state: 'foo',
|
||||||
},
|
},
|
||||||
@@ -175,7 +182,7 @@ module('Unit | Serializer | auth method', function (hooks) {
|
|||||||
max_age: maxAge,
|
max_age: maxAge,
|
||||||
},
|
},
|
||||||
version: 1,
|
version: 1,
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
id: 'oidc123',
|
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 { confirm } from 'core/decorators/confirm';
|
||||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||||
import { resourceFilter } from 'core/decorators/resource-filter';
|
import { resourceFilter } from 'core/decorators/resource-filter';
|
||||||
|
import { TYPES_AUTH_METHOD } from 'api/models/auth-method';
|
||||||
|
|
||||||
export default class ScopesScopeAuthMethodsRoute extends Route {
|
export default class ScopesScopeAuthMethodsRoute extends Route {
|
||||||
// =services
|
// =services
|
||||||
@@ -23,7 +24,7 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
|
|||||||
|
|
||||||
// =attributes
|
// =attributes
|
||||||
|
|
||||||
@resourceFilter({ allowed: ['password', 'oidc'] }) type;
|
@resourceFilter({ allowed: TYPES_AUTH_METHOD }) type;
|
||||||
|
|
||||||
// =methods
|
// =methods
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import { getOwner } from '@ember/application';
|
|||||||
import { action } from '@ember/object';
|
import { action } from '@ember/object';
|
||||||
import { loading } from 'ember-loading';
|
import { loading } from 'ember-loading';
|
||||||
import { notifyError } from 'core/decorators/notify';
|
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 {
|
export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
||||||
// =services
|
// =services
|
||||||
@@ -62,8 +67,8 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
|||||||
const authenticatorName = `authenticator:${authMethod.type}`;
|
const authenticatorName = `authenticator:${authMethod.type}`;
|
||||||
const requestCookies = false;
|
const requestCookies = false;
|
||||||
switch (authMethod.type) {
|
switch (authMethod.type) {
|
||||||
case 'password':
|
case TYPE_AUTH_METHOD_PASSWORD:
|
||||||
case 'ldap':
|
case TYPE_AUTH_METHOD_LDAP:
|
||||||
await this.session.authenticate(
|
await this.session.authenticate(
|
||||||
authenticatorName,
|
authenticatorName,
|
||||||
creds,
|
creds,
|
||||||
@@ -72,7 +77,7 @@ export default class ScopesScopeAuthenticateMethodRoute extends Route {
|
|||||||
);
|
);
|
||||||
this.router.transitionTo('index');
|
this.router.transitionTo('index');
|
||||||
break;
|
break;
|
||||||
case 'oidc':
|
case TYPE_AUTH_METHOD_OIDC:
|
||||||
await this.startOIDCAuthentication(authenticatorName, {
|
await this.startOIDCAuthentication(authenticatorName, {
|
||||||
scope,
|
scope,
|
||||||
authMethod,
|
authMethod,
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
{{#each @model as |authMethod|}}
|
{{#each @model as |authMethod|}}
|
||||||
<body.row as |row|>
|
<body.row as |row|>
|
||||||
<row.headerCell>
|
<row.headerCell>
|
||||||
{{#if (can 'read model' authMethod)}}
|
{{#if (can 'read auth-method' authMethod)}}
|
||||||
<LinkTo
|
<LinkTo
|
||||||
@route='scopes.scope.auth-methods.auth-method'
|
@route='scopes.scope.auth-methods.auth-method'
|
||||||
@model={{authMethod.id}}
|
@model={{authMethod.id}}
|
||||||
@@ -154,29 +154,34 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
</row.cell>
|
</row.cell>
|
||||||
<row.cell>
|
<row.cell>
|
||||||
<Rose::Dropdown
|
{{#if (can 'makePrimary auth-method' authMethod)}}
|
||||||
@text={{t 'actions.manage'}}
|
<Rose::Dropdown
|
||||||
@dropdownRight={{true}}
|
@text={{t 'actions.manage'}}
|
||||||
@iconOnly={{true}}
|
@dropdownRight={{true}}
|
||||||
@showCaret={{false}}
|
@iconOnly={{true}}
|
||||||
@icon='flight-icons/svg/more-horizontal-16'
|
@showCaret={{false}}
|
||||||
as |dropdown|
|
@icon='flight-icons/svg/more-horizontal-16'
|
||||||
>
|
as |dropdown|
|
||||||
{{#unless authMethod.isPrimary}}
|
>
|
||||||
<dropdown.button
|
{{#unless authMethod.isPrimary}}
|
||||||
{{on 'click' (route-action 'makePrimary' authMethod)}}
|
<dropdown.button
|
||||||
>
|
{{on 'click' (route-action 'makePrimary' authMethod)}}
|
||||||
{{t 'resources.auth-method.actions.make-primary'}}
|
>
|
||||||
</dropdown.button>
|
{{t 'resources.auth-method.actions.make-primary'}}
|
||||||
{{/unless}}
|
</dropdown.button>
|
||||||
{{#if authMethod.isPrimary}}
|
{{/unless}}
|
||||||
<dropdown.button
|
{{#if authMethod.isPrimary}}
|
||||||
{{on 'click' (route-action 'removeAsPrimary' authMethod)}}
|
<dropdown.button
|
||||||
>
|
{{on
|
||||||
{{t 'resources.auth-method.actions.remove-as-primary'}}
|
'click'
|
||||||
</dropdown.button>
|
(route-action 'removeAsPrimary' authMethod)
|
||||||
{{/if}}
|
}}
|
||||||
</Rose::Dropdown>
|
>
|
||||||
|
{{t 'resources.auth-method.actions.remove-as-primary'}}
|
||||||
|
</dropdown.button>
|
||||||
|
{{/if}}
|
||||||
|
</Rose::Dropdown>
|
||||||
|
{{/if}}
|
||||||
</row.cell>
|
</row.cell>
|
||||||
</body.row>
|
</body.row>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import {
|
|||||||
//invalidateSession,
|
//invalidateSession,
|
||||||
} from 'ember-simple-auth/test-support';
|
} from 'ember-simple-auth/test-support';
|
||||||
|
|
||||||
|
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||||
|
|
||||||
module('Acceptance | auth methods | oidc', function (hooks) {
|
module('Acceptance | auth methods | oidc', function (hooks) {
|
||||||
setupApplicationTest(hooks);
|
setupApplicationTest(hooks);
|
||||||
setupMirage(hooks);
|
setupMirage(hooks);
|
||||||
@@ -49,7 +51,7 @@ module('Acceptance | auth methods | oidc', function (hooks) {
|
|||||||
});
|
});
|
||||||
instances.authMethod = this.server.create('auth-method', {
|
instances.authMethod = this.server.create('auth-method', {
|
||||||
scope: instances.scopes.org,
|
scope: instances.scopes.org,
|
||||||
type: 'oidc',
|
type: TYPE_AUTH_METHOD_OIDC,
|
||||||
});
|
});
|
||||||
|
|
||||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { module, test } from 'qunit';
|
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 { setupApplicationTest } from 'ember-qunit';
|
||||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||||
@@ -14,23 +14,44 @@ import {
|
|||||||
// //currentSession,
|
// //currentSession,
|
||||||
// //invalidateSession,
|
// //invalidateSession,
|
||||||
} from 'ember-simple-auth/test-support';
|
} 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) {
|
module('Acceptance | auth methods | read', function (hooks) {
|
||||||
setupApplicationTest(hooks);
|
setupApplicationTest(hooks);
|
||||||
setupMirage(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 = {
|
const instances = {
|
||||||
scopes: {
|
scopes: {
|
||||||
global: null,
|
global: null,
|
||||||
org: null,
|
org: null,
|
||||||
},
|
},
|
||||||
authMethod: null,
|
passwordAuthMethodOrg: null,
|
||||||
|
oidcAuthMethodGlobal: null,
|
||||||
|
ldapAuthMethod: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const urls = {
|
const urls = {
|
||||||
|
globalScope: null,
|
||||||
orgScope: null,
|
orgScope: null,
|
||||||
authMethods: null,
|
orgAuthMethods: null,
|
||||||
newAuthMethod: null,
|
globalAuthMethods: null,
|
||||||
authMethod: null,
|
passwordAuthMethodOrg: null,
|
||||||
|
oidcAuthMethodGlobal: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
hooks.beforeEach(function () {
|
hooks.beforeEach(function () {
|
||||||
@@ -41,37 +62,126 @@ module('Acceptance | auth methods | read', function (hooks) {
|
|||||||
type: 'org',
|
type: 'org',
|
||||||
scope: { id: 'global', type: 'global' },
|
scope: { id: 'global', type: 'global' },
|
||||||
});
|
});
|
||||||
instances.authMethod = this.server.create('auth-method', {
|
instances.passwordAuthMethodOrg = this.server.create('auth-method', {
|
||||||
scope: instances.scopes.org,
|
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
|
// Generate route URLs for resources
|
||||||
|
urls.globalScope = `/scopes/global`;
|
||||||
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
urls.orgScope = `/scopes/${instances.scopes.org.id}`;
|
||||||
urls.authMethods = `${urls.orgScope}/auth-methods`;
|
urls.orgAuthMethods = `${urls.orgScope}/auth-methods`;
|
||||||
urls.newAuthMethod = `${urls.authMethods}/new?type=password`;
|
urls.globalAuthMethods = `${urls.globalScope}/auth-methods`;
|
||||||
urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`;
|
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);
|
assert.expect(1);
|
||||||
await visit(urls.authMethods);
|
await visit(urls.orgScope);
|
||||||
|
|
||||||
|
await click(`[href="${urls.orgAuthMethods}"]`);
|
||||||
await a11yAudit();
|
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);
|
assert.expect(1);
|
||||||
await visit(urls.authMethods);
|
await visit(urls.globalScope);
|
||||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
|
||||||
|
await click(`[href="${urls.globalAuthMethods}"]`);
|
||||||
await a11yAudit();
|
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);
|
assert.expect(1);
|
||||||
instances.authMethod.authorized_actions =
|
instances.passwordAuthMethodOrg.authorized_actions =
|
||||||
instances.authMethod.authorized_actions.filter((item) => item !== 'read');
|
instances.passwordAuthMethodOrg.authorized_actions.filter(
|
||||||
await visit(urls.authMethod);
|
(item) => item !== 'read'
|
||||||
assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a'));
|
);
|
||||||
|
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