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 b9eb433c3..9d001037f 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -308,13 +308,17 @@ credential-store: 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. + 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 cd50e3aae..c77bfb410 100644 --- a/ui/admin/app/components/form/credential-store/index.hbs +++ b/ui/admin/app/components/form/credential-store/index.hbs @@ -92,6 +92,15 @@ {{/if}} + {{#unless @model.isNew}} + + {{/unless}} + + @error={{@model.errors.attributes_tls_skip_verify}} + as |field| + > + {{#if @model.errors.attributes_tls_skip_verify}} + + {{#each @model.errors.attributes_tls_skip_verify as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + {{#unless @model.isNew}} + + {{/unless}} +