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:
lisbet-alvarez authored and GitHub committed 2023-05-11 15:15:31 -07:00
1 parent 4c80f8d8ff
commit 3b3d6ab50f
14 files changed
+424 -67

No files matched your search

+20
View File
@@ -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');
}
}
+26 -2
View File
@@ -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);
}
/**
+3 -1
View File
@@ -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);
+6 -3
View File
@@ -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',
}));
+21
View File
@@ -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));
});
});