diff --git a/addons/api/addon/serializers/fragment-credential-store-attributes.js b/addons/api/addon/serializers/fragment-credential-store-attributes.js index 547c6a4f7..883a823aa 100644 --- a/addons/api/addon/serializers/fragment-credential-store-attributes.js +++ b/addons/api/addon/serializers/fragment-credential-store-attributes.js @@ -19,6 +19,16 @@ export default class FragmentCredentialStoreAttributesSerializer extends JSONSer if (type === 'string' && json[key] === '') json[key] = null; // Do not serialize read-only attributes. if (options.readOnly) delete json[key]; + // Token cannot be unset. If it's falsy, it must be removed. + if (key === 'token' && !json[key]) delete json[key]; + // Client certificate key cannot be unset when certificate is set. + // If it's falsy, it must be removed. + if ( + key === 'client_certificate_key' && + !json[key] && + json['client_certificate'] + ) + delete json[key]; return value; } } diff --git a/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js b/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js index 7fbbd0744..cfa00734b 100644 --- a/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js +++ b/addons/api/tests/unit/serializers/fragment-credential-store-attributes-test.js @@ -6,26 +6,112 @@ module( function (hooks) { setupTest(hooks); - // Replace this with your real tests. - test('it exists', function (assert) { - let store = this.owner.lookup('service:store'); - let serializer = store.serializerFor( - 'fragment-credential-store-attributes' + test('it serializes empty strings to null', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( + 'fragment-credential-store-attributes', + { + address: '', + ca_cert: '', + client_certificate: '', + client_certificate_key: '', + namespace: '', + tls_server_name: '', + tls_skip_verify: false, + } ); - - assert.ok(serializer); + let serializedRecord = record.serialize(); + assert.deepEqual(serializedRecord, { + address: null, + ca_cert: null, + client_certificate: null, + client_certificate_key: null, + namespace: null, + tls_server_name: null, + tls_skip_verify: false, + }); }); - test('it serializes records', function (assert) { - let store = this.owner.lookup('service:store'); - let record = store.createRecord( + test('it does not serialize token if present but falsy', function (assert) { + assert.expect(1); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( 'fragment-credential-store-attributes', - {} + { + token: null, + address: 'http://localhost:5000', + ca_cert: 'ca-cert-123', + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + address: 'http://localhost:5000', + ca_cert: 'ca-cert-123', + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'token attribute is not expected' + ); + }); + + test('it does not serialize client certificate key if present but falsy when client certificate is present', function (assert) { + assert.expect(2); + const store = this.owner.lookup('service:store'); + const record = store.createRecord( + 'fragment-credential-store-attributes', + { + client_certificate: 'client-cert-123', + client_certificate_key: '', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + } + ); + let serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + client_certificate: 'client-cert-123', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'client certificate key attribute is not expected' ); - let serializedRecord = record.serialize(); - - assert.ok(serializedRecord); + record.client_certificate_key = 'client-cert-key-456'; + serializedRecord = record.serialize(); + assert.deepEqual( + serializedRecord, + { + client_certificate: 'client-cert-123', + client_certificate_key: 'client-cert-key-456', + address: 'http://localhost:5000', + token: 'foo', + ca_cert: 'ca-cert-123', + namespace: 'foobar', + tls_server_name: 'yes', + tls_skip_verify: false, + }, + 'client certificate key attribute is expected' + ); }); } ); diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index a448c0011..9d001037f 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -290,6 +290,35 @@ credential-store: delete: Delete Credential Store types: vault: Vault + form: + address: + label: Address + help: The address of the Vault server. This should be a complete URL such as https://127.0.0.1:8200. + namespace: + label: Namespace + help: A Vault namespace. Requires Vault Enterprise. + ca_cert: + label: CA Certificate + help: A PEM-encoded CA certificate to verify the Vault server's TLS certificate. + tls_server_name: + label: TLS Server Name + help: Name to use as the SNI host when connecting to Vault via TLS. + tls_skip_verify: + label: TLS Skip Verify + help: Disable verification of TLS certificates. Using this option is highly discouraged as it decreases the security of data transmissions to and from the Vault server. + token: + label: Token + help: A token used for accessing Vault. + token_hmac: + label: Token HMAC + client_certificate: + label: Client Certificate + help: A PEM-encoded client certificate to use for TLS authentication to the Vault server. + client_certificate_key: + label: Client Certificate Key + help: A PEM-encoded private key matching the client certificate from Client Certificate. + client_certificate_key_hmac: + label: Client Certificate Key HMAC credential-library: title: Credential Library title_plural: Credential Libraries diff --git a/ui/admin/app/components/form/credential-store/index.hbs b/ui/admin/app/components/form/credential-store/index.hbs index b70183ed3..c77bfb410 100644 --- a/ui/admin/app/components/form/credential-store/index.hbs +++ b/ui/admin/app/components/form/credential-store/index.hbs @@ -52,6 +52,188 @@ {{/if}} +
{{t 'resources.credential-library.description'}}
{{t 'resources.credential-store.description'}}
diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index fca0dab92..9f13c5e50 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -55,7 +55,8 @@ module.exports = function (environment) { 'host-set': '/host-sets', 'host-set.new': '/host-sets/new', 'host-set.add-hosts': '/host-sets/add-hosts', - 'credential-stores': '/credential-stores', + 'credential-store': '/credential-stores', + 'credential-source': '/credential-sources', host: '/hosts', 'host.new': '/hosts/new', role: '/roles',