diff --git a/addons/api/addon/abilities/credential-library.js b/addons/api/addon/abilities/credential-library.js new file mode 100644 index 000000000..5968a80f0 --- /dev/null +++ b/addons/api/addon/abilities/credential-library.js @@ -0,0 +1,15 @@ +import ModelAbility from './model'; +/** + * Provides abilities for credential. + */ +export default class CredentialLibaryAbility extends ModelAbility { + // =permissions + + /** + * Only "known" credential libary types may be read. + * @type {boolean} + */ + get canRead() { + return !this.model.isUnknown && this.hasAuthorizedAction('read'); + } +} diff --git a/addons/api/addon/abilities/credential.js b/addons/api/addon/abilities/credential.js new file mode 100644 index 000000000..115856118 --- /dev/null +++ b/addons/api/addon/abilities/credential.js @@ -0,0 +1,15 @@ +import ModelAbility from "./model"; +/** + * Provides abilities for credential. + */ +export default class CredentialAbility extends ModelAbility { + // =permissions + + /** + * Only "known" credential types may be read. + * @type {boolean} + */ + get canRead() { + return !this.model.isUnknown && this.hasAuthorizedAction('read'); + } +} \ No newline at end of file diff --git a/addons/api/addon/models/credential-library.js b/addons/api/addon/models/credential-library.js index 773478638..f864abcbb 100644 --- a/addons/api/addon/models/credential-library.js +++ b/addons/api/addon/models/credential-library.js @@ -7,4 +7,27 @@ export const options = { http_method: ['GET', 'POST'], }; -export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel {} +/** + * Supported Credential Library types. + */ +export const types = ['vault']; + +export default class CredentialLibraryModel extends GeneratedCredentialLibraryModel { + // =attributes + + /** + * True if credential is an unknown type. + * @type {boolean} + */ + get isUnknown() { + return !types.includes(this.type); + } + + /** + * True if credential is a vault type. + * @type {boolean} + */ + get isVault() { + return this.type === 'vault'; + } +} diff --git a/addons/api/addon/models/credential.js b/addons/api/addon/models/credential.js index 877de41dc..3fee8cf9d 100644 --- a/addons/api/addon/models/credential.js +++ b/addons/api/addon/models/credential.js @@ -1,10 +1,23 @@ import GeneratedCredentialModel from '../generated/models/credential'; import { equal } from '@ember/object/computed'; +/** + * Supported Credential types. + */ +export const types = ['username_password', 'ssh_private_key']; + export default class CredentialModel extends GeneratedCredentialModel { // =attributes /** * @type {boolean} */ @equal('type', 'username_password') isUsernamePassword; + + /** + * True if credential is an unknown type. + * @type {boolean} + */ + get isUnknown() { + return !types.includes(this.type); + } } diff --git a/addons/api/app/abilities/credential-library.js b/addons/api/app/abilities/credential-library.js new file mode 100644 index 000000000..c55e5afe7 --- /dev/null +++ b/addons/api/app/abilities/credential-library.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/credential-library'; diff --git a/addons/api/app/abilities/credential.js b/addons/api/app/abilities/credential.js new file mode 100644 index 000000000..af95b315a --- /dev/null +++ b/addons/api/app/abilities/credential.js @@ -0,0 +1 @@ +export { default } from 'api/abilities/credential'; \ No newline at end of file diff --git a/addons/api/mirage/factories/credential-store.js b/addons/api/mirage/factories/credential-store.js index 39337f230..3b10f756e 100644 --- a/addons/api/mirage/factories/credential-store.js +++ b/addons/api/mirage/factories/credential-store.js @@ -59,7 +59,7 @@ export default factory.extend({ break; case 'static': default: - server.createList('credential', 2, { + server.createList('credential', 3, { scope, credentialStore, }); diff --git a/addons/api/mirage/factories/credential.js b/addons/api/mirage/factories/credential.js index eac680c96..58e1f5351 100644 --- a/addons/api/mirage/factories/credential.js +++ b/addons/api/mirage/factories/credential.js @@ -3,7 +3,7 @@ import { faker } from '@faker-js/faker'; import permissions from '../helpers/permissions'; import generatedId from '../helpers/id'; -const types = ['username_password', 'ssh_private_key']; +const types = ['username_password', 'ssh_private_key', 'json']; export default factory.extend({ type: (i) => types[i % types.length], @@ -13,6 +13,8 @@ export default factory.extend({ return generatedId('credspk_'); case 'username_password': return generatedId('credup_'); + case 'json': + return generatedId('credjson_'); } }, authorized_actions: () => diff --git a/addons/api/tests/unit/models/credential-library-test.js b/addons/api/tests/unit/models/credential-library-test.js index 4cd00ab05..12610cf8c 100644 --- a/addons/api/tests/unit/models/credential-library-test.js +++ b/addons/api/tests/unit/models/credential-library-test.js @@ -4,10 +4,19 @@ import { setupTest } from 'ember-qunit'; module('Unit | Model | credential library', function (hooks) { setupTest(hooks); - // Replace this with your real tests. test('it exists', function (assert) { let store = this.owner.lookup('service:store'); let model = store.createRecord('credential-library', {}); assert.ok(model); }); + + test('it has isUnknown property and returns the expected values', async function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const modelA = store.createRecord('credential-library', { type: 'vault' }); + const modelB = store.createRecord('credential-library', { type: 'unknown' }); + + assert.false(modelA.isUnknown); + assert.true(modelB.isUnknown); + }); }); diff --git a/addons/api/tests/unit/models/credential-test.js b/addons/api/tests/unit/models/credential-test.js index 7cf89e154..1a091665a 100644 --- a/addons/api/tests/unit/models/credential-test.js +++ b/addons/api/tests/unit/models/credential-test.js @@ -9,4 +9,26 @@ module('Unit | Model | credential', function (hooks) { const model = store.createRecord('credential', {}); assert.ok(model); }); + + test('it has isUsernamePassword property and returns the expected values', async function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const modelA = store.createRecord('credential', { type: 'username_password' }); + const modelB = store.createRecord('credential', { type: 'ssh_private_key' }); + + assert.true(modelA.isUsernamePassword); + assert.false(modelB.isUsernamePassword); + }); + + test('it has isUnknown property and returns the expected values', async function (assert) { + assert.expect(3); + const store = this.owner.lookup('service:store'); + const modelA = store.createRecord('credential', { type: 'username_password' }); + const modelB = store.createRecord('credential', { type: 'ssh_private_key' }); + const modelC = store.createRecord('credential', { type: 'unknown' }); + + assert.false(modelA.isUnknown); + assert.false(modelB.isUnknown); + assert.true(modelC.isUnknown); + }); }); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 3bb660319..74fd773ad 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -304,10 +304,6 @@ target: brokered-credential-source: title: Brokered Credential title_plural: Brokered Credentials - types: - vault: Vault - username_password: Username & Password - ssh_private_key: Username & Key Pair messages: welcome: title: Welcome to brokered credentials @@ -321,10 +317,6 @@ target: injected-application-credential-source: title: Injected Application Credential title_plural: Injected Application Credentials - types: - vault: Vault - username_password: Username & Password - ssh_private_key: Username & Key Pair messages: welcome: title: Welcome to Injected Application credentials @@ -403,7 +395,6 @@ credential-library: types: vault: Vault static: Static - username_password: Username & Password credential: title: Credential title_plural: Credentials @@ -418,6 +409,7 @@ credential: types: username_password: Username & Password ssh_private_key: Username & Key Pair + unknown: Unknown help: username_password: This host requires a username and password to connect. ssh_private_key: This host requires a username, public key, and private key to connect. diff --git a/ui/admin/app/components/cred-source-type-badge/index.hbs b/ui/admin/app/components/cred-source-type-badge/index.hbs new file mode 100644 index 000000000..122d02a18 --- /dev/null +++ b/ui/admin/app/components/cred-source-type-badge/index.hbs @@ -0,0 +1,13 @@ +{{#if @model.isUnknown}} + + {{t 'resources.credential.types.unknown'}} + +{{else if @model.isVault}} + + {{t (concat 'resources.credential-library.types.' @model.type)}} + +{{else}} + + {{t (concat 'resources.credential.types.' @model.type)}} + +{{/if}} diff --git a/ui/admin/app/components/form/target/add-brokered-credential-sources/index.hbs b/ui/admin/app/components/form/target/add-brokered-credential-sources/index.hbs index 9e0945e13..e8c4070bc 100644 --- a/ui/admin/app/components/form/target/add-brokered-credential-sources/index.hbs +++ b/ui/admin/app/components/form/target/add-brokered-credential-sources/index.hbs @@ -31,12 +31,7 @@ {{credentialSource.name}} - {{t - (concat - 'resources.target.brokered-credential-source.types.' - credentialSource.type - ) - }} + {{/each}} diff --git a/ui/admin/app/components/form/target/add-injected-application-credential-sources/index.hbs b/ui/admin/app/components/form/target/add-injected-application-credential-sources/index.hbs index 955d0f3fe..216f69108 100644 --- a/ui/admin/app/components/form/target/add-injected-application-credential-sources/index.hbs +++ b/ui/admin/app/components/form/target/add-injected-application-credential-sources/index.hbs @@ -32,12 +32,7 @@ {{credentialSource.name}} - {{t - (concat - 'resources.target.injected-application-credential-source.types.' - credentialSource.type - ) - }} + {{/each}} diff --git a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs index 77f9385b8..b5f65aba6 100644 --- a/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs +++ b/ui/admin/app/templates/scopes/scope/credential-stores/credential-store/credential-libraries/index.hbs @@ -35,7 +35,7 @@ {{#each @model as |credentialLibrary|}} - {{#if (can 'read model' credentialLibrary)}} + {{#if (can 'read credential-library' credentialLibrary)}} - {{#if (can 'read model' credential)}} + {{#if (can 'read credential' credential)}} {{credential.description}}

- {{t - (concat 'resources.credential.types.' credential.type) - }} + - {{#if brokeredCredentialSource.isUsernamePassword}} - - {{brokeredCredentialSource.displayName}} - + {{#if brokeredCredentialSource.isUnknown}} + {{brokeredCredentialSource.displayName}} {{else}} - - {{brokeredCredentialSource.displayName}} - + {{#if brokeredCredentialSource.isUsernamePassword}} + + {{brokeredCredentialSource.displayName}} + + {{else}} + + {{brokeredCredentialSource.displayName}} + + {{/if}} {{/if}}

{{brokeredCredentialSource.description}}

- {{t - (concat - 'resources.target.brokered-credential-source.types.' - brokeredCredentialSource.type - ) - }} + - {{#if injectedApplicationCredentialSource.isUsernamePassword}} - - {{injectedApplicationCredentialSource.displayName}} - + {{#if injectedApplicationCredentialSource.isUnknown}} + {{injectedApplicationCredentialSource.displayName}} {{else}} - - {{injectedApplicationCredentialSource.displayName}} - + {{#if injectedApplicationCredentialSource.isUsernamePassword}} + + {{injectedApplicationCredentialSource.displayName}} + + {{else}} + + {{injectedApplicationCredentialSource.displayName}} + + {{/if}} {{/if}}

{{injectedApplicationCredentialSource.description}}

- {{t - (concat - 'resources.target.injected-application-credential-source.types.' - injectedApplicationCredentialSource.type - ) - }} +