diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/JsonUtils.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/JsonUtils.java index 26907de..977bdd1 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/JsonUtils.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/JsonUtils.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.util.ISO8601DateFormat; import org.springframework.credhub.support.JsonCredential; import org.springframework.credhub.support.PasswordCredential; import org.springframework.credhub.support.RsaCredential; +import org.springframework.credhub.support.SshCredential; import org.springframework.credhub.support.UserCredential; import org.springframework.credhub.support.ValueCredential; import org.springframework.credhub.support.ValueType; @@ -66,6 +67,7 @@ public class JsonUtils { new NamedType(ValueCredential.class, ValueType.VALUE.type()), new NamedType(UserCredential.class, ValueType.USER.type()), new NamedType(RsaCredential.class, ValueType.RSA.type()), + new NamedType(SshCredential.class, ValueType.SSH.type()), new NamedType(JsonCredential.class, ValueType.JSON.type()) ); } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshCredential.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshCredential.java new file mode 100644 index 0000000..c4a5b7b --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshCredential.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** + * An SSH credential consists of a public and/or private key. At least one of these key values must be provided. + * + * @author Scott Frederick + */ +public class SshCredential extends KeyPairCredential { + /** + * Create an empty {@link SshCredential}. Intended to be used internally for deserialization of responses. + */ + private SshCredential() { + super(); + } + + /** + * Create an {@link SshCredential} from the provided public and private key. At least one of the key + * values must not be {@literal null}. + * + * @param publicKey the public key + * @param privateKey the private key + */ + public SshCredential(String publicKey, String privateKey) { + super(publicKey, privateKey); + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshWriteRequest.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshWriteRequest.java new file mode 100644 index 0000000..59a2554 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SshWriteRequest.java @@ -0,0 +1,67 @@ +/* + * 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; + +import org.springframework.util.Assert; + +import static org.springframework.credhub.support.ValueType.SSH; + +/** + * The details of a request to write a new or update an existing {@link SshCredential} in CredHub. + * + * @author Scott Frederick + */ +public class SshWriteRequest extends WriteRequest { + /** + * Create a builder that provides a fluent API for providing the values required + * to construct a {@link SshWriteRequest}. + * + * @return a builder + */ + public static SshWriteRequestBuilder builder() { + return new SshWriteRequestBuilder(); + } + + /** + * A builder that provides a fluent API for constructing {@link SshWriteRequest}s. + */ + public static class SshWriteRequestBuilder + extends WriteRequestBuilder { + @Override + protected SshWriteRequest createTarget() { + return new SshWriteRequest(); + } + + @Override + protected SshWriteRequestBuilder createBuilder() { + return this; + } + + /** + * Set the value of an SSH credential. + * + * @param value the credential value; must not be {@literal null} + * @return the builder + */ + public SshWriteRequestBuilder value(SshCredential value) { + Assert.notNull(value, "value must not be null"); + targetObj.setType(SSH); + targetObj.setValue(value); + return this; + } + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ValueType.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ValueType.java index cc9900c..156804b 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ValueType.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ValueType.java @@ -48,6 +48,12 @@ public enum ValueType { */ RSA("rsa"), + /** + * An SSH credential consists of a private key and/or public key. The values + * are provided by the client. + */ + SSH("ssh"), + /** * A JSON credential consists of one or more fields in a JSON document. The keys and * values in the JSON document are determined by the client. diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailRsaUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailRsaUnitTests.java index 2f19788..deaa1b0 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailRsaUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailRsaUnitTests.java @@ -35,7 +35,7 @@ import org.springframework.http.ResponseEntity; @RunWith(Theories.class) public class CredHubTemplateDetailRsaUnitTests extends CredHubTemplateDetailUnitTestsBase { - private static final RsaCredential CREDENTIAL = new RsaCredential("myname", "secret"); + private static final RsaCredential CREDENTIAL = new RsaCredential("public-key", "private-key"); @DataPoints("detail-responses") public static List>> buildDetailResponses() { diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailSshUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailSshUnitTests.java new file mode 100644 index 0000000..2ed92ea --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailSshUnitTests.java @@ -0,0 +1,86 @@ +/* + * 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.core; + +import java.util.List; + +import org.junit.experimental.theories.DataPoints; +import org.junit.experimental.theories.FromDataPoints; +import org.junit.experimental.theories.Theories; +import org.junit.experimental.theories.Theory; +import org.junit.runner.RunWith; + +import org.springframework.credhub.support.CredentialDetails; +import org.springframework.credhub.support.CredentialDetailsData; +import org.springframework.credhub.support.SshCredential; +import org.springframework.credhub.support.SshWriteRequest; +import org.springframework.credhub.support.ValueType; +import org.springframework.credhub.support.WriteRequest; +import org.springframework.http.ResponseEntity; + +@RunWith(Theories.class) +public class CredHubTemplateDetailSshUnitTests + extends CredHubTemplateDetailUnitTestsBase { + private static final SshCredential CREDENTIAL = new SshCredential("public-key", "private-key"); + + @DataPoints("detail-responses") + public static List>> buildDetailResponses() { + return buildDetailResponses(ValueType.RSA, CREDENTIAL); + } + + @DataPoints("data-responses") + public static List>> buildDataResponses() { + return buildDataResponses(ValueType.RSA, CREDENTIAL); + } + + @Override + public WriteRequest getRequest() { + return SshWriteRequest.builder() + .name(NAME) + .value(CREDENTIAL) + .build(); + } + + @Override + public Class getType() { + return SshCredential.class; + } + + @Theory + public void write(@FromDataPoints("detail-responses") + ResponseEntity> expectedResponse) { + verifyWrite(expectedResponse); + } + + @Theory + public void getById(@FromDataPoints("detail-responses") + ResponseEntity> expectedResponse) { + verifyGetById(expectedResponse); + } + + @Theory + public void getByNameWithString(@FromDataPoints("data-responses") + ResponseEntity> expectedResponse) { + verifyGetByNameWithString(expectedResponse); + } + + @Theory + public void getByNameWithCredentialName(@FromDataPoints("data-responses") + ResponseEntity> expectedResponse) { + verifyGetByNameWithCredentialName(expectedResponse); + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshCredentialDetailsUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshCredentialDetailsUnitTests.java new file mode 100644 index 0000000..36011f4 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshCredentialDetailsUnitTests.java @@ -0,0 +1,81 @@ +/* + * 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; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class SshCredentialDetailsUnitTests extends JsonParsingUnitTestsBase { + private static final String SSH_CREDENTIALS = + " \"type\": \"ssh\"," + + " \"value\": {" + + " \"private_key\": \"private-key\"," + + " \"public_key\": \"public-key\"" + + " }"; + + @Test + public void deserializeDetailsWithPublicAndPrivateKeys() throws Exception { + CredentialDetails data = parseDetails(SSH_CREDENTIALS, SshCredential.class); + + assertDetails(data, "public-key", "private-key"); + } + + @Test + public void deserializeDetailsWithPublicKey() throws Exception { + final String credentials = + " \"type\": \"ssh\"," + + " \"value\": {" + + " \"public_key\": \"public-key\"" + + " }"; + CredentialDetails data = parseDetails(credentials, SshCredential.class); + + assertDetails(data, "public-key", null); + } + + @Test + public void deserializeDetailsWithPrivateKey() throws Exception { + final String credentials = + " \"type\": \"ssh\"," + + " \"value\": {" + + " \"private_key\": \"private-key\"" + + " }"; + CredentialDetails data = parseDetails(credentials, SshCredential.class); + + assertDetails(data, null, "private-key"); + } + + @Test + public void deserializeDetailsData() throws Exception { + CredentialDetailsData response = parseDetailsData(SSH_CREDENTIALS, SshCredential.class); + + assertThat(response.getData().size(), equalTo(1)); + + CredentialDetails data = response.getData().get(0); + + assertDetails(data, "public-key", "private-key"); + } + + private void assertDetails(CredentialDetails data, String publicKey, String privateKey) { + assertCommonDetails(data); + + assertThat(data.getValueType(), equalTo(ValueType.SSH)); + assertThat(data.getValue().getPublicKey(), equalTo(publicKey)); + assertThat(data.getValue().getPrivateKey(), equalTo(privateKey)); + } +} diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshWriteRequestUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshWriteRequestUnitTests.java new file mode 100644 index 0000000..8d08d92 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SshWriteRequestUnitTests.java @@ -0,0 +1,93 @@ +/* + * 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; + +import org.junit.Before; +import org.junit.Test; + +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 SshWriteRequestUnitTests extends WriteRequestUnitTestsBase { + @Before + public void setUp() { + buildRequest(new SshCredential("public-key", "private-key")); + } + + @Test + public void serializeWithPublicAndPrivateKey() throws Exception { + String jsonValue = serializeToJson(requestBuilder); + + assertThat(jsonValue, + allOf(hasJsonPath("$.overwrite", equalTo(true)), + hasJsonPath("$.name", equalTo("/c/example/credential")), + hasJsonPath("$.type", equalTo("ssh")), + hasJsonPath("$.value.public_key", equalTo("public-key")), + hasJsonPath("$.value.private_key", equalTo("private-key")))); + + assertThat(jsonValue, hasNoJsonPath("$.additional_permissions")); + } + + @Test + public void serializeWithPublicKey() throws Exception { + buildRequest(new SshCredential("public-key", null)); + + String jsonValue = serializeToJson(requestBuilder); + + assertThat(jsonValue, + allOf(hasJsonPath("$.overwrite", equalTo(true)), + hasJsonPath("$.name", equalTo("/c/example/credential")), + hasJsonPath("$.type", equalTo("ssh")), + hasJsonPath("$.value.public_key", equalTo("public-key")), + hasNoJsonPath("$.value.private_key"))); + + assertThat(jsonValue, hasNoJsonPath("$.additional_permissions")); + } + + @Test + public void serializeWithPrivateKey() throws Exception { + buildRequest(new SshCredential(null, "private-key")); + + String jsonValue = serializeToJson(requestBuilder); + + assertThat(jsonValue, + allOf(hasJsonPath("$.overwrite", equalTo(true)), + hasJsonPath("$.name", equalTo("/c/example/credential")), + hasJsonPath("$.type", equalTo("ssh")), + hasNoJsonPath("$.value.public_key"), + hasJsonPath("$.value.private_key", equalTo("private-key")))); + + assertThat(jsonValue, hasNoJsonPath("$.additional_permissions")); + } + + @Test(expected = IllegalArgumentException.class) + public void serializeWithNeitherKey() throws Exception { + buildRequest(new SshCredential(null, null)); + + String jsonValue = serializeToJson(requestBuilder); + } + + private void buildRequest(SshCredential value) { + requestBuilder = SshWriteRequest.builder() + .name(new SimpleCredentialName("example", "credential")) + .overwrite(true) + .value(value); + } +} \ No newline at end of file