From 9af009a5d224a3d39e862bc0bffc5e810d6837f3 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Wed, 24 Oct 2018 14:33:12 -0500 Subject: [PATCH] Add updateTransitionalVersion method to certificate operations. Fixes #42 --- .../CredHubCertificateOperations.java | 25 +++++-- .../CredHubCertificateTemplate.java | 59 ++++++++++++--- .../credential/CredHubCredentialTemplate.java | 20 +++--- .../CredHubInterpolationTemplate.java | 5 +- .../permission/CredHubPermissionTemplate.java | 5 +- .../credhub/support/CredentialDetails.java | 5 +- .../CertificateCredentialDetails.java | 71 +++++++++++++++++++ .../CredHubCertificateTemplateUnitTests.java | 47 ++++++++++-- .../CertificateIntegrationTests.java | 49 ++++++++++++- 9 files changed, 244 insertions(+), 42 deletions(-) create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/certificate/CertificateCredentialDetails.java diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateOperations.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateOperations.java index 591b466..5b0ae57 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateOperations.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateOperations.java @@ -17,9 +17,8 @@ package org.springframework.credhub.core.certificate; import org.springframework.credhub.support.CertificateSummary; -import org.springframework.credhub.support.CredentialDetails; import org.springframework.credhub.support.CredentialName; -import org.springframework.credhub.support.certificate.CertificateCredential; +import org.springframework.credhub.support.certificate.CertificateCredentialDetails; import java.util.List; @@ -48,9 +47,25 @@ public interface CredHubCertificateOperations { /** * Regenerate a certificate. * - * @param id the CredHub-generated ID of the certificate credential; must not be {@literal null} - * @param setAsTransitional make the certificate version transitional or not + * @param id the CredHub-generated ID of the certificate credential; must not be {@literal null} + * and must be an ID returned by {@link #getAll()} + * or {@link #getByName(CredentialName)} + * @param setAsTransitional {@code true} to mark the certificate version transitional; + * {@code false} otherwise * @return the details of the certificate credential */ - CredentialDetails regenerate(final String id, final boolean setAsTransitional); + CertificateCredentialDetails regenerate(final String id, final boolean setAsTransitional); + + /** + * Make the specified version of a certificate the {@literal transitional} version. + * + * @param id the CredHub-generated ID of the certificate credential; must not be {@literal null} + * and must be an ID returned by {@link #getAll()} + * or {@link #getByName(CredentialName)} + * @param versionId the CredHub-generated ID of the version of the certificate credential that should be + * marked {@literal transitional}, or {@literal null} to indicate that no version + * is {@literal transitional} + * @return the details of the certificate credential, including all versions + */ + List updateTransitionalVersion(final String id, final String versionId); } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplate.java index 6369459..65c10aa 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplate.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplate.java @@ -22,10 +22,10 @@ import org.springframework.credhub.core.ExceptionUtils; import org.springframework.credhub.core.RestOperationsCallback; import org.springframework.credhub.support.CertificateSummary; import org.springframework.credhub.support.CertificateSummaryData; -import org.springframework.credhub.support.CredentialDetails; import org.springframework.credhub.support.CredentialName; -import org.springframework.credhub.support.certificate.CertificateCredential; +import org.springframework.credhub.support.certificate.CertificateCredentialDetails; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.web.client.RestOperations; @@ -34,8 +34,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.springframework.http.HttpMethod.POST; - /** * Implements the interactions with CredHub to retrieve, regenerate, and update * * certificates. @@ -46,7 +44,10 @@ public class CredHubCertificateTemplate implements CredHubCertificateOperations static final String BASE_URL_PATH = "/api/v1/certificates"; static final String NAME_URL_QUERY = BASE_URL_PATH + "?name={name}"; static final String REGENERATE_URL_PATH = BASE_URL_PATH + "/{id}/regenerate"; + static final String UPDATE_TRANSITIONAL_URL_PATH = BASE_URL_PATH + "/{id}/update_transitional_version"; + static final String TRANSITIONAL_REQUEST_FIELD = "set_as_transitional"; + static final String VERSION_REQUEST_FIELD = "version"; private CredHubOperations credHubOperations; @@ -108,23 +109,59 @@ public class CredHubCertificateTemplate implements CredHubCertificateOperations * Regenerate a certificate. * * @param id the CredHub-generated ID of the certificate credential; must not be {@literal null} + * @param setAsTransitional {@code true} to mark the certificate version transitional; + * {@code false} otherwise * @return the details of the certificate credential */ @Override - public CredentialDetails regenerate(final String id, final boolean setAsTransitional) { + public CertificateCredentialDetails regenerate(final String id, final boolean setAsTransitional) { Assert.notNull(id, "credential ID must not be null"); - final ParameterizedTypeReference> ref = - new ParameterizedTypeReference>() {}; + final ParameterizedTypeReference ref = + new ParameterizedTypeReference() {}; - return credHubOperations.doWithRest(new RestOperationsCallback>() { + return credHubOperations.doWithRest(new RestOperationsCallback() { @Override - public CredentialDetails doWithRestOperations(RestOperations restOperations) { + public CertificateCredentialDetails doWithRestOperations(RestOperations restOperations) { Map request = new HashMap<>(); request.put(TRANSITIONAL_REQUEST_FIELD, setAsTransitional); - ResponseEntity> response = - restOperations.exchange(REGENERATE_URL_PATH, POST, + ResponseEntity response = + restOperations.exchange(REGENERATE_URL_PATH, HttpMethod.POST, + new HttpEntity(request), ref, id); + + ExceptionUtils.throwExceptionOnError(response); + + return response.getBody(); + } + }); + } + + /** + * Make the specified version of a certificate the {@literal transitional} version. + * + * @param id the CredHub-generated ID of the certificate credential; must not be {@literal null} + * and must be an ID returned by {@link #getAll()} + * or {@link #getByName(CredentialName)} + * @param versionId the CredHub-generated ID of the version of the certificate credential that should be + * marked {@literal transitional} + * @return the details of the certificate credential, including all versions + */ + public List updateTransitionalVersion(final String id, + final String versionId) { + Assert.notNull(id, "credential ID must not be null"); + + final ParameterizedTypeReference> ref = + new ParameterizedTypeReference>() {}; + + return credHubOperations.doWithRest(new RestOperationsCallback>() { + @Override + public List doWithRestOperations(RestOperations restOperations) { + Map request = new HashMap<>(); + request.put(VERSION_REQUEST_FIELD, versionId); + + ResponseEntity> response = + restOperations.exchange(UPDATE_TRANSITIONAL_URL_PATH, HttpMethod.PUT, new HttpEntity(request), ref, id); ExceptionUtils.throwExceptionOnError(response); diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/credential/CredHubCredentialTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/credential/CredHubCredentialTemplate.java index d5bcaab..72ea7fa 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/credential/CredHubCredentialTemplate.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/credential/CredHubCredentialTemplate.java @@ -30,6 +30,7 @@ import org.springframework.credhub.support.CredentialSummary; import org.springframework.credhub.support.CredentialSummaryData; import org.springframework.credhub.support.ParametersRequest; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.web.client.RestOperations; @@ -38,10 +39,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.springframework.http.HttpMethod.GET; -import static org.springframework.http.HttpMethod.POST; -import static org.springframework.http.HttpMethod.PUT; - /** * Implements the interactions with CredHub to save, retrieve, * and delete credentials. @@ -81,7 +78,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public CredentialDetails doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(BASE_URL_PATH, PUT, + restOperations.exchange(BASE_URL_PATH, HttpMethod.PUT, new HttpEntity<>(credentialRequest), ref); ExceptionUtils.throwExceptionOnError(response); @@ -102,7 +99,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public CredentialDetails doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(BASE_URL_PATH, POST, + restOperations.exchange(BASE_URL_PATH, HttpMethod.POST, new HttpEntity<>(parametersRequest), ref); ExceptionUtils.throwExceptionOnError(response); @@ -127,7 +124,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { request.put("name", name.getName()); ResponseEntity> response = - restOperations.exchange(REGENERATE_URL_PATH, POST, + restOperations.exchange(REGENERATE_URL_PATH, HttpMethod.POST, new HttpEntity<>(request), ref); ExceptionUtils.throwExceptionOnError(response); @@ -149,7 +146,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public CredentialDetails doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(ID_URL_PATH, GET, null, ref, id); + restOperations.exchange(ID_URL_PATH, HttpMethod.GET, null, ref, id); ExceptionUtils.throwExceptionOnError(response); @@ -170,7 +167,8 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public CredentialDetails doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(NAME_URL_QUERY_CURRENT, GET, null, ref, name.getName()); + restOperations.exchange(NAME_URL_QUERY_CURRENT, HttpMethod.GET, + null, ref, name.getName()); ExceptionUtils.throwExceptionOnError(response); @@ -191,7 +189,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public List> doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(NAME_URL_QUERY, GET, null, ref, name.getName()); + restOperations.exchange(NAME_URL_QUERY, HttpMethod.GET, null, ref, name.getName()); ExceptionUtils.throwExceptionOnError(response); @@ -213,7 +211,7 @@ public class CredHubCredentialTemplate implements CredHubCredentialOperations { @Override public List> doWithRestOperations(RestOperations restOperations) { ResponseEntity> response = - restOperations.exchange(NAME_URL_QUERY_VERSIONS, GET, null, ref, + restOperations.exchange(NAME_URL_QUERY_VERSIONS, HttpMethod.GET, null, ref, name.getName(), versions); ExceptionUtils.throwExceptionOnError(response); diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/interpolation/CredHubInterpolationTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/interpolation/CredHubInterpolationTemplate.java index 5db5464..374aee1 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/interpolation/CredHubInterpolationTemplate.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/interpolation/CredHubInterpolationTemplate.java @@ -21,12 +21,11 @@ import org.springframework.credhub.core.ExceptionUtils; import org.springframework.credhub.core.RestOperationsCallback; import org.springframework.credhub.support.ServicesData; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.web.client.RestOperations; -import static org.springframework.http.HttpMethod.POST; - /** * Implements the main interaction with CredHub to interpolate service binding credentials. * @@ -54,7 +53,7 @@ public class CredHubInterpolationTemplate implements CredHubInterpolationOperati @Override public ServicesData doWithRestOperations(RestOperations restOperations) { ResponseEntity response = restOperations - .exchange(INTERPOLATE_URL_PATH, POST, + .exchange(INTERPOLATE_URL_PATH, HttpMethod.POST, new HttpEntity<>(serviceData), ServicesData.class); ExceptionUtils.throwExceptionOnError(response); diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/permission/CredHubPermissionTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/permission/CredHubPermissionTemplate.java index 312f5b0..435b9a9 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/permission/CredHubPermissionTemplate.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/permission/CredHubPermissionTemplate.java @@ -23,14 +23,13 @@ import org.springframework.credhub.support.CredentialPermissions; import org.springframework.credhub.support.permissions.Actor; import org.springframework.credhub.support.permissions.CredentialPermission; import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.web.client.RestOperations; import java.util.List; -import static org.springframework.http.HttpMethod.POST; - /** * Implements the main interaction with CredHub to add, retrieve, * and delete permissions. @@ -78,7 +77,7 @@ public class CredHubPermissionTemplate implements CredHubPermissionOperations { credHubOperations.doWithRest(new RestOperationsCallback() { @Override public Void doWithRestOperations(RestOperations restOperations) { - restOperations.exchange(PERMISSIONS_URL_PATH, POST, + restOperations.exchange(PERMISSIONS_URL_PATH, HttpMethod.POST, new HttpEntity<>(credentialPermissions), CredentialPermissions.class); return null; diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java index d2c3a94..77c413d 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java @@ -22,8 +22,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import java.util.Objects; /** - * The details of a credential that has been written to CredHub. Clients don't - * typically instantiate objects of this type, but will receive them in response + * The details of a credential that has been written to CredHub. + * + * Clients don't typically instantiate objects of this type, but will receive them in response * to write and retrieve requests. The {@literal id} and {@literal name} fields * can be used in subsequent requests. * diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/certificate/CertificateCredentialDetails.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/certificate/CertificateCredentialDetails.java new file mode 100644 index 0000000..01a84a0 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/certificate/CertificateCredentialDetails.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.credhub.support.certificate; + +import org.springframework.credhub.support.CredentialDetails; +import org.springframework.credhub.support.CredentialName; +import org.springframework.credhub.support.CredentialType; + +/** + * The details of a certificate credential that has been written to CredHub. This is a specialization + * of {@link CredentialDetails} that adds certificate-specific fields. + * + * Clients don't typically instantiate objects of this type, but will receive them in response + * to credential operation requests. The {@literal id} and {@literal name} fields + * can be used in subsequent requests. + * + * @author Scott Frederick + */ +public class CertificateCredentialDetails extends CredentialDetails { + private final boolean transitional; + + /** + * Create a {@link CertificateCredentialDetails}. + */ + @SuppressWarnings("unused") + private CertificateCredentialDetails() { + super(); + this.transitional = false; + } + + /** + * Create a {@link CertificateCredentialDetails} from the provided parameters. Intended for + * internal use. Clients will get {@link CertificateCredentialDetails} objects populated from + * CredHub responses. + * + * @param id the CredHub-generated unique ID of the credential + * @param name the client-provided name of the credential + * @param credentialType the {@link CredentialType} of the credential + * @param transitional a flag indicating whether the certificate will be used for signing + * @param value the client-provided value for the credential + */ + public CertificateCredentialDetails(String id, CredentialName name, CredentialType credentialType, + boolean transitional, CertificateCredential value) { + super(id, name, credentialType, value); + this.transitional = transitional; + } + + /** + * Get the value of the flag indicating whether the certificate is currently being used for signing + * or if it is being staged. + * + * @return the transitional flag + */ + public boolean isTransitional() { + return transitional; + } +} diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplateUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplateUnitTests.java index 010862b..67577f6 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplateUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/certificate/CredHubCertificateTemplateUnitTests.java @@ -25,15 +25,16 @@ import org.springframework.core.ParameterizedTypeReference; import org.springframework.credhub.core.CredHubTemplate; import org.springframework.credhub.support.CertificateSummary; import org.springframework.credhub.support.CertificateSummaryData; -import org.springframework.credhub.support.CredentialDetails; import org.springframework.credhub.support.CredentialType; import org.springframework.credhub.support.SimpleCredentialName; import org.springframework.credhub.support.certificate.CertificateCredential; +import org.springframework.credhub.support.certificate.CertificateCredentialDetails; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -46,6 +47,8 @@ import static org.springframework.credhub.core.certificate.CredHubCertificateTem import static org.springframework.credhub.core.certificate.CredHubCertificateTemplate.NAME_URL_QUERY; import static org.springframework.credhub.core.certificate.CredHubCertificateTemplate.REGENERATE_URL_PATH; import static org.springframework.credhub.core.certificate.CredHubCertificateTemplate.TRANSITIONAL_REQUEST_FIELD; +import static org.springframework.credhub.core.certificate.CredHubCertificateTemplate.UPDATE_TRANSITIONAL_URL_PATH; +import static org.springframework.credhub.core.certificate.CredHubCertificateTemplate.VERSION_REQUEST_FIELD; import static org.springframework.http.HttpStatus.OK; @RunWith(MockitoJUnitRunner.class) @@ -97,25 +100,57 @@ public class CredHubCertificateTemplateUnitTests { } @Test + @SuppressWarnings("unchecked") public void regenerate() { - CredentialDetails expectedCertificates = - new CredentialDetails<>("id", NAME, CredentialType.CERTIFICATE, + CertificateCredentialDetails expectedCertificate = + new CertificateCredentialDetails("id", NAME, CredentialType.CERTIFICATE, true, new CertificateCredential("cert", "authority", "key")); Map request = new HashMap<>(); request.put(TRANSITIONAL_REQUEST_FIELD, true); when(restTemplate.exchange(eq(REGENERATE_URL_PATH), eq(HttpMethod.POST), - eq(new HttpEntity(request)), isA(ParameterizedTypeReference.class), eq("id"))) - .thenReturn(new ResponseEntity<>(expectedCertificates, OK)); + eq(new HttpEntity<>(request)), isA(ParameterizedTypeReference.class), eq("id"))) + .thenReturn(new ResponseEntity<>(expectedCertificate, OK)); - CredentialDetails response = credHubTemplate.regenerate("id", true); + CertificateCredentialDetails response = credHubTemplate.regenerate("id", true); assertThat(response).isNotNull(); assertThat(response.getId()).isEqualTo("id"); assertThat(response.getCredentialType()).isEqualTo(CredentialType.CERTIFICATE); + assertThat(response.isTransitional()).isTrue(); assertThat(response.getValue().getCertificate()).isEqualTo("cert"); assertThat(response.getValue().getCertificateAuthority()).isEqualTo("authority"); assertThat(response.getValue().getPrivateKey()).isEqualTo("key"); } + + @Test + @SuppressWarnings("unchecked") + public void updateTransitionalVersion() { + List expectedCertificates = Arrays.asList( + new CertificateCredentialDetails("id1", NAME, CredentialType.CERTIFICATE, false, + new CertificateCredential("cert1", "authority1", "key1")), + new CertificateCredentialDetails("id2", NAME, CredentialType.CERTIFICATE, true, + new CertificateCredential("cert2", "authority2", "key2")) + ); + + Map request = new HashMap<>(); + request.put(VERSION_REQUEST_FIELD, "id2"); + + when(restTemplate.exchange(eq(UPDATE_TRANSITIONAL_URL_PATH), eq(HttpMethod.PUT), + eq(new HttpEntity<>(request)), isA(ParameterizedTypeReference.class), eq("id1"))) + .thenReturn(new ResponseEntity<>(expectedCertificates, OK)); + + List response = + credHubTemplate.updateTransitionalVersion("id1", "id2"); + + assertThat(response).hasSize(2); + assertThat(response).extracting("id").contains("id1", "id2"); + assertThat(response).extracting("credentialType").contains(CredentialType.CERTIFICATE, + CredentialType.CERTIFICATE); + assertThat(response).extracting("transitional").contains(false, true); + assertThat(response).extracting("value.certificate").contains("cert1", "cert2"); + assertThat(response).extracting("value.certificateAuthority").contains("authority1", "authority2"); + assertThat(response).extracting("value.privateKey").contains("key1", "key2"); + } } \ No newline at end of file diff --git a/spring-credhub-integration-tests/src/test/java/org/springframework/credhub/integration/CertificateIntegrationTests.java b/spring-credhub-integration-tests/src/test/java/org/springframework/credhub/integration/CertificateIntegrationTests.java index eb26901..26e686f 100644 --- a/spring-credhub-integration-tests/src/test/java/org/springframework/credhub/integration/CertificateIntegrationTests.java +++ b/spring-credhub-integration-tests/src/test/java/org/springframework/credhub/integration/CertificateIntegrationTests.java @@ -28,6 +28,7 @@ import org.springframework.credhub.support.CredentialSummary; import org.springframework.credhub.support.CredentialType; import org.springframework.credhub.support.SimpleCredentialName; import org.springframework.credhub.support.certificate.CertificateCredential; +import org.springframework.credhub.support.certificate.CertificateCredentialDetails; import org.springframework.credhub.support.certificate.CertificateParameters; import org.springframework.credhub.support.certificate.CertificateParametersRequest; @@ -101,10 +102,56 @@ public class CertificateIntegrationTests extends CredHubIntegrationTests { CertificateSummary byName = certificates.getByName(CREDENTIAL_NAME); - CredentialDetails regenerated = certificates.regenerate(byName.getId(), true); + CertificateCredentialDetails regenerated = certificates.regenerate(byName.getId(), true); assertThat(regenerated.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName()); + assertThat(regenerated.isTransitional()).isTrue(); assertThat(regenerated.getValue().getCertificate()).isNotEqualTo(certificate.getValue().getCertificate()); assertThat(regenerated.getValue().getCertificateAuthority()).isNotEqualTo(certificate.getValue().getCertificateAuthority()); assertThat(regenerated.getValue().getPrivateKey()).isNotEqualTo(certificate.getValue().getPrivateKey()); } + + @Test + public void rotateCertificate() { + CredentialDetails certificate = credentials.generate(CertificateParametersRequest.builder() + .name(CREDENTIAL_NAME) + .parameters(CertificateParameters.builder() + .commonName("example.com") + .selfSign(true) + .build()) + .build()); + assertThat(certificate.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName()); + + String credentialVersion0Id = certificate.getId(); + + List> allVersions = + credentials.getByNameWithHistory(CREDENTIAL_NAME, CertificateCredential.class); + assertThat(allVersions).hasSize(1); + assertThat(allVersions.get(0).getId()).isEqualTo(credentialVersion0Id); + + CertificateSummary byName = certificates.getByName(CREDENTIAL_NAME); + String certificateId = byName.getId(); + + CertificateCredentialDetails regenerated = certificates.regenerate(certificateId, true); + assertThat(regenerated.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName()); + assertThat(regenerated.getValue().getCertificate()).isNotEqualTo(certificate.getValue().getCertificate()); + assertThat(regenerated.getValue().getCertificateAuthority()).isNotEqualTo(certificate.getValue().getCertificateAuthority()); + assertThat(regenerated.getValue().getPrivateKey()).isNotEqualTo(certificate.getValue().getPrivateKey()); + + String credentialVersion1Id = regenerated.getId(); + + allVersions = credentials.getByNameWithHistory(CREDENTIAL_NAME, CertificateCredential.class); + assertThat(allVersions).hasSize(2); + assertThat(allVersions).extracting("id").contains(credentialVersion1Id, credentialVersion0Id); + + List updatedCertificate = + certificates.updateTransitionalVersion(certificateId, credentialVersion0Id); + assertThat(updatedCertificate).hasSize(2); + assertThat(updatedCertificate).extracting("id").contains(credentialVersion1Id, credentialVersion0Id); + assertThat(updatedCertificate).extracting("transitional").contains(false, true); + + updatedCertificate = certificates.updateTransitionalVersion(certificateId, null); + assertThat(updatedCertificate).hasSize(1); + assertThat(updatedCertificate).extracting("id").contains(credentialVersion1Id); + assertThat(updatedCertificate).extracting("transitional").contains(false); + } }