Add support for generation of certificate credentials.

This commit is contained in:
Scott Frederick
2017-05-26 18:00:47 -05:00
parent 961c506352
commit e971bd3de6
7 changed files with 506 additions and 30 deletions

View File

@@ -0,0 +1,229 @@
/*
* 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.KeyLength;
import org.springframework.credhub.support.rsa.KeyParameters;
import org.springframework.util.Assert;
/**
* Parameters for generating a new certificate credential.
*
* @author Scott Frederick
*/
public class CertificateParameters extends KeyParameters {
private String commonName;
private String[] alternativeNames;
private String organization;
private String organizationUnit;
private String locality;
private String state;
private String country;
private String credential;
private Boolean isCertificateAuthority;
private Boolean selfSign;
private Integer duration;
/**
* Create a {@link CertificateParameters} using defaults for all parameter values.
*/
private CertificateParameters() {
this.commonName = null;
this.alternativeNames = null;
this.organization = null;
this.organizationUnit = null;
this.locality = null;
this.state = null;
this.country = null;
this.duration = null;
this.credential = null;
this.isCertificateAuthority = null;
this.selfSign = null;
}
private CertificateParameters(KeyLength keyLength, String commonName, String[] alternativeNames, String organization,
String organizationUnit, String locality, String state, String country,
Integer duration, String credential, Boolean isCa, Boolean selfSign) {
super(keyLength);
this.commonName = commonName;
this.alternativeNames = alternativeNames;
this.organization = organization;
this.organizationUnit = organizationUnit;
this.locality = locality;
this.state = state;
this.country = country;
this.duration = duration;
this.credential = credential;
this.isCertificateAuthority = isCa;
this.selfSign = selfSign;
}
public String getCommonName() {
return commonName;
}
public String[] getAlternativeNames() {
return alternativeNames;
}
public String getOrganization() {
return organization;
}
public String getOrganizationUnit() {
return organizationUnit;
}
public String getLocality() {
return locality;
}
public String getState() {
return state;
}
public String getCountry() {
return country;
}
public String getCredential() {
return credential;
}
public Boolean getIsCa() {
return isCertificateAuthority;
}
public Boolean getSelfSign() {
return selfSign;
}
public Integer getDuration() {
return duration;
}
/**
* Create a builder that provides a fluent API for providing the values required
* to construct a {@link CertificateParameters}.
*
* @return a builder
*/
public static CertificateParametersBuilder builder() {
return new CertificateParametersBuilder();
}
/**
* A builder that provides a fluent API for constructing {@link CertificateParametersBuilder}s.
*/
public static class CertificateParametersBuilder {
private KeyLength keyLength;
private String commonName;
private String[] alternativeNames;
private String organization;
private String organizationUnit;
private String locality;
private String state;
private String country;
private Integer duration;
private String credential;
private Boolean certificateAuthority;
private Boolean selfSign;
public CertificateParametersBuilder keyLength(KeyLength keyLength) {
Assert.notNull(keyLength, "keyLength must not be null");
this.keyLength = keyLength;
return this;
}
public CertificateParametersBuilder commonName(String commonName) {
Assert.notNull(commonName, "commonName must not be null");
this.commonName = commonName;
return this;
}
public CertificateParametersBuilder alternateNames(String... alternativeNames) {
Assert.notNull(alternativeNames, "alternativeNames must not be null");
this.alternativeNames = alternativeNames;
return this;
}
public CertificateParametersBuilder organization(String organization) {
Assert.notNull(organization, "organization must not be null");
this.organization = organization;
return this;
}
public CertificateParametersBuilder organizationUnit(String organizationUnit) {
Assert.notNull(organizationUnit, "organizationUnit must not be null");
this.organizationUnit = organizationUnit;
return this;
}
public CertificateParametersBuilder locality(String locality) {
Assert.notNull(locality, "locality must not be null");
this.locality = locality;
return this;
}
public CertificateParametersBuilder state(String state) {
Assert.notNull(state, "state must not be null");
this.state = state;
return this;
}
public CertificateParametersBuilder country(String country) {
Assert.notNull(country, "country must not be null");
this.country = country;
return this;
}
public CertificateParametersBuilder duration(int duration) {
this.duration = duration;
return this;
}
public CertificateParametersBuilder credential(String credential) {
this.credential = credential;
return this;
}
public CertificateParametersBuilder certificateAuthority(boolean certificateAuthority) {
this.certificateAuthority = certificateAuthority;
return this;
}
public CertificateParametersBuilder selfSign(boolean selfSign) {
this.selfSign = selfSign;
return this;
}
/**
* Create a {@link CertificateParameters} from the provided values.
*
* @return the created {@link CertificateParameters}
*/
public CertificateParameters build() {
Assert.isTrue(commonName != null || organization != null || organizationUnit != null ||
locality != null || state != null || country != null,
"at least one subject parameter must be specified");
Assert.isTrue(credential != null || certificateAuthority != null || selfSign != null,
"at least one signing parameter must be specified");
return new CertificateParameters(keyLength, commonName, alternativeNames, organization, organizationUnit,
locality, state, country, duration, credential, certificateAuthority, selfSign);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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.ParametersRequest;
import org.springframework.util.Assert;
import static org.springframework.credhub.support.CredentialType.CERTIFICATE;
/**
* The details of a request to generate a new {@link CertificateCredential} in CredHub.
*
* @author Scott Frederick
*/
public class CertificateParametersRequest extends ParametersRequest<CertificateParameters> {
/**
* Create a {@link CertificateParametersRequest}.
*/
CertificateParametersRequest() {
super(CERTIFICATE);
}
/**
* Create a builder that provides a fluent API for providing the values required
* to construct a {@link CertificateParametersRequest}.
*
* @return a builder
*/
public static CertificateParametersRequestBuilder builder() {
return new CertificateParametersRequestBuilder();
}
/**
* A builder that provides a fluent API for constructing {@link CertificateParametersRequest}s.
*/
public static class CertificateParametersRequestBuilder
extends ParametersRequestBuilder<CertificateParameters, CertificateParametersRequest, CertificateParametersRequestBuilder> {
@Override
protected CertificateParametersRequest createTarget() {
return new CertificateParametersRequest();
}
@Override
protected CertificateParametersRequestBuilder createBuilder() {
return this;
}
/**
* Set the parameters for generation of a password credential.
*
* @param parameters the generation parameters; must not be {@literal null}
* @return the builder
*/
public CertificateParametersRequestBuilder parameters(CertificateParameters parameters) {
Assert.notNull(parameters, "parameters must not be null");
targetObj.setParameters(parameters);
return this;
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.rsa;
import org.springframework.credhub.support.KeyLength;
public class KeyParameters {
protected final KeyLength keyLength;
protected KeyParameters() {
this.keyLength = null;
}
protected KeyParameters(KeyLength keyLength) {
this.keyLength = keyLength;
}
/**
* Get the value of the key length parameter.
*
* @return the value of the parameter; will be {@literal null} if not explicitly set
*/
public Integer getKeyLength() {
return keyLength == null ? null : keyLength.getLength();
}
}

View File

@@ -25,14 +25,12 @@ import org.springframework.util.Assert;
*
* @author Scott Frederick
*/
public class RsaParameters {
private final KeyLength keyLength;
public class RsaParameters extends KeyParameters {
/**
* Create a {@link RsaParameters} using defaults for all parameter values.
*/
private RsaParameters() {
keyLength = null;
super();
}
/**
@@ -41,16 +39,7 @@ public class RsaParameters {
* @param keyLength length of generated RSA key; must not be {@literal null}
*/
public RsaParameters(KeyLength keyLength) {
super(keyLength);
Assert.notNull(keyLength, "keyLength must not be null");
this.keyLength = keyLength;
}
/**
* Get the value of the key length parameter.
*
* @return the value of the parameter; will be {@literal null} if not explicitly set
*/
public Integer getKeyLength() {
return keyLength == null ? null : keyLength.getLength();
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.credhub.support.ssh;
import org.springframework.credhub.support.KeyLength;
import org.springframework.credhub.support.rsa.KeyParameters;
import org.springframework.util.Assert;
/**
@@ -25,15 +26,14 @@ import org.springframework.util.Assert;
*
* @author Scott Frederick
*/
public class SshParameters {
private final KeyLength keyLength;
public class SshParameters extends KeyParameters {
private final String sshComment;
/**
* Create a {@link SshParameters} using defaults for all parameter values.
*/
private SshParameters() {
keyLength = null;
super();
sshComment = null;
}
@@ -43,8 +43,8 @@ public class SshParameters {
* @param sshComment comment for the generated SSH key; must not be {@literal null}
*/
public SshParameters(String sshComment) {
super();
Assert.notNull(sshComment, "sshComment must not be null");
this.keyLength = null;
this.sshComment = sshComment;
}
@@ -54,8 +54,8 @@ public class SshParameters {
* @param keyLength length of generated SSH key; must not be {@literal null}
*/
public SshParameters(KeyLength keyLength) {
super(keyLength);
Assert.notNull(keyLength, "keyLength must not be null");
this.keyLength = keyLength;
this.sshComment = null;
}
@@ -66,21 +66,12 @@ public class SshParameters {
* @param sshComment comment for the generated SSH key; must not be {@literal null}
*/
public SshParameters(KeyLength keyLength, String sshComment) {
super(keyLength);
Assert.notNull(keyLength, "keyLength must not be null");
Assert.notNull(sshComment, "sshComment must not be null");
this.keyLength = keyLength;
this.sshComment = sshComment;
}
/**
* Get the value of the key length parameter.
*
* @return the value of the parameter; will be {@literal null} if not explicitly set
*/
public Integer getKeyLength() {
return keyLength == null ? null : keyLength.getLength();
}
/**
* Get the value of the ssh comment parameter.
*

View File

@@ -28,15 +28,22 @@ import org.springframework.credhub.support.CredentialDetails;
import org.springframework.credhub.support.CredentialDetailsData;
import org.springframework.credhub.support.CredentialRequest;
import org.springframework.credhub.support.CredentialType;
import org.springframework.credhub.support.ParametersRequest;
import org.springframework.credhub.support.certificate.CertificateCredential;
import org.springframework.credhub.support.certificate.CertificateCredentialRequest;
import org.springframework.credhub.support.certificate.CertificateParameters;
import org.springframework.credhub.support.certificate.CertificateParametersRequest;
import org.springframework.http.ResponseEntity;
@RunWith(Theories.class)
public class CredHubTemplateDetailCertificateUnitTests
extends CredHubTemplateDetailUnitTestsBase<CertificateCredential, Void> {
extends CredHubTemplateDetailUnitTestsBase<CertificateCredential, CertificateParameters> {
private static final CertificateCredential CREDENTIAL =
new CertificateCredential("certificate", "authority", "private-key");
private static final CertificateParameters PARAMETERS = CertificateParameters.builder()
.commonName("common")
.credential("credential")
.build();
@DataPoints("detail-responses")
public static List<ResponseEntity<CredentialDetails<CertificateCredential>>> buildDetailResponses() {
@@ -56,6 +63,14 @@ public class CredHubTemplateDetailCertificateUnitTests
.build();
}
@Override
public ParametersRequest<CertificateParameters> getGenerateRequest() {
return CertificateParametersRequest.builder()
.name(NAME)
.parameters(PARAMETERS)
.build();
}
@Override
public Class<CertificateCredential> getType() {
return CertificateCredential.class;
@@ -67,6 +82,12 @@ public class CredHubTemplateDetailCertificateUnitTests
verifyWrite(expectedResponse);
}
@Theory
public void generate(@FromDataPoints("detail-responses")
ResponseEntity<CredentialDetails<CertificateCredential>> expectedResponse) {
verifyGenerate(expectedResponse);
}
@Theory
public void getById(@FromDataPoints("detail-responses")
ResponseEntity<CredentialDetails<CertificateCredential>> expectedResponse) {

View File

@@ -0,0 +1,132 @@
/*
* 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.junit.Test;
import org.springframework.credhub.support.KeyLength;
import org.springframework.credhub.support.ParametersRequestUnitTestsBase;
import org.springframework.credhub.support.SimpleCredentialName;
import org.springframework.credhub.support.certificate.CertificateParametersRequest.CertificateParametersRequestBuilder;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.valid4j.matchers.jsonpath.JsonPathMatchers.hasJsonPath;
import static org.valid4j.matchers.jsonpath.JsonPathMatchers.hasNoJsonPath;
public class CertificateParametersRequestUnitTests extends ParametersRequestUnitTestsBase {
@Test
public void serializeWithParameters() throws Exception {
CertificateParametersRequestBuilder requestBuilder = CertificateParametersRequest.builder()
.name(new SimpleCredentialName("example", "credential"))
.overwrite(true)
.parameters(CertificateParameters.builder()
.keyLength(KeyLength.LENGTH_2048)
.commonName("common")
.alternateNames("alt1", "alt2")
.organization("org")
.organizationUnit("dev")
.locality("city")
.state("state")
.country("country")
.duration(1234)
.credential("credential")
.certificateAuthority(true)
.selfSign(false)
.build());
String jsonValue = serializeToJson(requestBuilder);
assertCommonRequestFields(jsonValue, true, "/example/credential", "certificate");
assertThat(jsonValue,
allOf(hasJsonPath("$.parameters.key_length", equalTo(2048)),
hasJsonPath("$.parameters.common_name", equalTo("common")),
hasJsonPath("$.parameters.alternative_names[0]", equalTo("alt1")),
hasJsonPath("$.parameters.alternative_names[1]", equalTo("alt2")),
hasJsonPath("$.parameters.organization", equalTo("org")),
hasJsonPath("$.parameters.organization_unit", equalTo("dev")),
hasJsonPath("$.parameters.locality", equalTo("city")),
hasJsonPath("$.parameters.state", equalTo("state")),
hasJsonPath("$.parameters.country", equalTo("country")),
hasJsonPath("$.parameters.duration", equalTo(1234)),
hasJsonPath("$.parameters.credential", equalTo("credential")),
hasJsonPath("$.parameters.is_ca", equalTo(true)),
hasJsonPath("$.parameters.self_sign", equalTo(false))));
}
@Test
public void serializeWithMinimalParameters() throws Exception {
CertificateParametersRequestBuilder requestBuilder = CertificateParametersRequest.builder()
.name(new SimpleCredentialName("example", "credential"))
.overwrite(true)
.parameters(CertificateParameters.builder()
.commonName("common")
.credential("credential")
.build());
String jsonValue = serializeToJson(requestBuilder);
assertCommonRequestFields(jsonValue, true, "/example/credential", "certificate");
assertThat(jsonValue,
allOf(hasNoJsonPath("$.parameters.key_length"),
hasJsonPath("$.parameters.common_name", equalTo("common")),
hasJsonPath("$.parameters.credential", equalTo("credential")),
hasNoJsonPath("$.parameters.alternative_names"),
hasNoJsonPath("$.parameters.organization"),
hasNoJsonPath("$.parameters.organization_unit"),
hasNoJsonPath("$.parameters.locality"),
hasNoJsonPath("$.parameters.state"),
hasNoJsonPath("$.parameters.country"),
hasNoJsonPath("$.parameters.duration"),
hasNoJsonPath("$.parameters.is_ca"),
hasNoJsonPath("$.parameters.self_sign")));
}
@Test
public void serializeWithNoParameters() throws Exception {
CertificateParametersRequestBuilder requestBuilder = CertificateParametersRequest.builder()
.name(new SimpleCredentialName("example", "credential"))
.overwrite(true);
String jsonValue = serializeToJson(requestBuilder);
assertCommonRequestFields(jsonValue, true, "/example/credential", "certificate");
assertParametersNotSet(jsonValue);
}
@Test(expected = IllegalArgumentException.class)
public void serializeWithEmptyParameters() throws Exception {
CertificateParametersRequestBuilder requestBuilder = CertificateParametersRequest.builder()
.name(new SimpleCredentialName("example", "credential"))
.overwrite(true)
.parameters(CertificateParameters.builder()
.keyLength(KeyLength.LENGTH_2048)
.build());
String jsonValue = serializeToJson(requestBuilder);
}
private void assertParametersNotSet(String jsonValue) {
assertThat(jsonValue,
allOf(hasNoJsonPath("$.parameters.key_length"),
hasNoJsonPath("$.parameters.exclude_lower"),
hasNoJsonPath("$.parameters.exclude_upper"),
hasNoJsonPath("$.parameters.exclude_number"),
hasNoJsonPath("$.parameters.include_special")));
}
}