From 75b06263de62e3596eb3cd62b61b41e9c5131ca3 Mon Sep 17 00:00:00 2001 From: Scott Frederick Date: Fri, 21 Apr 2017 18:32:27 -0500 Subject: [PATCH] Polish and add JavaDoc. --- etc/ide/eclipse-code-formatter.xml | 296 ++++++++++++++++++ etc/ide/eclipse.importorder | 7 + manifest.yml | 8 + pom.xml | 1 + spring-credhub-core/pom.xml | 7 - .../ClientHttpRequestFactoryFactory.java | 34 +- .../configuration/CredHubConfiguration.java | 61 +++- .../CloudFoundryAppInstanceProperties.java | 31 +- .../credhub/core/CredHubClient.java | 56 +++- .../credhub/core/CredHubException.java | 24 +- .../credhub/core/CredHubOperations.java | 180 +++++++++++ .../credhub/core/CredHubProperties.java | 22 +- .../credhub/core/CredHubTemplate.java | 263 +++++++++++++--- .../credhub/core/RestOperationsCallback.java | 3 +- .../credhub/support/AccessControlEntry.java | 175 ++++++++++- .../credhub/support/ClientOptions.java | 12 +- .../credhub/support/CredHubRequest.java | 59 ---- .../credhub/support/CredHubResponse.java | 81 ----- .../credhub/support/CredentialData.java | 156 --------- .../support/CredentialDataResponse.java | 138 -------- .../credhub/support/CredentialDetails.java | 234 ++++++++++++++ .../support/CredentialDetailsData.java | 177 +++++++++++ .../credhub/support/CredentialName.java | 59 +++- .../credhub/support/CredentialSummary.java | 163 ++++++++++ .../support/CredentialSummaryData.java | 179 +++++++++++ .../credhub/support/FindResponse.java | 204 ------------ .../credhub/support/ReadRequest.java | 32 -- .../ServiceInstanceCredentialName.java | 128 +++++++- .../credhub/support/SimpleCredentialName.java | 37 ++- .../credhub/support/SslConfiguration.java | 105 ++++++- .../credhub/support/ValueType.java | 23 ++ .../credhub/support/WriteRequest.java | 263 +++++++++++----- .../ClientHttpRequestFactoryFactoryTests.java | 9 +- .../credhub/core/CredHubClientUnitTests.java | 15 +- ...redHubTemplateDetailResponseUnitTests.java | 118 +++++++ ...edHubTemplateDetailsResponseUnitTests.java | 114 +++++++ ...edHubTemplateSummaryResponseUnitTests.java | 135 ++++++++ .../credhub/core/CredHubTemplateTests.java | 269 ---------------- .../core/CredHubTemplateUnitTests.java | 106 +++++++ .../core/CredHubTemplateUnitTestsBase.java | 44 +++ ...va => CredentialDetailsDataUnitTests.java} | 65 ++-- .../CredentialSummaryDataUnitTests.java | 82 +++++ .../support/JsonParsingUnitTestsBase.java | 41 +++ ...erviceInstanceCredentialNameUnitTests.java | 32 ++ ...ava => SimpleCredentialNameUnitTests.java} | 17 +- .../support/WriteRequestUnitTests.java | 105 +++---- spring-credhub-demo/pom.xml | 75 +++++ .../credhub/demo/Application.java | 29 ++ .../demo/CredHubDemoConfiguration.java | 26 ++ .../credhub/demo/CredHubDemoController.java | 194 ++++++++++++ 50 files changed, 3420 insertions(+), 1274 deletions(-) create mode 100644 etc/ide/eclipse-code-formatter.xml create mode 100644 etc/ide/eclipse.importorder create mode 100644 manifest.yml create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubOperations.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubRequest.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubResponse.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialData.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDataResponse.java create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetailsData.java create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummary.java create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummaryData.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/FindResponse.java delete mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/support/ReadRequest.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailResponseUnitTests.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailsResponseUnitTests.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateSummaryResponseUnitTests.java delete mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateTests.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTests.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTestsBase.java rename spring-credhub-core/src/test/java/org/springframework/credhub/support/{CredentialDataResponseUnitTests.java => CredentialDetailsDataUnitTests.java} (56%) create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialSummaryDataUnitTests.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/support/JsonParsingUnitTestsBase.java create mode 100644 spring-credhub-core/src/test/java/org/springframework/credhub/support/ServiceInstanceCredentialNameUnitTests.java rename spring-credhub-core/src/test/java/org/springframework/credhub/support/{CredHubRequestUnitTests.java => SimpleCredentialNameUnitTests.java} (62%) create mode 100644 spring-credhub-demo/pom.xml create mode 100644 spring-credhub-demo/src/main/java/org/springframework/credhub/demo/Application.java create mode 100644 spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoConfiguration.java create mode 100644 spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoController.java diff --git a/etc/ide/eclipse-code-formatter.xml b/etc/ide/eclipse-code-formatter.xml new file mode 100644 index 0000000..6f7bc03 --- /dev/null +++ b/etc/ide/eclipse-code-formatter.xml @@ -0,0 +1,296 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/ide/eclipse.importorder b/etc/ide/eclipse.importorder new file mode 100644 index 0000000..8b4e3b2 --- /dev/null +++ b/etc/ide/eclipse.importorder @@ -0,0 +1,7 @@ +#Organize Import Order +#Thu Oct 13 16:40:43 CEST 2016 +4=\# +3=org.springframework +2= +1=javax +0=java \ No newline at end of file diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..2421a50 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,8 @@ +--- +applications: +- name: spring-credhub-demo + memory: 1G + path: spring-credhub-demo/target/spring-credhub-demo-1.0.0.BUILD-SNAPSHOT.jar + env: + logging.level.org.apache.http.wire: DEBUG + diff --git a/pom.xml b/pom.xml index 3e58748..c495785 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ spring-credhub-dependencies spring-credhub-core + spring-credhub-demo diff --git a/spring-credhub-core/pom.xml b/spring-credhub-core/pom.xml index e9b02a7..e0b050e 100644 --- a/spring-credhub-core/pom.xml +++ b/spring-credhub-core/pom.xml @@ -74,13 +74,6 @@ json-path-matchers test - - - org.projectlombok - lombok - 1.16.10 - true - diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactory.java b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactory.java index ab08937..07887dd 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactory.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactory.java @@ -16,12 +16,18 @@ package org.springframework.credhub.configuration; +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLContext; + import org.apache.http.client.config.RequestConfig; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; + import org.springframework.credhub.support.ClientOptions; import org.springframework.credhub.support.SslConfiguration; import org.springframework.http.client.ClientHttpRequestFactory; @@ -29,17 +35,13 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import javax.net.ssl.SSLContext; -import java.io.IOException; -import java.security.GeneralSecurityException; - /** * Factory for {@link ClientHttpRequestFactory} that supports Apache HTTP Components, * OkHttp, Netty and the JDK HTTP client (in that order). This factory configures a * {@link ClientHttpRequestFactory} depending on the available dependencies. * - * @author Scott Frederick * @author Mark Paluch + * @author Scott Frederick */ public class ClientHttpRequestFactoryFactory { @@ -51,13 +53,13 @@ public class ClientHttpRequestFactoryFactory { * Create a {@link ClientHttpRequestFactory} for the given {@link ClientOptions} and * {@link SslConfiguration}. * - * @param options must not be {@literal null} + * @param options must not be {@literal null} * @param sslConfiguration must not be {@literal null} * @return a new {@link ClientHttpRequestFactory}. Lifecycle beans must be initialized * after obtaining. */ public static ClientHttpRequestFactory create(ClientOptions options, - SslConfiguration sslConfiguration) { + SslConfiguration sslConfiguration) { Assert.notNull(options, "ClientOptions must not be null"); Assert.notNull(sslConfiguration, "SslConfiguration must not be null"); @@ -66,9 +68,11 @@ public class ClientHttpRequestFactoryFactory { if (HTTP_COMPONENTS_PRESENT) { return HttpComponents.usingHttpComponents(options, sslConfiguration); } - } catch (GeneralSecurityException e) { + } + catch (GeneralSecurityException e) { throw new IllegalStateException(e); - } catch (IOException e) { + } + catch (IOException e) { throw new IllegalStateException(e); } @@ -85,18 +89,22 @@ public class ClientHttpRequestFactoryFactory { */ static class HttpComponents { - static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslConfiguration sslConfiguration) + static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, + SslConfiguration sslConfiguration) throws GeneralSecurityException, IOException { HttpClientBuilder httpClientBuilder = HttpClients.custom(); if (hasSslConfiguration(sslConfiguration)) { SSLContext sslContext = SSLContexts.custom() - .loadTrustMaterial(sslConfiguration.getKeyStore(), new TrustSelfSignedStrategy()) - .loadKeyMaterial(sslConfiguration.getTrustStore(), sslConfiguration.getKeyPassword()) + .loadTrustMaterial(sslConfiguration.getKeyStore(), + new TrustSelfSignedStrategy()) + .loadKeyMaterial(sslConfiguration.getTrustStore(), + sslConfiguration.getKeyPassword()) .build(); - SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext); + SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory( + sslContext); httpClientBuilder.setSSLSocketFactory(sslSocketFactory); httpClientBuilder.setSSLContext(sslContext); } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/CredHubConfiguration.java b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/CredHubConfiguration.java index ef38cdd..5717816 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/CredHubConfiguration.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/CredHubConfiguration.java @@ -27,18 +27,53 @@ import org.springframework.credhub.support.ClientOptions; import org.springframework.credhub.support.SslConfiguration; import org.springframework.http.client.ClientHttpRequestFactory; +/** + * Configuration for the {@link CredHubTemplate} used to communicate with CredHub. This + * class is typically imported into Java-based Spring application configuration as in + * this example: + * + *
+ * {@code
+ * @Configuration
+ * @Import(CredHubConfiguration.class)
+ * public class MyConfiguration {
+ * }
+ * }
+ * 
+ * + * @author Scott Frederick + */ @Configuration public class CredHubConfiguration { + + /** + * Create the {@link CredHubProperties} that contains information about the + * CredHub server. + * + * @return the {@link CredHubProperties} bean + */ @Bean public CredHubProperties credHubProperties() { return new CredHubProperties(); } + /** + * Create the {@link CloudFoundryAppInstanceProperties} that contains information + * about the application instance running on Cloud Foundry. + * + * @return the {@link CloudFoundryAppInstanceProperties} bean + */ @Bean public CloudFoundryAppInstanceProperties cloudFoundryAppInstanceProperties() { return new CloudFoundryAppInstanceProperties(); } + /** + * Create the {@link CredHubTemplate} that the application will use to interact + * with CredHub. + * + * @return the {@link CredHubTemplate} bean + */ @Bean public CredHubTemplate credHubTemplate() { return new CredHubTemplate(credHubProperties().getApiUriBase(), @@ -46,11 +81,11 @@ public class CredHubConfiguration { } /** - * Create a {@link ClientFactoryWrapper} containing a {@link ClientHttpRequestFactory}. - * {@link ClientHttpRequestFactory} is not exposed as root bean because - * {@link ClientHttpRequestFactory} is configured with {@link ClientOptions} and - * {@link SslConfiguration} which are not necessarily applicable for the whole - * application. + * Create a {@link ClientFactoryWrapper} containing a + * {@link ClientHttpRequestFactory}. {@link ClientHttpRequestFactory} is not exposed + * as root bean because {@link ClientHttpRequestFactory} is configured with + * {@link ClientOptions} and {@link SslConfiguration} which are not necessarily + * applicable for the whole application. * * @return the {@link ClientFactoryWrapper} to wrap a {@link ClientHttpRequestFactory} * instance. @@ -65,20 +100,26 @@ public class CredHubConfiguration { } /** - * @return {@link ClientOptions} to configure communication parameters. - * @see ClientOptions + * Create the default {@link ClientOptions} to configure communication parameters. + * + * @return the default {@link ClientOptions} */ private ClientOptions clientOptions() { return new ClientOptions(); } /** - * @return SSL configuration options. - * @see SslConfiguration + * Create the default {@link SslConfiguration} to configure SSL context parameters. + * The default configuration uses a certificate and key supplied in the application + * container to configure mutual SSL authentication between the client application + * and the CredHub server. + * + * @return the default {@link SslConfiguration} */ private SslConfiguration sslConfiguration() { CloudFoundryAppInstanceProperties properties = cloudFoundryAppInstanceProperties(); - return SslConfiguration.forContainerCert(properties.getInstanceCertLocation(), properties.getInstanceKeyLocation()); + return SslConfiguration.forContainerCert(properties.getInstanceCertLocation(), + properties.getInstanceKeyLocation()); } /** diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CloudFoundryAppInstanceProperties.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CloudFoundryAppInstanceProperties.java index 5aa88a9..f82285d 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CloudFoundryAppInstanceProperties.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CloudFoundryAppInstanceProperties.java @@ -18,6 +18,12 @@ package org.springframework.credhub.core; import org.springframework.beans.factory.annotation.Value; +/** + * Properties containing information about an application instance + * running on Cloud Foundry. + * + * @author Scott Frederick + */ public class CloudFoundryAppInstanceProperties { @Value("${CF_INSTANCE_CERT}") private String instanceCertLocation; @@ -25,18 +31,41 @@ public class CloudFoundryAppInstanceProperties { @Value("${CF_INSTANCE_KEY}") private String instanceKeyLocation; + /** + * Create a new instance without initializing properties. + */ public CloudFoundryAppInstanceProperties() { } - public CloudFoundryAppInstanceProperties(String instanceCertLocation, String instanceKeyLocation) { + /** + * Create a new instance from the provided property values. Intended to be used + * internally for testing. + * + * @param instanceCertLocation the absolute path of the certificate file in the app + * instance container + * @param instanceKeyLocation the absolute path of the private key file in the app + * instance container + */ + CloudFoundryAppInstanceProperties(String instanceCertLocation, + String instanceKeyLocation) { this.instanceCertLocation = instanceCertLocation; this.instanceKeyLocation = instanceKeyLocation; } + /** + * Get the absolute path of the certificate file in the app instance container. + * + * @return the certificate file path + */ public String getInstanceCertLocation() { return instanceCertLocation; } + /** + * Get the absolute path of the private key file in the app instance container. + * + * @return the key file path + */ public String getInstanceKeyLocation() { return instanceKeyLocation; } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java index c686b92..5ceed36 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java @@ -18,21 +18,73 @@ package org.springframework.credhub.core; +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; + import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.converter.ByteArrayHttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.UriTemplateHandler; +/** + * Factory for creating a {@link RestTemplate} configured for communication with + * a CredHub server. + * + * @author Scott Frederick + */ public class CredHubClient { - public static RestTemplate createRestTemplate(String baseUri, ClientHttpRequestFactory clientHttpRequestFactory) { + /** + * Create a {@link RestTemplate} configured for communication with a CredHub server. + * + * @param baseUri the base URI for the CredHub server + * @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when + * creating new connections + * @return a configured {@link RestTemplate} + */ + public static RestTemplate createRestTemplate(String baseUri, + ClientHttpRequestFactory clientHttpRequestFactory) { RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(createUriTemplateHandler(baseUri)); restTemplate.setRequestFactory(clientHttpRequestFactory); + restTemplate.setUriTemplateHandler(createUriTemplateHandler(baseUri)); + restTemplate.setMessageConverters(createMessageConverters()); return restTemplate; } + /** + * Create a {@link UriTemplateHandler} that prefixes all {@link RestTemplate} calls + * with the configured {@literal baseUri}. + * + * @param baseUri the base URI for the CredHub server + * @return a configured {@link UriTemplateHandler} + */ private static DefaultUriTemplateHandler createUriTemplateHandler(String baseUri) { DefaultUriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler(); uriTemplateHandler.setBaseUrl(baseUri); return uriTemplateHandler; } + + /** + * Create the {@link HttpMessageConverter}s necessary to build request to + * and parse responses from CredHub. + * + * @return the list of {@link HttpMessageConverter}s + */ + private static List> createMessageConverters() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setDateFormat(new ISO8601DateFormat()); + + List> messageConverters = new ArrayList>(3); + messageConverters.add(new ByteArrayHttpMessageConverter()); + messageConverters.add(new StringHttpMessageConverter()); + messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper)); + + return messageConverters; + } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubException.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubException.java index daa262c..742302b 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubException.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubException.java @@ -20,16 +20,30 @@ import org.springframework.core.NestedRuntimeException; import org.springframework.http.HttpStatus; import org.springframework.web.client.HttpStatusCodeException; +/** + * Exception class to capture errors specific to CredHub communication. + * + * @author Scott Frederick + */ public class CredHubException extends NestedRuntimeException { + /** + * Create a new exception with the provided root cause. + * + * @param e an {@link HttpStatusCodeException} caught while attempting to communicate + * with CredHub + */ public CredHubException(HttpStatusCodeException e) { - super("Error calling CredHub: " + e.getStatusCode() + ": " + e.getResponseBodyAsString()); + super("Error calling CredHub: " + e.getStatusCode() + ": " + + e.getResponseBodyAsString()); } + /** + * Create a new exception with the provided error status code. + * + * @param statusCode an {@link HttpStatus} indicating an error while attempting to + * communicate with CredHub + */ public CredHubException(HttpStatus statusCode) { super("Error calling CredHub: " + statusCode); } - - public CredHubException(String message) { - super("Error returned from call to CredHub: " + message); - } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubOperations.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubOperations.java new file mode 100644 index 0000000..4ce3eed --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubOperations.java @@ -0,0 +1,180 @@ +/* + * 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 java.util.Map; + +import org.springframework.credhub.support.CredentialDetails; +import org.springframework.credhub.support.CredentialName; +import org.springframework.credhub.support.CredentialSummary; +import org.springframework.credhub.support.WriteRequest; +import org.springframework.web.client.RestTemplate; + +/** + * Specifies the main interaction with CredHub to save, retrieve, + * and delete credentials. + * + * @author Scott Frederick + */ +public interface CredHubOperations { + /** + * Write a new credential to CredHub, or overwrite an existing credential with a new + * value. + * + * @param writeRequest the credential to write to CredHub; must not be {@literal null} + * @return the details of the written credential + */ + CredentialDetails write(WriteRequest writeRequest); + + /** + * Retrieve a credential using its ID, as returned in a write request. + * + * @param id the ID of the credential; must not be {@literal null} + * @return the details of the retrieved credential + */ + CredentialDetails getById(String id); + + /** + * Retrieve a credential using its name, as passed to a write request. + * A collection of all stored values for the named credential will be returned, + * including historical values. + * + * @param name the name of the credential; must not be {@literal null} + * @return the details of the retrieved credential, including history + */ + List getByName(String name); + + /** + * Retrieve a credential using its name, as passed to a write request. + * A collection of all stored values for the named credential will be returned, + * including historical values. + * + * @param name the name of the credential; must not be {@literal null} + * @return the details of the retrieved credential, including history + */ + List getByName(CredentialName name); + + /** + * Find a credential using a full or partial name. + * + * @param name the name of the credential; must not be {@literal null} + * @return a summary of the credential search results + */ + List findByName(String name); + + /** + * Find a credential using a full or partial name. + * + * @param name the name of the credential; must not be {@literal null} + * @return a summary of the credential search results + */ + List findByName(CredentialName name); + + /** + * Find a credential using a path. + * + * @param path the path to the credential; must not be {@literal null} + * @return a summary of the credential search results + */ + List findByPath(String path); + + /** + * Delete a credential by its full name. + * + * @param name the name of the credential; must not be {@literal null} + */ + void deleteByName(String name); + + /** + * Delete a credential by its full name. + * + * @param name the name of the credential; must not be {@literal null} + */ + void deleteByName(CredentialName name); + + /** + * Search the provided data structure of bound service credentials, looking for + * references to CredHub credentials. Any CredHub credentials found in the data + * structure will be replaced by the credential value stored in CredHub. + * + * Example: + * + * A JSON data structure parsed from a {@literal VCAP_SERVICES} environment + * variable might look like this if the service broker that provided the binding + * is integrated with CredHub: + * + *
+	 * {@code
+	 * {
+	 *    "service-offering": [{
+	 *      "credentials": {
+	 *        "credhub-ref": "((/c/service-broker/service-offering/1111-2222-3333-4444/credentials))"
+	 *      }
+	 *      "label": "service-offering",
+	 *      "name": "service-instance",
+	 *      "plan": "standard",
+	 *      "tags": ["
+	 *        "cloud-service"
+	 *      ]
+	 *    }]
+	 * }
+	 * }
+	 * 
+ * + * Assuming that CredHub has a credential with the name + * {@literal /c/service-broker/service-offering/1111-2222-3333-4444/credentials}, + * passing the data structure above to this method would result in the + * {@literal credhub-ref} field being replaced by the credentials stored in CredHub: + * + *
+	 * {@code
+	 * {
+	 *    "service-offering": [{
+	 *      "credentials": {
+	 *        "url": "https://servicehost.example.com/",
+	 *        "username": "someuser",
+	 *        "password": "secret"
+	 *      }
+	 *      "label": "service-offering",
+	 *      "name": "service-instance",
+	 *      "plan": "standard",
+	 *      "tags": ["
+	 *        "cloud-service"
+	 *      ]
+	 *    }]
+	 * }
+	 * }
+	 * 
+ * + * @param serviceData a data structure of bound service credentials, as would be + * parsed from the {@literal VCAP_SERVICES} environment variable provided to + * applications running on Cloud Foundry + * @return the serviceData structure with CredHub references replaced by stored + * credential values + */ + Map interpolateServiceData(Map serviceData); + + /** + * Allow interaction with the configured {@link RestTemplate} not provided + * by other methods. + * + * @param callback wrapper for the callback method + * @return the return value from the callback method + */ + T doWithRest(RestOperationsCallback callback); +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubProperties.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubProperties.java index c4525ec..1f205b8 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubProperties.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubProperties.java @@ -20,17 +20,37 @@ package org.springframework.credhub.core; import org.springframework.beans.factory.annotation.Value; +/** + * Properties containing information about a CredHub server. + * + * @author Scott Frederick + */ public class CredHubProperties { @Value("${CREDHUB_API}") private String apiUriBase; + /** + * Create a new instance without initializing properties. + */ public CredHubProperties() { } - public CredHubProperties(String apiUriBase) { + /** + * Create a new instance with the provided properties. Intended to be used + * internally for testing. + * + * @param apiUriBase the base URI for the CredHub server + */ + CredHubProperties(String apiUriBase) { this.apiUriBase = apiUriBase; } + /** + * Get the base URI for the CredHub server (scheme, host, and port). This value + * will be prepended to all requests to CredHub. + * + * @return the base URI + */ public String getApiUriBase() { return apiUriBase; } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubTemplate.java index b94c18e..ad10050 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubTemplate.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubTemplate.java @@ -1,9 +1,31 @@ +/* + * 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 org.springframework.credhub.support.CredHubResponse; -import org.springframework.credhub.support.CredentialDataResponse; -import org.springframework.credhub.support.CredentialData; -import org.springframework.credhub.support.FindResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.credhub.support.CredentialDetails; +import org.springframework.credhub.support.CredentialDetailsData; +import org.springframework.credhub.support.CredentialName; +import org.springframework.credhub.support.CredentialSummary; +import org.springframework.credhub.support.CredentialSummaryData; import org.springframework.credhub.support.WriteRequest; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; @@ -15,59 +37,65 @@ import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; -public class CredHubTemplate { +/** + * Implements the main interaction with CredHub to save, retrieve, + * and delete credentials. + * + * @author Scott Frederick + */ +public class CredHubTemplate implements CredHubOperations { static final String BASE_URL_PATH = "/api/v1/data"; static final String ID_URL_PATH = BASE_URL_PATH + "/{id}"; static final String NAME_URL_QUERY = BASE_URL_PATH + "?name={name}"; static final String NAME_LIKE_URL_QUERY = BASE_URL_PATH + "?name-like={name}"; static final String PATH_URL_QUERY = BASE_URL_PATH + "?path={path}"; + static final String INTERPOLATE_URL_PATH = "/api/v1/vcap"; + + static final String VCAP_SERVICES_KEY = "VCAP_SERVICES"; private final RestTemplate restTemplate; + /** + * Create a new {@link CredHubTemplate} using the provided {@link RestTemplate}. + * Intended for internal testing only. + * + * @param restTemplate the {@link RestTemplate} to use for interactions with CredHub + */ CredHubTemplate(RestTemplate restTemplate) { + Assert.notNull(restTemplate, "restTemplate must not be null"); + this.restTemplate = restTemplate; } + /** + * Create a new {@link CredHubTemplate} using the provided base URI and + * {@link ClientHttpRequestFactory}. + * + * @param apiUriBase the base URI for the CredHub server (scheme, host, and port); + * must not be {@literal null} + * @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when + * creating new connections + */ public CredHubTemplate(String apiUriBase, ClientHttpRequestFactory clientHttpRequestFactory) { - this.restTemplate = CredHubClient.createRestTemplate(apiUriBase, clientHttpRequestFactory); + Assert.notNull(apiUriBase, "apiUriBase must not be null"); + Assert.notNull(clientHttpRequestFactory, "clientHttpRequestFactory must not be null"); + + this.restTemplate = CredHubClient.createRestTemplate(apiUriBase, + clientHttpRequestFactory); } - public CredentialData write(final WriteRequest writeRequest) { - return doWithRest(new RestOperationsCallback() { + @Override + public CredentialDetails write(final WriteRequest writeRequest) { + Assert.notNull(writeRequest, "writeRequest must not be null"); + + return doWithRest(new RestOperationsCallback() { @Override - public CredentialData doWithRestOperations(RestOperations restOperations) { - ResponseEntity response = - restOperations.exchange(BASE_URL_PATH, HttpMethod.PUT, + public CredentialDetails doWithRestOperations( + RestOperations restOperations) { + ResponseEntity response = restOperations + .exchange(BASE_URL_PATH, HttpMethod.PUT, new HttpEntity(writeRequest), - CredentialDataResponse.class); - - throwExceptionOnError(response); - - return response.getBody().getData().get(0); - } - }); - } - - public CredentialData getById(final String id) { - return doWithRest(new RestOperationsCallback() { - @Override - public CredentialData doWithRestOperations(RestOperations restOperations) { - ResponseEntity response = - restOperations.getForEntity(ID_URL_PATH, CredentialDataResponse.class, id); - - throwExceptionOnError(response); - - return response.getBody().getData().get(0); - } - }); - } - - public FindResponse findByName(final String name) { - return doWithRest(new RestOperationsCallback() { - @Override - public FindResponse doWithRestOperations(RestOperations restOperations) { - ResponseEntity response = - restOperations.getForEntity(NAME_LIKE_URL_QUERY, FindResponse.class, name); + CredentialDetails.class); throwExceptionOnError(response); @@ -76,12 +104,16 @@ public class CredHubTemplate { }); } - public FindResponse findByPath(final String path) { - return doWithRest(new RestOperationsCallback() { + @Override + public CredentialDetails getById(final String id) { + Assert.notNull(id, "credential id must not be null"); + + return doWithRest(new RestOperationsCallback() { @Override - public FindResponse doWithRestOperations(RestOperations restOperations) { - ResponseEntity response = - restOperations.getForEntity(PATH_URL_QUERY, FindResponse.class, path); + public CredentialDetails doWithRestOperations( + RestOperations restOperations) { + ResponseEntity response = restOperations + .getForEntity(ID_URL_PATH, CredentialDetails.class, id); throwExceptionOnError(response); @@ -90,7 +122,81 @@ public class CredHubTemplate { }); } + @Override + public List getByName(final String name) { + Assert.notNull(name, "credential name must not be null"); + + return doWithRest(new RestOperationsCallback>() { + @Override + public List doWithRestOperations( + RestOperations restOperations) { + ResponseEntity response = restOperations + .getForEntity(NAME_URL_QUERY, CredentialDetailsData.class, + name); + + throwExceptionOnError(response); + + return response.getBody().getData(); + } + }); + } + + @Override + public List getByName(final CredentialName name) { + Assert.notNull(name, "credential name must not be null"); + + return getByName(name.getName()); + } + + @Override + public List findByName(final String name) { + Assert.notNull(name, "credential name must not be null"); + + return doWithRest(new RestOperationsCallback>() { + @Override + public List doWithRestOperations( + RestOperations restOperations) { + ResponseEntity response = restOperations + .getForEntity(NAME_LIKE_URL_QUERY, + CredentialSummaryData.class, name); + + throwExceptionOnError(response); + + return response.getBody().getCredentials(); + } + }); + } + + @Override + public List findByName(final CredentialName name) { + Assert.notNull(name, "credential name must not be null"); + + return findByName(name.getName()); + } + + @Override + public List findByPath(final String path) { + Assert.notNull(path, "credential path must not be null"); + + return doWithRest(new RestOperationsCallback>() { + @Override + public List doWithRestOperations( + RestOperations restOperations) { + ResponseEntity response = restOperations + .getForEntity(PATH_URL_QUERY, CredentialSummaryData.class, + path); + + throwExceptionOnError(response); + + return response.getBody().getCredentials(); + } + }); + } + + @Override public void deleteByName(final String name) { + Assert.notNull(name, "credential name must not be null"); + doWithRest(new RestOperationsCallback() { @Override public Void doWithRestOperations(RestOperations restOperations) { @@ -100,23 +206,76 @@ public class CredHubTemplate { }); } + @Override + public void deleteByName(final CredentialName name) { + Assert.notNull(name, "credential name must not be null"); + + deleteByName(name.getName()); + } + + @Override + public Map interpolateServiceData(final Map serviceData) { + Assert.notNull(serviceData, "serviceData must not be null"); + + return doWithRest(new RestOperationsCallback>() { + @Override + public Map doWithRestOperations(RestOperations restOperations) { + Map> wrappedServiceData = wrapServiceDataRequest(serviceData); + + ResponseEntity>> response = restOperations + .exchange(INTERPOLATE_URL_PATH, HttpMethod.POST, + new HttpEntity>>(wrappedServiceData), mapType()); + + throwExceptionOnError(response); + + return response.getBody().get(VCAP_SERVICES_KEY); + } + }); + } + + @Override public T doWithRest(RestOperationsCallback callback) { - Assert.notNull(callback, "Callback must not be null"); + Assert.notNull(callback, "callback must not be null"); try { return callback.doWithRestOperations(restTemplate); - } catch (HttpStatusCodeException e) { + } + catch (HttpStatusCodeException e) { throw new CredHubException(e); } } - private void throwExceptionOnError(ResponseEntity response) { + /** + * Wrap the service data structure with the "VCAP_SERVICES" key as required by the + * CredHub interpolation API. + * + * @param serviceData a {@literal Map} of services details + * @return the provided {@literal serviceData} structure wrapped with the "VCAP_SERVICES" key + */ + private Map> wrapServiceDataRequest(Map serviceData) { + Map> wrappedServiceData = new HashMap>(); + wrappedServiceData.put(VCAP_SERVICES_KEY, serviceData); + return wrappedServiceData; + } + + /** + * Helper method to create a type reference for use by {@link RestTemplate}. + * + * @return the type reference for a {@literal Map} type + */ + private ParameterizedTypeReference>> mapType() { + return new ParameterizedTypeReference>>() {}; + } + + /** + * Helper method to throw an appropriate exception if a request to CredHub + * returns with an error code. + * + * @param response a {@link ResponseEntity} returned from {@link RestTemplate} + */ + private void throwExceptionOnError(ResponseEntity response) { if (!response.getStatusCode().equals(HttpStatus.OK)) { throw new CredHubException(response.getStatusCode()); } - - if (response.getBody().getErrorMessage() != null) { - throw new CredHubException(response.getBody().getErrorMessage()); - } } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/RestOperationsCallback.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/RestOperationsCallback.java index 91b4455..28461d9 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/RestOperationsCallback.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/RestOperationsCallback.java @@ -26,7 +26,8 @@ import org.springframework.web.client.RestOperations; public interface RestOperationsCallback { /** - * Callback method providing a {@link RestOperations} that is configured to interact with the CredHub server. + * Callback method providing a {@link RestOperations} that is configured to interact + * with the CredHub server. * * @param restOperations restOperations to use, must not be {@literal null}. * @return a result object or null if none. diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/AccessControlEntry.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/AccessControlEntry.java index 70cdd64..3cdea52 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/AccessControlEntry.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/AccessControlEntry.java @@ -18,26 +18,54 @@ package org.springframework.credhub.support; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Data; -import lombok.Setter; -import lombok.Singular; - import java.util.ArrayList; +import java.util.Collection; import java.util.List; -@Data -@Builder +/** + * Access control requirements for a credential in CredHub. If provided when a + * credential is written, these values will control what actors can access update + * or retrieve the credential. + * + * This object of this type is typically constructed by the application and passed + * as part of a {@link WriteRequest}. + * + * @author Scott Frederick + */ public class AccessControlEntry { private static final String APP_ACTOR_PREFIX = "mtls-app:"; - - @Setter(AccessLevel.PRIVATE) - private String actor; - @Singular + private String actor; private List operations; + /** + * Create a set of access controls. Intended to be used internally for testing. + * Clients should use {@link #builder()} to construct instances of this class. + * + * @param actor the ID of the entity that will be allowed to access the credential + * @param operations the operations that the actor will be allowed to perform on the + * credential + */ + AccessControlEntry(String actor, List operations) { + this.actor = actor; + this.operations = operations; + } + + /** + * Get the ID of the entity that will be allowed to access the credential + * + * @return the ID + */ + public String getActor() { + return this.actor; + } + + /** + * Get the set of operations that the actor will be allowed to perform on + * the credential. + * + * @return the operations + */ public List getOperations() { List operationValues = new ArrayList(operations.size()); for (Operation operation : operations) { @@ -46,13 +74,136 @@ public class AccessControlEntry { return operationValues; } + /** + * Create a builder that provides a fluent API for providing the values required + * to construct a {@link AccessControlEntry}. + * + * @return a builder + */ + public static AccessControlEntryBuilder builder() { + return new AccessControlEntryBuilder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof AccessControlEntry)) + return false; + + AccessControlEntry that = (AccessControlEntry) o; + + if (actor != null ? !actor.equals(that.actor) : that.actor != null) + return false; + return operations != null ? operations.equals(that.operations) + : that.operations == null; + } + + @Override + public int hashCode() { + int result = actor != null ? actor.hashCode() : 0; + result = 31 * result + (operations != null ? operations.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "AccessControlEntry{" + + "actor='" + actor + '\'' + + ", operations=" + operations + + '}'; + } + + /** + * A builder that provides a fluent API for constructing {@link AccessControlEntry} + * instances. + */ public static class AccessControlEntryBuilder { + private String actor; + private ArrayList operations; + + AccessControlEntryBuilder() { + } + + /** + * Set the ID of an application that will be allowed to access a credential. + * This will often be a Cloud Foundry application GUID. + * + * @param appId application ID + * @return the builder + */ public AccessControlEntryBuilder app(String appId) { this.actor = APP_ACTOR_PREFIX + appId; return this; } + + /** + * Set the name of an actor that will be allowed to access the credential. + * + * @param actor actor name + * @return the builder + */ + public AccessControlEntryBuilder actor(String actor) { + this.actor = actor; + return this; + } + + /** + * Set an {@link Operation} that the actor will be allowed to perform on + * the credential. Multiple operations can be provided with consecutive calls to + * this method. + * + * @param operation the {@link Operation} + * @return the builder + */ + public AccessControlEntryBuilder operation(Operation operation) { + initOperations(); + this.operations.add(operation); + return this; + } + + /** + * Specify a set of {@link Operation}s that the actor will be allowed to perform + * on the credential. + * + * @param operations the {@link Operation}s + * @return the builder + */ + public AccessControlEntryBuilder operations(Collection operations) { + initOperations(); + this.operations.addAll(operations); + return this; + } + + private void initOperations() { + if (this.operations == null) this.operations = new ArrayList(); + } + + /** + * Construct an {@link AccessControlEntry} with the provided values. + * + * @return an {@link AccessControlEntry} + */ + public AccessControlEntry build() { + List operations; + switch (this.operations == null ? 0 : this.operations.size()) { + case 0: + operations = java.util.Collections.emptyList(); + break; + case 1: + operations = java.util.Collections.singletonList(this.operations.get(0)); + break; + default: + operations = java.util.Collections.unmodifiableList(new ArrayList(this.operations)); + } + + return new AccessControlEntry(actor, operations); + } } + /** + * The set of operations that are allowed on a credential. + */ public enum Operation { READ("read"), WRITE("write"); diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ClientOptions.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ClientOptions.java index f5d2119..0d5ebbd 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ClientOptions.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ClientOptions.java @@ -19,7 +19,7 @@ package org.springframework.credhub.support; import java.util.concurrent.TimeUnit; /** - * Client options for CredHubConnectivity. + * Client options for CredHub connectivity. * * @author Mark Paluch * @author Scott Frederick @@ -46,7 +46,7 @@ public class ClientOptions { } /** - * Create new {@link ClientOptions}. + * Create a {@link ClientOptions} with the provided values. * * @param connectionTimeout connection timeout in {@link TimeUnit#MILLISECONDS}, must * be greater {@literal 0}. @@ -59,14 +59,18 @@ public class ClientOptions { } /** - * @return the connection timeout in {@link TimeUnit#MILLISECONDS}. + * Gets the connection timeout in {@link TimeUnit#MILLISECONDS}. + * + * @return the connection timeout */ public int getConnectionTimeout() { return connectionTimeout; } /** - * @return the read timeout in {@link TimeUnit#MILLISECONDS}. + * Gets the read timeout in {@link TimeUnit#MILLISECONDS} + * + * @return the read timeout */ public int getReadTimeout() { return readTimeout; diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubRequest.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubRequest.java deleted file mode 100644 index 65db233..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubRequest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * - * * Copyright 2013-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 com.fasterxml.jackson.annotation.JsonInclude; - -public class CredHubRequest { - private CredentialName name; - - CredHubRequest(CredentialName name) { - this.name = name; - } - - CredHubRequest() { - } - - @JsonInclude - public String getName() { - return name.getName(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CredHubRequest)) return false; - - CredHubRequest that = (CredHubRequest) o; - - return name != null ? name.equals(that.name) : that.name == null; - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - return "CredHubRequest{" + - "name=" + name + - '}'; - } -} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubResponse.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubResponse.java deleted file mode 100644 index 4d8b6b7..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredHubResponse.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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 com.fasterxml.jackson.annotation.JsonProperty; - -public class CredHubResponse { - @JsonProperty("errorMessage") - protected final String errorMessage; - - CredHubResponse() { - errorMessage = null; - } - - CredHubResponse(String errorMessage) { - this.errorMessage = errorMessage; - } - - public String getErrorMessage() { - return this.errorMessage; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - CredHubResponse that = (CredHubResponse) o; - - return errorMessage != null ? errorMessage.equals(that.errorMessage) : that.errorMessage == null; - } - - @Override - public int hashCode() { - return errorMessage != null ? errorMessage.hashCode() : 0; - } - - @Override - public String toString() { - return "CredHubResponse{" + - "errorMessage='" + errorMessage + '\'' + - '}'; - } - - public static class CredHubResponseBuilder { - private String errorMessage; - - CredHubResponseBuilder() { - } - - public CredHubResponse.CredHubResponseBuilder errorMessage(String errorMessage) { - this.errorMessage = errorMessage; - return this; - } - - public CredHubResponse build() { - return new CredHubResponse(errorMessage); - } - - @Override - public String toString() { - return "CredHubResponseBuilder{" + - "errorMessage='" + errorMessage + '\'' + - '}'; - } - } -} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialData.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialData.java deleted file mode 100644 index 42d58af..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialData.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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 com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; - -import java.util.Map; - -@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) -public class CredentialData { - private String id; - private CredentialName name; - @JsonProperty("type") - private ValueType valueType; - private Object value; - private String versionCreatedAt; - - public CredentialData() { - } - - CredentialData(String id, CredentialName name, ValueType valueType, Object value, String versionCreatedAt) { - this.id = id; - this.name = name; - this.valueType = valueType; - this.value = value; - this.versionCreatedAt = versionCreatedAt; - } - - public static CredentialDataBuilder builder() { - return new CredentialDataBuilder(); - } - - public String getId() { - return this.id; - } - - public CredentialName getName() { - return this.name; - } - - public ValueType getValueType() { - return this.valueType; - } - - public Object getValue() { - return this.value; - } - - public String getVersionCreatedAt() { - return this.versionCreatedAt; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CredentialData)) return false; - - CredentialData that = (CredentialData) o; - - if (id != null ? !id.equals(that.id) : that.id != null) return false; - if (name != null ? !name.equals(that.name) : that.name != null) return false; - if (valueType != that.valueType) return false; - if (value != null ? !value.equals(that.value) : that.value != null) return false; - return versionCreatedAt != null ? versionCreatedAt.equals(that.versionCreatedAt) : that.versionCreatedAt == null; - } - - @Override - public int hashCode() { - int result = id != null ? id.hashCode() : 0; - result = 31 * result + (name != null ? name.hashCode() : 0); - result = 31 * result + (valueType != null ? valueType.hashCode() : 0); - result = 31 * result + (value != null ? value.hashCode() : 0); - result = 31 * result + (versionCreatedAt != null ? versionCreatedAt.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "CredentialData{" + - "id='" + id + '\'' + - ", name=" + name + - ", valueType=" + valueType + - ", value=" + value + - ", versionCreatedAt='" + versionCreatedAt + '\'' + - '}'; - } - - public static class CredentialDataBuilder { - private String id; - private CredentialName name; - private ValueType valueType; - private Object value; - private String versionCreatedAt; - - CredentialDataBuilder() { - } - - public CredentialData.CredentialDataBuilder id(String id) { - this.id = id; - return this; - } - - public CredentialData.CredentialDataBuilder name(CredentialName name) { - this.name = name; - return this; - } - - public CredentialData.CredentialDataBuilder passwordValue(String value) { - this.valueType = ValueType.PASSWORD; - this.value = value; - return this; - } - - public CredentialData.CredentialDataBuilder jsonValue(Map value) { - this.valueType = ValueType.JSON; - this.value = value; - return this; - } - - public CredentialData.CredentialDataBuilder versionCreatedAt(String versionCreatedAt) { - this.versionCreatedAt = versionCreatedAt; - return this; - } - - public CredentialData build() { - return new CredentialData(id, name, valueType, value, versionCreatedAt); - } - - @Override - public String toString() { - return "CredentialDataBuilder{" + - "id='" + id + '\'' + - ", name=" + name + - ", valueType=" + valueType + - ", value=" + value + - ", versionCreatedAt='" + versionCreatedAt + '\'' + - '}'; - } - } -} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDataResponse.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDataResponse.java deleted file mode 100644 index f1604eb..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDataResponse.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * - * * Copyright 2013-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 com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; - -@JsonInclude(NON_EMPTY) -public class CredentialDataResponse extends CredHubResponse { - private List data; - - public CredentialDataResponse() { - } - - CredentialDataResponse(String errorMessage) { - super(errorMessage); - } - - CredentialDataResponse(List data) { - super(null); - this.data = data; - } - - CredentialDataResponse(String errorMessage, List data) { - super(errorMessage); - this.data = data; - } - - public static CredentialDataResponseBuilder builder() { - return new CredentialDataResponseBuilder(); - } - - public List getData() { - return this.data; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof CredentialDataResponse)) return false; - if (!super.equals(o)) return false; - - CredentialDataResponse that = (CredentialDataResponse) o; - - return data != null ? data.equals(that.data) : that.data == null; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (data != null ? data.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "CredentialDataResponse{" + - "errorMessage=" + errorMessage + - ", data=" + data + - '}'; - } - - public static class CredentialDataResponseBuilder { - private String errorMessage; - private ArrayList data; - - CredentialDataResponseBuilder() { - } - - public CredentialDataResponse.CredentialDataResponseBuilder errorMessage(String errorMessage) { - this.errorMessage = errorMessage; - return this; - } - - public CredentialDataResponse.CredentialDataResponseBuilder datum(CredentialData datum) { - initData(); - this.data.add(datum); - return this; - } - - public CredentialDataResponse.CredentialDataResponseBuilder data(Collection data) { - initData(); - this.data.addAll(data); - return this; - } - - private void initData() { - if (this.data == null) { - this.data = new ArrayList(); - } - } - - public CredentialDataResponse build() { - List data; - switch (this.data == null ? 0 : this.data.size()) { - case 0: - data = java.util.Collections.emptyList(); - break; - case 1: - data = java.util.Collections.singletonList(this.data.get(0)); - break; - default: - data = java.util.Collections.unmodifiableList(new ArrayList(this.data)); - } - - return new CredentialDataResponse(errorMessage, data); - } - - @Override - public String toString() { - return "CredentialDataResponseBuilder{" + - "errorMessage=" + errorMessage + "," + - "data=" + data + - '}'; - } - } -} 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 new file mode 100644 index 0000000..35db185 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetails.java @@ -0,0 +1,234 @@ +/* + * 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 java.util.Date; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import org.springframework.util.Assert; + +/** + * 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. + * + * @author Scott Frederick + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) +public class CredentialDetails extends CredentialSummary { + private String id; + @JsonProperty("type") + private ValueType valueType; + private Object value; + + /** + * Create a {@link CredentialDetails}. + */ + public CredentialDetails() { + } + + /** + * Create a {@link CredentialDetails} from the provided parameters. Intended for + * internal use. Clients will get {@link CredentialDetails} 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 valueType the {@link ValueType} of the credential + * @param value the client-provided value for the credential + * @param versionCreatedAt the {@link Date} when this version of the credential was + * created + */ + CredentialDetails(String id, CredentialName name, ValueType valueType, + Object value, Date versionCreatedAt) { + super(name, versionCreatedAt); + this.id = id; + this.valueType = valueType; + this.value = value; + } + + /** + * Get the the CredHub-generated unique ID of the credential. + * + * @return the credential ID + */ + public String getId() { + return this.id; + } + + /** + * Get the client-provided {@link ValueType} of the credential. + * + * @return the credential type + */ + public ValueType getValueType() { + return this.valueType; + } + + /** + * Get the client-provided value for the credential. + * + * @return the credential value + */ + public Object getValue() { + return this.value; + } + + /** + * Create a builder for a {@link CredentialDetails} object. Intended for internal + * use in tests. Clients will get {@link CredentialDetails} objects populated from + * CredHub responses. + * + * @return the builder + */ + public static CredentialDetailsBuilder detailsBuilder() { + return new CredentialDetailsBuilder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CredentialDetails)) + return false; + + CredentialDetails that = (CredentialDetails) o; + + if (id != null ? !id.equals(that.id) : that.id != null) + return false; + if (valueType != that.valueType) + return false; + if (value != null ? !value.equals(that.value) : that.value != null) + return false; + return true; + } + + @Override + public int hashCode() { + int result = id != null ? id.hashCode() : 0; + result = 31 * result + (name != null ? name.hashCode() : 0); + result = 31 * result + (valueType != null ? valueType.hashCode() : 0); + result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + + (versionCreatedAt != null ? versionCreatedAt.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CredentialDetails{" + + "id='" + id + '\'' + + ", name=" + name + + ", valueType=" + valueType + + ", value=" + value + + ", versionCreatedAt='" + versionCreatedAt + '\'' + + '}'; + } + + /** + * A builder that provides a fluent API for constructing {@link CredentialDetails} + * instances. Intended to be used internally for testing. + */ + public static class CredentialDetailsBuilder { + private String id; + private CredentialName name; + private ValueType valueType; + private Object value; + private Date versionCreatedAt; + + CredentialDetailsBuilder() { + } + + /** + * Set the ID of the credential. + * + * @param id the ID; must not be {@literal null} + * @return the builder + */ + public CredentialDetailsBuilder id(String id) { + Assert.notNull(id, "id must not be null"); + this.id = id; + return this; + } + + /** + * Set the name of the credential. + * + * @param name the name; must not be {@literal null} + * @return the builder + */ + public CredentialDetailsBuilder name(CredentialName name) { + Assert.notNull(name, "name must not be null"); + this.name = name; + return this; + } + + /** + * Set a password value and {@link ValueType#PASSWORD} type for the credential. + * + * @param value the password value; must not be {@literal null} + * @return the builder + */ + public CredentialDetailsBuilder passwordValue(String value) { + Assert.notNull(value, "value must not be null"); + this.valueType = ValueType.PASSWORD; + this.value = value; + return this; + } + + /** + * Set a JSON value and {@link ValueType#JSON} type for the credential. + * + * @param value the JSON value; must not be {@literal null} + * @return the builder + */ + public CredentialDetailsBuilder jsonValue(Map value) { + Assert.notNull(value, "value must not be null"); + this.valueType = ValueType.JSON; + this.value = value; + return this; + } + + /** + * Set a creation date for the credential. + * + * @param versionCreatedAt the creation date; must not be {@literal null} + * @return the builder + */ + public CredentialDetailsBuilder versionCreatedAt(Date versionCreatedAt) { + Assert.notNull(versionCreatedAt, "versionCreatedAt must not be null"); + this.versionCreatedAt = versionCreatedAt; + return this; + } + + /** + * Construct a {@link CredentialDetails} from the provided values. + * + * @return a {@link CredentialDetails} + */ + public CredentialDetails build() { + return new CredentialDetails(id, name, valueType, value, versionCreatedAt); + } + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetailsData.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetailsData.java new file mode 100644 index 0000000..c4630af --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialDetailsData.java @@ -0,0 +1,177 @@ +/* + * + * * Copyright 2013-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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import org.springframework.util.Assert; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; + +/** + * A collection of {@link CredentialDetails}. Clients don't typically instantiate + * objects of this type, but will receive them in response to write and retrieve + * requests. + * + * @author Scott Frederick + */ +@JsonInclude(NON_EMPTY) +@JsonIgnoreProperties(ignoreUnknown = true) +public class CredentialDetailsData { + private List data; + + /** + * Create a {@link CredentialDetailsData}. + */ + public CredentialDetailsData() { + } + + /** + * Create a {@link CredentialDetailsData} from the provided parameters. Intended for internal + * use. Clients will get {@link CredentialDetailsData} objects populated from + * CredHub responses. + * + * @param data a collection of {@link CredentialDetails} + */ + CredentialDetailsData(List data) { + this.data = data; + } + + /** + * Get the collection of {@link CredentialDetails}. + * + * @return the collection of {@link CredentialDetails} + */ + public List getData() { + return this.data; + } + + /** + * Create a builder for a {@link CredentialDetailsData} object. Intended for internal + * use. Clients will get {@link CredentialDetailsData} objects populated from + * CredHub responses. + * + * @return the builder + */ + public static CredentialDetailsDataBuilder builder() { + return new CredentialDetailsDataBuilder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CredentialDetailsData)) + return false; + if (!super.equals(o)) + return false; + + CredentialDetailsData that = (CredentialDetailsData) o; + + return data != null ? data.equals(that.data) : that.data == null; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (data != null ? data.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CredentialDetailResponse{" + + "data=" + data + + '}'; + } + + /** + * A builder that provides a fluent API for constructing {@link CredentialDetailsData} + * instances. Intended to be used internally for testing. + */ + public static class CredentialDetailsDataBuilder { + private List data; + + /** + * Create a {@link CredentialDetailsDataBuilder}. + */ + CredentialDetailsDataBuilder() { + } + + /** + * Add a {@link CredentialDetails} to the collection of details. + * + * @param datum a {@link CredentialDetails} to add; must not be + * {@literal null} + * @return the builder + */ + public CredentialDetailsDataBuilder datum(CredentialDetails datum) { + Assert.notNull(datum, "datum must not be null"); + initData(); + this.data.add(datum); + return this; + } + + /** + * Add a collection of {@link CredentialDetails} to the collection of details. + * + * @param data a collection of {@link CredentialDetails} to add; + * must not be {@literal null} + * @return the builder + */ + public CredentialDetailsDataBuilder data(Collection data) { + Assert.notNull(data, "data must not be null"); + initData(); + this.data.addAll(data); + return this; + } + + private void initData() { + if (this.data == null) { + this.data = new ArrayList(); + } + } + + /** + * Construct a {@link CredentialDetailsData} from the provided values. + * + * @return a {@link CredentialDetailsData} + */ + public CredentialDetailsData build() { + List data; + switch (this.data == null ? 0 : this.data.size()) { + case 0: + data = java.util.Collections.emptyList(); + break; + case 1: + data = java.util.Collections.singletonList(this.data.get(0)); + break; + default: + data = java.util.Collections + .unmodifiableList(new ArrayList(this.data)); + } + + return new CredentialDetailsData(data); + } + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialName.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialName.java index 2dabaa0..537028e 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialName.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialName.java @@ -16,30 +16,75 @@ package org.springframework.credhub.support; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.Data; -import org.springframework.util.StringUtils; - import java.util.Arrays; -@Data +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * The client-provided name of a credential stored in CredHub. Credential names are + * constructed of segments separated by the "/" character, like Unix paths. + * + * @author Scott Frederick + */ public class CredentialName { @JsonIgnore - private final String[] segments; + protected final String[] segments; + /** + * Create a name from the provided value. The name must consist of segments + * separated by the "/" character. + * + * @param name the credential name; must not be {@literal null} + */ CredentialName(String name) { + Assert.notNull("name", "name must not be null"); + String[] split = name.split("/"); + + Assert.isTrue(split.length > 2, "name must include at least one segment separated by '/'"); + // remove the "/c/" prefix this.segments = Arrays.copyOfRange(split, 2, split.length); } + /** + * Create a name from the provided segments. + * + * @param segments the list of name segments; must not be {@literal null} + */ CredentialName(String... segments) { + Assert.notNull(segments, "segments must not be null"); this.segments = segments; } + /** + * Builds a name from the provided segments. + * + * @return the credential name + */ @JsonInclude public String getName() { return "/c/" + StringUtils.arrayToDelimitedString(segments, "/"); } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CredentialName)) + return false; + + CredentialName that = (CredentialName) o; + + return Arrays.equals(segments, that.segments); + } + + @Override + public int hashCode() { + return Arrays.hashCode(segments); + } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummary.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummary.java new file mode 100644 index 0000000..f8ef5f3 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummary.java @@ -0,0 +1,163 @@ +/* + * 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 java.util.Date; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import org.springframework.util.Assert; + +/** + * A summary 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 name} field can be used in subsequent requests. + * + * @author Scott Frederick + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) +public class CredentialSummary { + protected CredentialName name; + protected Date versionCreatedAt; + + /** + * Create a {@link CredentialSummary}. Intended for internal use. + */ + CredentialSummary() { + } + + /** + * Create a {@link CredentialSummary} from the provided parameters. Intended for + * internal use. Clients will get {@link CredentialSummary} objects populated from + * CredHub responses. + * + * @param name the name of the credential + * @param versionCreatedAt the {@link Date} when this version of the credential was + * created + */ + CredentialSummary(CredentialName name, Date versionCreatedAt) { + this.name = name; + this.versionCreatedAt = versionCreatedAt; + } + + /** + * Get the client-provided name of the credential. + * + * @return the credential name + */ + public CredentialName getName() { + return this.name; + } + + /** + * Get the CredHub-generated {@link Date} when this version of the credential was created. + * + * @return the credential version creation {@link Date} + */ + public Date getVersionCreatedAt() { + return this.versionCreatedAt; + } + + /** + * Create a builder for a {@link CredentialSummary} object. Intended for internal + * use in tests. Clients will get {@link CredentialSummary} objects populated from + * CredHub responses. + * + * @return the builder + */ + public static CredentialSummaryBuilder summaryBuilder() { + return new CredentialSummaryBuilder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CredentialSummary)) + return false; + + CredentialSummary that = (CredentialSummary) o; + + if (name != null ? !name.equals(that.name) : that.name != null) + return false; + return versionCreatedAt != null ? versionCreatedAt.equals(that.versionCreatedAt) + : that.versionCreatedAt == null; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + + (versionCreatedAt != null ? versionCreatedAt.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CredentialSummary{" + + "name=" + name + + ", versionCreatedAt='" + versionCreatedAt + '\'' + + '}'; + } + + /** + * A builder that provides a fluent API for constructing {@link CredentialSummary} + * instances. Intended to be used internally for testing. + */ + public static class CredentialSummaryBuilder { + protected CredentialName name; + protected Date versionCreatedAt; + + CredentialSummaryBuilder() { + } + + /** + * Set the name of the credential. + * + * @param name the name; must not be {@literal null} + * @return the builder + */ + public CredentialSummaryBuilder name(CredentialName name) { + Assert.notNull(name, "name must not be null"); + this.name = name; + return this; + } + + /** + * Set a creation date for the credential. + * + * @param versionCreatedAt the creation date; must not be {@literal null} + * @return the builder + */ + public CredentialSummaryBuilder versionCreatedAt(Date versionCreatedAt) { + Assert.notNull(versionCreatedAt, "versionCreatedAt must not be null"); + this.versionCreatedAt = versionCreatedAt; + return this; + } + + /** + * Construct a {@link CredentialSummary} from the provided values. + * + * @return a {@link CredentialSummary} + */ + public CredentialSummary build() { + return new CredentialSummary(name, versionCreatedAt); + } + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummaryData.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummaryData.java new file mode 100644 index 0000000..43ce305 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/CredentialSummaryData.java @@ -0,0 +1,179 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import org.springframework.util.Assert; + +/** + * A collection of {@link CredentialSummary}s. Clients don't typically instantiate + * objects of this type, but will receive them in response to write and retrieve + * requests. + * + * @author Scott Frederick + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) +public class CredentialSummaryData { + private List credentials; + + /** + * Create a {@link CredentialSummaryData}. + */ + CredentialSummaryData() { + } + + /** + * Create a {@link CredentialSummaryData} from the provided parameters. Intended for internal + * use. Clients will get {@link CredentialSummaryData} objects populated from + * CredHub responses. + * + * @param credentials a collection of {@link CredentialSummary}s + */ + CredentialSummaryData(List credentials) { + this.credentials = credentials; + } + + /** + * Get the collection of {@link CredentialSummary}s. + * + * @return the collection of {@link CredentialSummary}s + */ + public List getCredentials() { + return this.credentials; + } + + /** + * Create a builder for a {@link CredentialSummaryData} object. Intended for internal + * use. Clients will get {@link CredentialSummaryData} objects populated from + * CredHub responses. + * + * @return the builder + */ + public static CredentialSummaryDataBuilder builder() { + return new CredentialSummaryDataBuilder(); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CredentialSummaryData)) + return false; + if (!super.equals(o)) + return false; + + CredentialSummaryData that = (CredentialSummaryData) o; + + return credentials != null ? credentials.equals(that.credentials) + : that.credentials == null; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (credentials != null ? credentials.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "CredentialSummaryResponse{" + + "credentials=" + credentials + + '}'; + } + + /** + * Create a builder for a {@link CredentialSummaryData} object. Intended for internal + * use. Clients will get {@link CredentialSummaryData} objects populated from + * CredHub responses. + * + * @return the builder + */ + public static class CredentialSummaryDataBuilder { + private List credentialSummaries; + + CredentialSummaryDataBuilder() { + } + + /** + * Add a {@link CredentialSummary} to the collection of summaries. + * + * @param credential the {@link CredentialSummary} to add; must not be + * {@literal null} + * @return the builder + */ + public CredentialSummaryDataBuilder credential(CredentialSummary credential) { + Assert.notNull(credential, "credential must not be null"); + initCredentials(); + this.credentialSummaries.add(credential); + return this; + } + + /** + * Add a collection of {@link CredentialSummary}s to the collection of summaries. + * + * @param credentials the {@link CredentialSummary}s to add; must not be + * {@literal null} + * @return the builder + */ + public CredentialSummaryDataBuilder credentials( + Collection credentials) { + Assert.notNull(credentials, "credentials must not be null"); + initCredentials(); + this.credentialSummaries.addAll(credentials); + return this; + } + + private void initCredentials() { + if (this.credentialSummaries == null) { + this.credentialSummaries = new ArrayList(); + } + } + + /** + * Construct a {@link CredentialSummaryData} from the provided values. + * + * @return a {@link CredentialSummaryData} + */ + public CredentialSummaryData build() { + List credentialSummaries; + switch (this.credentialSummaries == null ? 0 + : this.credentialSummaries.size()) { + case 0: + credentialSummaries = java.util.Collections.emptyList(); + break; + case 1: + credentialSummaries = java.util.Collections + .singletonList(this.credentialSummaries.get(0)); + break; + default: + credentialSummaries = java.util.Collections.unmodifiableList( + new ArrayList(this.credentialSummaries)); + } + + return new CredentialSummaryData(credentialSummaries); + } + } + +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/FindResponse.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/FindResponse.java deleted file mode 100644 index 34a34cf..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/FindResponse.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) -public class FindResponse extends CredHubResponse { - private List foundCredentials; - - FindResponse(List foundCredentials) { - this.foundCredentials = foundCredentials; - } - - public FindResponse(String errorMessage, List foundCredentials) { - super(errorMessage); - this.foundCredentials = foundCredentials; - } - - public static FindResponseBuilder builder() { - return new FindResponseBuilder(); - } - - public List getFoundCredentials() { - return this.foundCredentials; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof FindResponse)) return false; - if (!super.equals(o)) return false; - - FindResponse that = (FindResponse) o; - - return foundCredentials != null ? foundCredentials.equals(that.foundCredentials) : that.foundCredentials == null; - } - - @Override - public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (foundCredentials != null ? foundCredentials.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "FindResponse{" + - "errorMessage='" + errorMessage + '\'' + - ", foundCredentials=" + foundCredentials + - '}'; - } - - public static class FindResponseBuilder { - private String errorMessage; - private ArrayList foundCredentials; - - FindResponseBuilder() { - } - - public FindResponse.FindResponseBuilder foundCredential(FoundCredential foundCredential) { - initFoundCredentials(); - this.foundCredentials.add(foundCredential); - return this; - } - - public FindResponse.FindResponseBuilder foundCredentials(Collection foundCredentials) { - initFoundCredentials(); - this.foundCredentials.addAll(foundCredentials); - return this; - } - - private void initFoundCredentials() { - if (this.foundCredentials == null) { - this.foundCredentials = new ArrayList(); - } - } - - public FindResponse build() { - List foundCredentials; - switch (this.foundCredentials == null ? 0 : this.foundCredentials.size()) { - case 0: - foundCredentials = java.util.Collections.emptyList(); - break; - case 1: - foundCredentials = java.util.Collections.singletonList(this.foundCredentials.get(0)); - break; - default: - foundCredentials = java.util.Collections.unmodifiableList(new ArrayList(this.foundCredentials)); - } - - return new FindResponse(errorMessage, foundCredentials); - } - - @Override - public String toString() { - return "FindResponseBuilder{" + - "foundCredentials=" + foundCredentials + - '}'; - } - - public FindResponseBuilder errorMessage(String errorMessage) { - this.errorMessage = errorMessage; - return this; - } - } - - public static class FoundCredential { - private CredentialName name; - private String versionCreatedAt; - - FoundCredential(CredentialName name, String versionCreatedAt) { - this.name = name; - this.versionCreatedAt = versionCreatedAt; - } - - public static FoundCredentialBuilder builder() { - return new FoundCredentialBuilder(); - } - - public CredentialName getName() { - return this.name; - } - - public String getVersionCreatedAt() { - return this.versionCreatedAt; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof FoundCredential)) return false; - - FoundCredential that = (FoundCredential) o; - - if (name != null ? !name.equals(that.name) : that.name != null) return false; - return versionCreatedAt != null ? versionCreatedAt.equals(that.versionCreatedAt) : that.versionCreatedAt == null; - } - - @Override - public int hashCode() { - int result = name != null ? name.hashCode() : 0; - result = 31 * result + (versionCreatedAt != null ? versionCreatedAt.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "FoundCredential{" + - "name=" + name + - ", versionCreatedAt='" + versionCreatedAt + '\'' + - '}'; - } - - public static class FoundCredentialBuilder { - private CredentialName name; - private String versionCreatedAt; - - FoundCredentialBuilder() { - } - - public FoundCredential.FoundCredentialBuilder name(CredentialName name) { - this.name = name; - return this; - } - - public FoundCredential.FoundCredentialBuilder versionCreatedAt(String versionCreatedAt) { - this.versionCreatedAt = versionCreatedAt; - return this; - } - - public FoundCredential build() { - return new FoundCredential(name, versionCreatedAt); - } - - @Override - public String toString() { - return "FoundCredentialBuilder{" + - "name=" + name + - ", versionCreatedAt='" + versionCreatedAt + '\'' + - '}'; - } - } - } -} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ReadRequest.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ReadRequest.java deleted file mode 100644 index fe75821..0000000 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ReadRequest.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * - * * Copyright 2013-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 lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.ToString; - -@ToString(callSuper = true) -@EqualsAndHashCode(callSuper = true) -public class ReadRequest extends CredHubRequest { - @Builder - public ReadRequest(CredentialName name) { - super(name); - } -} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ServiceInstanceCredentialName.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ServiceInstanceCredentialName.java index 3682297..c848d21 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/ServiceInstanceCredentialName.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/ServiceInstanceCredentialName.java @@ -16,18 +16,132 @@ package org.springframework.credhub.support; -import lombok.Builder; -import lombok.Data; +import org.springframework.util.Assert; -@Data +import java.util.Arrays; + +/** + * The client-provided name of a credential that stores service instance binding + * credentials. Service instance binding credential names consist of four segments: + * service broker name, service offering name, service binding GUID, and credential + * name. When these values are combined the full name of the credential will be of + * the form + * {@literal /c/service-broker-name/service-offering-name/binding-GUID/credential-name}. + * + * Objects of this type are created by clients and included as part of requests. + * + * @author Scott Frederick + */ public class ServiceInstanceCredentialName extends CredentialName { - @Builder - public ServiceInstanceCredentialName(String serviceBrokerName, String serviceOfferingName, String serviceBindingId, String credentialName) { + /** + * Create a {@link ServiceInstanceCredentialName} from the required name fields. + * Intended for internal use in tests. Clients should use + * {@link #builder()} to construct instances of this class. + * + * @param serviceBrokerName the human-readable name of the service broker + * @param serviceOfferingName the human-readable name of the service offering + * @param serviceBindingId the GUID of the service binding + * @param credentialName the name of the binding credential + */ + ServiceInstanceCredentialName(String serviceBrokerName, String serviceOfferingName, + String serviceBindingId, String credentialName) { super(serviceBrokerName, serviceOfferingName, serviceBindingId, credentialName); } + /** + * Create a builder that provides a fluent API for providing the values required + * to construct a {@link ServiceInstanceCredentialName}. + * + * @return the builder + */ + public static ServiceInstanceCredentialNameBuilder builder() { + return new ServiceInstanceCredentialNameBuilder(); + } + @Override - public String getName() { - return null; + public String toString() { + return "ServiceInstanceCredentialName{" + + "segments=" + Arrays.toString(segments) + + "}"; + } + + /** + * A builder that provides a fluent API for constructing + * {@link ServiceInstanceCredentialName} instances. + */ + public static class ServiceInstanceCredentialNameBuilder { + private String serviceBrokerName; + private String serviceOfferingName; + private String serviceBindingId; + private String credentialName; + + /** + * Create a {@link ServiceInstanceCredentialNameBuilder} + */ + ServiceInstanceCredentialNameBuilder() { + } + + /** + * Set the service broker name segment of the credential name. This is typically + * a human-readable name and should be unique among all service brokers in + * Cloud Foundry. + * + * @param serviceBrokerName the service broker name; must not be {@literal null} + * @return the builder + */ + public ServiceInstanceCredentialNameBuilder serviceBrokerName(String serviceBrokerName) { + Assert.notNull(serviceBrokerName, "serviceBrokerName must not be null"); + this.serviceBrokerName = serviceBrokerName; + return this; + } + + /** + * Set the service offering name segment of the credential name. This is typically + * a human-readable name and should be unique within the service broker. + * + * @param serviceOfferingName the service offering name; must not be {@literal null} + * @return the builder + */ + public ServiceInstanceCredentialNameBuilder serviceOfferingName(String serviceOfferingName) { + Assert.notNull(serviceOfferingName, "serviceOfferingName must not be null"); + this.serviceOfferingName = serviceOfferingName; + return this; + } + + /** + * Set the service binding ID segment of the credential name. This value is + * generated by Cloud Foundry when a service instance is bound to an application + * and is in the form of a GUID. + * + * @param serviceBindingId the service binding ID; must not be {@literal null} + * @return the builder + */ + public ServiceInstanceCredentialNameBuilder serviceBindingId(String serviceBindingId) { + Assert.notNull(serviceBindingId, "serviceBindingId must not be null"); + this.serviceBindingId = serviceBindingId; + return this; + } + + /** + * Set the credential name segment of the full credential name. + * + * @param credentialName the credential name; must not be {@literal null} + * @return the builder + */ + public ServiceInstanceCredentialNameBuilder credentialName(String credentialName) { + Assert.notNull(credentialName, "credentialName must not be null"); + this.credentialName = credentialName; + return this; + } + + /** + * Create a {@link ServiceInstanceCredentialName} from the provided values. + * + * @return a {@link ServiceInstanceCredentialName} + */ + public ServiceInstanceCredentialName build() { + return new ServiceInstanceCredentialName(serviceBrokerName, + serviceOfferingName, serviceBindingId, credentialName); + } } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SimpleCredentialName.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SimpleCredentialName.java index 0f25de0..fa94b3c 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SimpleCredentialName.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SimpleCredentialName.java @@ -16,22 +16,37 @@ package org.springframework.credhub.support; -import lombok.Builder; -import lombok.Data; -import lombok.EqualsAndHashCode; +import org.springframework.util.Assert; -@Data -@EqualsAndHashCode(callSuper = true) +import java.util.Arrays; + +/** + * The client-provided name of a credential. The name consists of one or more segments. + * When the value of each segment are combined the full name of the credential will be of + * the form + * {@literal /c/segment1/segment2/segment3}. + * + * Objects of this type are created by clients and included as part of requests. + * + * @author Scott Frederick + */ public class SimpleCredentialName extends CredentialName { - @Builder + /** + * Create a {@link SimpleCredentialName} from the provided segments. + * + * @param segments the credential name segments; must not be {@literal null} and must + * contain at least one segment + */ public SimpleCredentialName(String... segments) { super(segments); + Assert.notNull(segments, "segments must not be null"); + Assert.isTrue(segments.length > 0, "at least one segment must be provided"); } - public static class SimpleCredentialNameBuilder { - public SimpleCredentialNameBuilder segments(String... segments) { - this.segments = segments; - return this; - } + @Override + public String toString() { + return "SimpleCredentialName{" + + "segments=" + Arrays.toString(segments) + + "}"; } } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SslConfiguration.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SslConfiguration.java index 0fdb857..3a02a6a 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/SslConfiguration.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/SslConfiguration.java @@ -16,17 +16,20 @@ package org.springframework.credhub.support; +import java.io.FileReader; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; + import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import java.io.FileReader; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.Certificate; - +/** + * Client configuration for SSL connectivity. + */ public class SslConfiguration { private static final char[] KEY_PASSWORD = "keystore".toCharArray(); private static final String CERTIFICATE_NAME = "credhub-cert"; @@ -35,17 +38,39 @@ public class SslConfiguration { private KeyStore trustStore; private KeyStore keyStore; + /** + * Create an empty {@link SslConfiguration}. Intended for internal use. + */ public SslConfiguration() { } - public static SslConfiguration forContainerCert(String instanceCertLocation, String instanceKeyLocation) { + /** + * Create an {@link SslConfiguration} that uses a certificate and private key that + * have been placed in a Cloud Foundry application container for use with mutual SSL + * authentication to CredHub. + * + * @param instanceCertLocation the absolute path of the certificate file in the app + * instance container + * @param instanceKeyLocation the absolute path of the private key file in the app + * instance container + * @return the {@link SslConfiguration} configured to use the container certificate + * and private key + */ + public static SslConfiguration forContainerCert(String instanceCertLocation, + String instanceKeyLocation) { SslConfiguration sslConfiguration = new SslConfiguration(); - KeyStore keyStore = sslConfiguration.buildKeyStore(instanceCertLocation, instanceKeyLocation); + KeyStore keyStore = sslConfiguration.buildKeyStore(instanceCertLocation, + instanceKeyLocation); sslConfiguration.setKeyStore(keyStore); sslConfiguration.setTrustStore(keyStore); return sslConfiguration; } + /** + * Get the {@link KeyStore key store} resource used to configure the SSL context. + * + * @return the key store + */ public KeyStore getKeyStore() { return keyStore; } @@ -54,6 +79,11 @@ public class SslConfiguration { this.keyStore = keyStore; } + /** + * Get the {@link KeyStore trust store} resource used to configure the SSL context. + * + * @return the trust store + */ public KeyStore getTrustStore() { return trustStore; } @@ -62,46 +92,91 @@ public class SslConfiguration { this.trustStore = keyStore; } + /** + * Get the password used to secure the generated key store. + * + * @return they key store password + */ public char[] getKeyPassword() { return KEY_PASSWORD; } - private KeyStore buildKeyStore(String instanceCertLocation, String instanceKeyLocation) { + /** + * Build a {@link KeyStore} using the container certificate and private key. + * + * @param instanceCertLocation the absolute path of the certificate file in the app + * instance container + * @param instanceKeyLocation the absolute path of the private key file in the app + * instance container + * @return the created key store + */ + private KeyStore buildKeyStore(String instanceCertLocation, + String instanceKeyLocation) { Certificate cert = parseCertificate(instanceCertLocation); PrivateKey key = parsePrivateKey(instanceKeyLocation); return createKeyStore(cert, key); } + /** + * Parse a PEM-formatted certificate and convert to a {@link Certificate}. + * + * @param certificateLocation the absolute path of the certificate file in the app + * instance container + * @return the created {@link Certificate} + */ private Certificate parseCertificate(String certificateLocation) { try { PEMParser parser = new PEMParser(new FileReader(certificateLocation)); - X509CertificateHolder certHolder = (X509CertificateHolder) parser.readObject(); + X509CertificateHolder certHolder = + (X509CertificateHolder) parser.readObject(); JcaX509CertificateConverter converter = new JcaX509CertificateConverter(); return converter.getCertificate(certHolder); - } catch (Exception e) { - throw new IllegalArgumentException("Error parsing and loading certificate from location " + certificateLocation, e); + } + catch (Exception e) { + throw new IllegalArgumentException( + "Error parsing and loading certificate from location " + + certificateLocation, + e); } } + /** + * Parse a PEM-formatted key and convert to a {@link PrivateKey}. + * + * @param keyLocation the absolute path of the key file in the app + * instance container + * @return the created {@link PrivateKey} + */ private PrivateKey parsePrivateKey(String keyLocation) { try { PEMParser reader = new PEMParser(new FileReader(keyLocation)); PEMKeyPair key = (PEMKeyPair) reader.readObject(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter(); return converter.getKeyPair(key).getPrivate(); - } catch (Exception e) { - throw new IllegalArgumentException("Error parsing and loading private key from location " + keyLocation, e); + } + catch (Exception e) { + throw new IllegalArgumentException( + "Error parsing and loading private key from location " + keyLocation, + e); } } + /** + * Create a {@link KeyStore} from the provided certificate and private key. + * + * @param cert the certifcate to add to the key store + * @param key the private key to add to the key store + * @return the created {@link KeyStore} + */ private KeyStore createKeyStore(Certificate cert, PrivateKey key) { try { KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(null); keystore.setCertificateEntry(CERTIFICATE_NAME, cert); - keystore.setKeyEntry(KEY_NAME, key, KEY_PASSWORD, new Certificate[]{cert}); + keystore.setKeyEntry(KEY_NAME, key, KEY_PASSWORD, new Certificate[] { cert }); return keystore; - } catch (Exception e) { + } + catch (Exception e) { throw new IllegalArgumentException("Error creating keystore ", e); } } 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 85a6abf..7495354 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 @@ -20,8 +20,20 @@ package org.springframework.credhub.support; import com.fasterxml.jackson.annotation.JsonCreator; +/** + * The types of credentials that can be written to CredHub. + */ public enum ValueType { + /** + * A password credential consists of a single string value. The password value + * is provided by the client (i.e. not generated by CredHub). + */ PASSWORD("password"), + + /** + * 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. + */ JSON("json"); private final String type; @@ -30,10 +42,21 @@ public enum ValueType { this.type = type; } + /** + * Get the type value that will be used in requests to CredHub. + * + * @return the type value + */ public String type() { return type; } + /** + * Convert a {@literal String} type to its enum value. + * + * @param type the {@literal String} type to convert + * @return the enum value + */ @JsonCreator public static ValueType getTypeByString(String type) { for (ValueType e : ValueType.values()) { diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/support/WriteRequest.java b/spring-credhub-core/src/main/java/org/springframework/credhub/support/WriteRequest.java index d82cc1b..3370a5f 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/support/WriteRequest.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/support/WriteRequest.java @@ -18,94 +18,157 @@ package org.springframework.credhub.support; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Singular; - import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import org.springframework.util.Assert; + import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; import static org.springframework.credhub.support.ValueType.JSON; +/** + * The details of a request to write a new or update an existing credential in CredHub. + * + * @author Scott Frederick + */ @JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class) -public class WriteRequest extends CredHubRequest { +public class WriteRequest { private boolean overwrite; - + private CredentialName name; private ValueType valueType; - private Object value; - @JsonInclude(NON_EMPTY) private List accessControlEntries; - private WriteRequest(CredentialName name, boolean overwrite, Object value, ValueType valueType, - @Singular List accessControlEntries) { - super(name); + /** + * Create a {@link WriteRequest} from the provided parameters. Intended for internal + * use. Clients should use {@link #builder()} to construct instances of this class. + * + * @param name the name of the credential + * @param overwrite {@literal false} to create a new credential, or + * {@literal true} to update and existing credential + * @param value the value of the credential + * @param valueType the {@link ValueType} of the credential + * @param accessControlEntries requirements for access control for the credential + */ + private WriteRequest(CredentialName name, boolean overwrite, + Object value, ValueType valueType, + List accessControlEntries) { + this.name = name; this.overwrite = overwrite; this.valueType = valueType; this.value = value; this.accessControlEntries = accessControlEntries; } + /** + * Get the value of the {@literal boolean} flag indicating whether the CredHub + * should create a new credential or update an existing credential. + * + * @return the {@literal boolean} overwrite value + */ + public boolean isOverwrite() { + return this.overwrite; + } + + + /** + * Get the {@link CredentialName} of the credential. + * + * @return the name of the credential + */ + @JsonInclude + public String getName() { + return name.getName(); + } + + /** + * Get the value of the credential. + * + * @return the value of the credential + */ + public Object getValue() { + return this.value; + } + + /** + * Get the {@link ValueType} of the credential. + * + * @return the type of the credential + */ + public String getType() { + return valueType.type(); + } + + /** + * Get the set of {@link AccessControlEntry} to assign to the credential. + * + * @return the set of {@link AccessControlEntry} + */ + public List getAccessControlEntries() { + return this.accessControlEntries; + } + + /** + * Create a builder that provides a fluent API for providing the values required + * to construct a {@link WriteRequest}. + * + * @return a builder + */ public static WriteRequestBuilder builder() { return new WriteRequestBuilder(); } @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof WriteRequest)) return false; - if (!super.equals(o)) return false; + if (this == o) + return true; + if (!(o instanceof WriteRequest)) + return false; WriteRequest that = (WriteRequest) o; - if (overwrite != that.overwrite) return false; - if (valueType != that.valueType) return false; - if (value != null ? !value.equals(that.value) : that.value != null) return false; - return accessControlEntries != null ? accessControlEntries.equals(that.accessControlEntries) : that.accessControlEntries == null; + if (overwrite != that.overwrite) + return false; + if (!name.equals(that.name)) + return false; + if (valueType != that.valueType) + return false; + if (!value.equals(that.value)) + return false; + return accessControlEntries.equals(that.accessControlEntries); } @Override public int hashCode() { - int result = super.hashCode(); - result = 31 * result + (overwrite ? 1 : 0); - result = 31 * result + (valueType != null ? valueType.hashCode() : 0); - result = 31 * result + (value != null ? value.hashCode() : 0); - result = 31 * result + (accessControlEntries != null ? accessControlEntries.hashCode() : 0); + int result = (overwrite ? 1 : 0); + result = 31 * result + name.hashCode(); + result = 31 * result + valueType.hashCode(); + result = 31 * result + value.hashCode(); + result = 31 * result + accessControlEntries.hashCode(); return result; } @Override public String toString() { - return "WriteRequest{" + - "overwrite=" + overwrite + - ", valueType=" + valueType + - ", value=" + value + - ", accessControlEntries=" + accessControlEntries + - '}'; - } - - public boolean isOverwrite() { - return this.overwrite; - } - - public Object getValue() { - return this.value; - } - - public String getType() { - return valueType.type(); - } - - public List getAccessControlEntries() { - return this.accessControlEntries; + return "WriteRequest{" + + "overwrite=" + overwrite + + ", name=" + name + + ", valueType=" + valueType + + ", value=" + value + + ", accessControlEntries=" + accessControlEntries + + '}'; } + /** + * A builder that provides a fluent API for constructing {@link WriteRequest}s. + */ public static class WriteRequestBuilder { private CredentialName name; private boolean overwrite; @@ -113,70 +176,124 @@ public class WriteRequest extends CredHubRequest { private ValueType valueType; private ArrayList accessControlEntries; + /** + * Create a {@link WriteRequestBuilder}. Intended for internal use. + */ WriteRequestBuilder() { } + /** + * Set the value of a password credential. A password credential consists of + * a single string value. The type of the credential is set to {@link ValueType#PASSWORD}. + * + * @param value the password credential value; must not be {@literal null} + * @return the builder + */ public WriteRequestBuilder passwordValue(String value) { + Assert.notNull(value, "value must not be null"); this.valueType = ValueType.PASSWORD; this.value = value; return this; } + /** + * Set the value of a JSON credential. A JSON credential consists of + * one or more fields in a JSON document. The provided {@literal Map} parameter. + * will be converted to a JSON document before sending to CredHub. The type of + * the credential is set to {@link ValueType#JSON}. + * + * @param value the json credential value; must not be {@literal null} + * @return the builder + */ public WriteRequestBuilder jsonValue(Map value) { + Assert.notNull(value, "value must not be null"); this.valueType = JSON; this.value = value; return this; } + /** + * Set the {@link CredentialName} for the credential. + * + * @param name the credential name; must not be {@literal null} + * @return the builder + */ public WriteRequestBuilder name(CredentialName name) { + Assert.notNull(name, "name must not be null"); this.name = name; return this; } + /** + * Sets a {@literal boolean} value indicating whether CredHub should create a new + * credential or update and existing credential. + * + * @param overwrite {@literal false} to create a new credential, or + * {@literal true} to update and existing credential + * @return the builder + */ public WriteRequestBuilder overwrite(boolean overwrite) { this.overwrite = overwrite; return this; } + /** + * Add an {@link AccessControlEntry} to the controls that will be assigned to the + * credential. + * + * @param accessControlEntry an {@link AccessControlEntry} to assign to the + * credential + * @return the builder + */ public WriteRequestBuilder accessControlEntry(AccessControlEntry accessControlEntry) { - if (this.accessControlEntries == null) - this.accessControlEntries = new ArrayList(); + initAccessControls(); this.accessControlEntries.add(accessControlEntry); return this; } + /** + * Add a collection of {@link AccessControlEntry}s to the controls that will be + * assigned to the credential. + * + * @param accessControlEntries an collection of {@link AccessControlEntry}s to + * assign to the credential + * @return the builder + */ public WriteRequestBuilder accessControlEntries(Collection accessControlEntries) { - if (this.accessControlEntries == null) - this.accessControlEntries = new ArrayList(); + initAccessControls(); this.accessControlEntries.addAll(accessControlEntries); return this; } - public WriteRequest build() { - List accessControlEntries; - switch (this.accessControlEntries == null ? 0 : this.accessControlEntries.size()) { - case 0: - accessControlEntries = java.util.Collections.emptyList(); - break; - case 1: - accessControlEntries = java.util.Collections.singletonList(this.accessControlEntries.get(0)); - break; - default: - accessControlEntries = java.util.Collections.unmodifiableList(new ArrayList(this.accessControlEntries)); + private void initAccessControls() { + if (this.accessControlEntries == null) { + this.accessControlEntries = new ArrayList(); } - - return new WriteRequest(name, overwrite, value, valueType, accessControlEntries); } - @Override - public String toString() { - return "WriteRequestBuilder{" + - "name=" + name + - ", overwrite=" + overwrite + - ", value=" + value + - ", valueType=" + valueType + - ", accessControlEntries=" + accessControlEntries + - '}'; + /** + * Create a {@link WriteRequest} from the provided values. + * + * @return a {@link WriteRequest} + */ + public WriteRequest build() { + List accessControlEntries; + switch (this.accessControlEntries == null ? 0 + : this.accessControlEntries.size()) { + case 0: + accessControlEntries = java.util.Collections.emptyList(); + break; + case 1: + accessControlEntries = java.util.Collections + .singletonList(this.accessControlEntries.get(0)); + break; + default: + accessControlEntries = java.util.Collections.unmodifiableList( + new ArrayList(this.accessControlEntries)); + } + + return new WriteRequest(name, overwrite, value, valueType, + accessControlEntries); } } diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactoryTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactoryTests.java index b18e487..9976993 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactoryTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/configuration/ClientHttpRequestFactoryFactoryTests.java @@ -19,6 +19,7 @@ package org.springframework.credhub.configuration; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.CloseableHttpClient; import org.junit.Test; + import org.springframework.beans.factory.DisposableBean; import org.springframework.credhub.support.ClientOptions; import org.springframework.credhub.support.SslConfiguration; @@ -33,12 +34,14 @@ public class ClientHttpRequestFactoryFactoryTests { @Test public void httpComponentsClientCreated() throws Exception { - ClientHttpRequestFactory factory = ClientHttpRequestFactoryFactory.HttpComponents.usingHttpComponents( - new ClientOptions(), new SslConfiguration()); + ClientHttpRequestFactory factory = + ClientHttpRequestFactoryFactory.HttpComponents.usingHttpComponents( + new ClientOptions(), new SslConfiguration()); assertThat(factory, instanceOf(HttpComponentsClientHttpRequestFactory.class)); - HttpClient httpClient = ((HttpComponentsClientHttpRequestFactory) factory).getHttpClient(); + HttpClient httpClient = ((HttpComponentsClientHttpRequestFactory) factory) + .getHttpClient(); assertThat(httpClient, instanceOf(CloseableHttpClient.class)); diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubClientUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubClientUnitTests.java index 675043e..392560d 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubClientUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubClientUnitTests.java @@ -22,18 +22,15 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.http.client.ClientHttpRequestExecution; + import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.AbstractUriTemplateHandler; -import java.net.URI; - import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.junit.Assert.assertThat; - @RunWith(MockitoJUnitRunner.class) public class CredHubClientUnitTests { private static final String CREDHUB_URI = "https://credhub.cf.example.com:8844"; @@ -43,12 +40,14 @@ public class CredHubClientUnitTests { @Test public void restTemplateIsCreated() throws Exception { - RestTemplate restTemplate = - CredHubClient.createRestTemplate(CREDHUB_URI, clientHttpRequestFactory); + RestTemplate restTemplate = CredHubClient.createRestTemplate(CREDHUB_URI, + clientHttpRequestFactory); - assertThat(restTemplate.getUriTemplateHandler(), instanceOf(AbstractUriTemplateHandler.class)); + assertThat(restTemplate.getUriTemplateHandler(), + instanceOf(AbstractUriTemplateHandler.class)); - AbstractUriTemplateHandler uriTemplateHandler = (AbstractUriTemplateHandler) restTemplate.getUriTemplateHandler(); + AbstractUriTemplateHandler uriTemplateHandler = (AbstractUriTemplateHandler) restTemplate + .getUriTemplateHandler(); assertThat(uriTemplateHandler.getBaseUrl(), equalTo(CREDHUB_URI)); } } \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailResponseUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailResponseUnitTests.java new file mode 100644 index 0000000..94c149b --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailResponseUnitTests.java @@ -0,0 +1,118 @@ +/* + * 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 org.junit.experimental.theories.DataPoint; +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.WriteRequest; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.util.Date; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; +import static org.springframework.credhub.core.CredHubTemplate.BASE_URL_PATH; +import static org.springframework.credhub.core.CredHubTemplate.ID_URL_PATH; +import static org.springframework.http.HttpMethod.PUT; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + +@RunWith(Theories.class) +public class CredHubTemplateDetailResponseUnitTests extends CredHubTemplateUnitTestsBase { + private static final String CREDENTIAL_ID = "1111-1111-1111-1111"; + private static final String CREDENTIAL_VALUE = "secret"; + + @DataPoint("responses") + public static ResponseEntity successfulResponse = + new ResponseEntity(CredentialDetails.detailsBuilder() + .name(NAME) + .id(CREDENTIAL_ID) + .passwordValue(CREDENTIAL_VALUE) + .versionCreatedAt(new Date()) + .build(), + OK); + + @DataPoint("responses") + public static ResponseEntity httpErrorResponse = + new ResponseEntity(CredentialDetails.detailsBuilder().build(), + UNAUTHORIZED); + + @Theory + public void write(@FromDataPoints("responses") ResponseEntity expectedResponse) { + WriteRequest request = WriteRequest.builder() + .name(NAME) + .passwordValue("secret") + .build(); + + when(restTemplate.exchange(BASE_URL_PATH, PUT, + new HttpEntity(request), CredentialDetails.class)) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(HttpStatus.OK)) { + try { + credHubTemplate.write(request); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + CredentialDetails response = credHubTemplate.write(request); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + @Theory + public void getById(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(ID_URL_PATH, CredentialDetails.class, CREDENTIAL_ID)) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(HttpStatus.OK)) { + try { + credHubTemplate.getById(CREDENTIAL_ID); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + CredentialDetails response = credHubTemplate.getById(CREDENTIAL_ID); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + private void assertResponseContainsExpectedCredentials( + ResponseEntity expectedResponse, CredentialDetails response) { + assertThat(response, notNullValue()); + assertThat(response, equalTo(expectedResponse.getBody())); + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailsResponseUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailsResponseUnitTests.java new file mode 100644 index 0000000..f9e7567 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateDetailsResponseUnitTests.java @@ -0,0 +1,114 @@ +/* + * 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.DataPoint; +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.http.ResponseEntity; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; +import static org.springframework.credhub.core.CredHubTemplate.NAME_URL_QUERY; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + +@RunWith(Theories.class) +public class CredHubTemplateDetailsResponseUnitTests extends CredHubTemplateUnitTestsBase { + private static final String CREDENTIAL_ID = "1111-1111-1111-1111"; + private static final String CREDENTIAL_VALUE = "secret"; + + @DataPoint("responses") + public static ResponseEntity successfulResponse = + new ResponseEntity( + CredentialDetailsData.builder() + .datum(CredentialDetails.detailsBuilder() + .name(NAME) + .id(CREDENTIAL_ID) + .passwordValue(CREDENTIAL_VALUE) + .build()) + .build(), + OK); + + @DataPoint("responses") + public static ResponseEntity httpErrorResponse = + new ResponseEntity( + CredentialDetailsData.builder() + .build(), + UNAUTHORIZED); + + @Theory + public void getByNameWithString(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(NAME_URL_QUERY, CredentialDetailsData.class, NAME.getName())) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(OK)) { + try { + credHubTemplate.getByName(NAME.getName()); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + List response = credHubTemplate.getByName(NAME.getName()); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + @Theory + public void getByNameWithCredentialName(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(NAME_URL_QUERY, CredentialDetailsData.class, NAME.getName())) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(OK)) { + try { + credHubTemplate.getByName(NAME); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + List response = credHubTemplate.getByName(NAME); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + private void assertResponseContainsExpectedCredentials( + ResponseEntity expectedResponse, + List response) { + assertThat(response, notNullValue()); + assertThat(response.size(), equalTo(expectedResponse.getBody().getData().size())); + assertThat(response.get(0), equalTo(expectedResponse.getBody().getData().get(0))); + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateSummaryResponseUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateSummaryResponseUnitTests.java new file mode 100644 index 0000000..96f81a5 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateSummaryResponseUnitTests.java @@ -0,0 +1,135 @@ +/* + * 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.Date; +import java.util.List; + +import org.junit.experimental.theories.DataPoint; +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.CredentialSummary; +import org.springframework.credhub.support.CredentialSummaryData; +import org.springframework.http.ResponseEntity; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.when; +import static org.springframework.credhub.core.CredHubTemplate.NAME_LIKE_URL_QUERY; +import static org.springframework.credhub.core.CredHubTemplate.PATH_URL_QUERY; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.UNAUTHORIZED; + +@RunWith(Theories.class) +public class CredHubTemplateSummaryResponseUnitTests extends CredHubTemplateUnitTestsBase { + @DataPoint("responses") + public static ResponseEntity successfulResponse = + new ResponseEntity( + CredentialSummaryData.builder() + .credential(CredentialSummary.summaryBuilder() + .name(NAME) + .versionCreatedAt(new Date()) + .build()) + .build(), + OK); + + @DataPoint("responses") + public static ResponseEntity httpErrorResponse = + new ResponseEntity( + CredentialSummaryData.builder() + .build(), + UNAUTHORIZED); + + @Theory + public void findByNameWithString(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(NAME_LIKE_URL_QUERY, CredentialSummaryData.class, NAME.getName())) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(OK)) { + try { + credHubTemplate.findByName(NAME.getName()); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + List response = credHubTemplate.findByName(NAME.getName()); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + @Theory + public void findByNameWithCredentialName(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(NAME_LIKE_URL_QUERY, CredentialSummaryData.class, NAME.getName())) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(OK)) { + try { + credHubTemplate.findByName(NAME); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + List response = credHubTemplate.findByName(NAME); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + @Theory + public void findByPath(@FromDataPoints("responses") ResponseEntity expectedResponse) { + when(restTemplate.getForEntity(PATH_URL_QUERY, CredentialSummaryData.class, NAME.getName())) + .thenReturn(expectedResponse); + + if (!expectedResponse.getStatusCode().equals(OK)) { + try { + credHubTemplate.findByPath(NAME.getName()); + fail("Exception should have been thrown"); + } + catch (CredHubException e) { + assertThat(e.getMessage(), containsString(expectedResponse.getStatusCode().toString())); + } + } + else { + List response = credHubTemplate.findByPath(NAME.getName()); + + assertResponseContainsExpectedCredentials(expectedResponse, response); + } + } + + private void assertResponseContainsExpectedCredentials( + ResponseEntity expectedResponse, + List response) { + assertThat(response, notNullValue()); + assertThat(response.size(), + equalTo(expectedResponse.getBody().getCredentials().size())); + assertThat(response.get(0), + equalTo(expectedResponse.getBody().getCredentials().get(0))); + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateTests.java deleted file mode 100644 index e358ca2..0000000 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateTests.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * 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 org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.credhub.support.CredentialDataResponse; -import org.springframework.credhub.support.CredentialData; -import org.springframework.credhub.support.FindResponse; -import org.springframework.credhub.support.SimpleCredentialName; -import org.springframework.credhub.support.WriteRequest; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.RestTemplate; - -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.springframework.credhub.core.CredHubTemplate.BASE_URL_PATH; -import static org.springframework.credhub.core.CredHubTemplate.NAME_LIKE_URL_QUERY; -import static org.springframework.credhub.core.CredHubTemplate.NAME_URL_QUERY; -import static org.springframework.credhub.core.CredHubTemplate.PATH_URL_QUERY; -import static org.springframework.credhub.core.CredHubTemplate.ID_URL_PATH; -import static org.springframework.http.HttpMethod.PUT; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; - -@RunWith(MockitoJUnitRunner.class) -public class CredHubTemplateTests { - private static final String CREDENTIAL_ID = "1111-1111-1111-1111"; - private static final String CREDENTIAL_VALUE = "secret"; - - @Mock - private RestTemplate restTemplate; - - private CredHubTemplate credHubTemplate; - - private SimpleCredentialName name; - - private CredentialDataResponse dataResponse; - private CredentialDataResponse dataResponseWithError; - - private FindResponse findResponse; - private FindResponse findResponseWithError; - - @Before - public void setUp() { - credHubTemplate = new CredHubTemplate(restTemplate); - - name = SimpleCredentialName.builder().segments("example", "credential").build(); - - dataResponse = CredentialDataResponse.builder() - .datum(CredentialData.builder() - .name(name) - .id(CREDENTIAL_ID) - .passwordValue(CREDENTIAL_VALUE) - .build()) - .build(); - - dataResponseWithError = CredentialDataResponse.builder() - .errorMessage("errorMessage message") - .build(); - - findResponse = FindResponse.builder() - .foundCredential(FindResponse.FoundCredential.builder() - .name(name) - .versionCreatedAt("") - .build()) - .build(); - - findResponseWithError = FindResponse.builder() - .errorMessage("errorMessage message") - .build(); - } - - @Test - public void writeWithSuccess() { - WriteRequest request = WriteRequest.builder() - .name(name) - .passwordValue("secret") - .build(); - - when(restTemplate.exchange(BASE_URL_PATH, PUT, new HttpEntity(request), CredentialDataResponse.class)) - .thenReturn(new ResponseEntity(dataResponse, OK)); - - CredentialData response = credHubTemplate.write(request); - - assertThat(response, notNullValue()); - assertThat(response, equalTo(dataResponse.getData().get(0))); - } - - @Test - public void writeWithErrorResponse() { - WriteRequest request = WriteRequest.builder() - .name(name) - .passwordValue("secret") - .build(); - - when(restTemplate.exchange(BASE_URL_PATH, PUT, new HttpEntity(request), CredentialDataResponse.class)) - .thenReturn(new ResponseEntity(dataResponseWithError, OK)); - - try { - credHubTemplate.write(request); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": errorMessage message")); - } - } - - @Test - public void writeWithHttpError() { - WriteRequest request = WriteRequest.builder() - .name(name) - .passwordValue("secret") - .build(); - - when(restTemplate.exchange(BASE_URL_PATH, PUT, new HttpEntity(request), CredentialDataResponse.class)) - .thenReturn(new ResponseEntity(dataResponseWithError, HttpStatus.UNAUTHORIZED)); - - try { - credHubTemplate.write(request); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": " + HttpStatus.UNAUTHORIZED.toString())); - } - } - - @Test - public void getByIdWithSuccess() { - when(restTemplate.getForEntity(ID_URL_PATH, CredentialDataResponse.class, CREDENTIAL_ID)) - .thenReturn(new ResponseEntity(dataResponse, OK)); - - CredentialData response = credHubTemplate.getById(CREDENTIAL_ID); - - assertThat(response, notNullValue()); - assertThat(response, equalTo(dataResponse.getData().get(0))); - } - - @Test - public void getByIdWithError() { - when(restTemplate.getForEntity(ID_URL_PATH, CredentialDataResponse.class, CREDENTIAL_ID)) - .thenReturn(new ResponseEntity(dataResponseWithError, OK)); - - try { - credHubTemplate.getById(CREDENTIAL_ID); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": errorMessage message")); - } - } - - @Test - public void getByIdWithHttpError() { - when(restTemplate.getForEntity(ID_URL_PATH, CredentialDataResponse.class, CREDENTIAL_ID)) - .thenReturn(new ResponseEntity(dataResponseWithError, UNAUTHORIZED)); - - try { - credHubTemplate.getById(CREDENTIAL_ID); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": " + HttpStatus.UNAUTHORIZED.toString())); - } - } - - @Test - public void findByNameWithSuccess() { - when(restTemplate.getForEntity(NAME_LIKE_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponse, OK)); - - FindResponse response = credHubTemplate.findByName(name.getName()); - - assertThat(response, notNullValue()); - assertThat(response.getFoundCredentials().size(), equalTo(1)); - assertThat(response.getFoundCredentials(), equalTo(findResponse.getFoundCredentials())); - } - - @Test - public void findByNameWithError() { - when(restTemplate.getForEntity(NAME_LIKE_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponseWithError, OK)); - - try { - credHubTemplate.findByName(name.getName()); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": errorMessage message")); - } - } - - @Test - public void findByNameWithHttpError() { - when(restTemplate.getForEntity(NAME_LIKE_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponseWithError, UNAUTHORIZED)); - - try { - credHubTemplate.findByName(name.getName()); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": " + HttpStatus.UNAUTHORIZED.toString())); - } - } - - @Test - public void findByPathWithSuccess() { - when(restTemplate.getForEntity(PATH_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponse, OK)); - - FindResponse response = credHubTemplate.findByPath(name.getName()); - - assertThat(response, notNullValue()); - assertThat(response.getFoundCredentials().size(), equalTo(1)); - assertThat(response.getFoundCredentials(), equalTo(findResponse.getFoundCredentials())); - } - - @Test - public void findByPathWithError() { - when(restTemplate.getForEntity(PATH_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponseWithError, OK)); - - try { - credHubTemplate.findByPath(name.getName()); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": errorMessage message")); - } - } - - @Test - public void findByPathWithHttpError() { - when(restTemplate.getForEntity(PATH_URL_QUERY, FindResponse.class, name.getName())) - .thenReturn(new ResponseEntity(findResponseWithError, UNAUTHORIZED)); - - try { - credHubTemplate.findByPath(name.getName()); - fail("Exception should have been thrown"); - } catch (CredHubException e) { - assertThat(e.getMessage(), containsString(": " + HttpStatus.UNAUTHORIZED.toString())); - } - } - - @Test - public void deleteByName() { - credHubTemplate.deleteByName(name.getName()); - - verify(restTemplate).delete(NAME_URL_QUERY, name.getName()); - } -} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTests.java new file mode 100644 index 0000000..b4fd07a --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTests.java @@ -0,0 +1,106 @@ +/* + * 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.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.credhub.support.ServiceInstanceCredentialName; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.credhub.core.CredHubTemplate.INTERPOLATE_URL_PATH; +import static org.springframework.credhub.core.CredHubTemplate.NAME_URL_QUERY; +import static org.springframework.credhub.core.CredHubTemplate.VCAP_SERVICES_KEY; +import static org.springframework.http.HttpStatus.OK; + +@RunWith(MockitoJUnitRunner.class) +public class CredHubTemplateUnitTests extends CredHubTemplateUnitTestsBase { + @Test + public void deleteByName() { + credHubTemplate.deleteByName(NAME.getName()); + + verify(restTemplate).delete(NAME_URL_QUERY, NAME.getName()); + } + + @Test + public void interpolateServiceData() throws IOException { + ServiceInstanceCredentialName credentialName = ServiceInstanceCredentialName.builder() + .serviceBrokerName("service-broker") + .serviceOfferingName("service-offering") + .serviceBindingId("1111-1111-1111-111") + .credentialName("credential_json") + .build(); + + Map request = buildVcap(credentialName.getName()); + Map> wrappedRequest = wrapVcap(request); + + Map> expectedResponse = new HashMap>(); + + ParameterizedTypeReference>> type = + new ParameterizedTypeReference>>() {}; + + when(restTemplate.exchange(INTERPOLATE_URL_PATH, HttpMethod.POST, + new HttpEntity>>(wrappedRequest), type)) + .thenReturn(new ResponseEntity>>(expectedResponse, OK)); + + Map response = credHubTemplate.interpolateServiceData(request); + + assertThat(response, equalTo(expectedResponse.get(VCAP_SERVICES_KEY))); + } + + private Map buildVcap(String credHubReferenceName) throws IOException { + String vcapServices = "{" + + " \"service-offering\": [" + + " {" + + " \"credentials\": {" + + " \"credhub-ref\": \"((" + credHubReferenceName + "))\"" + + " }," + + " \"label\": \"service-offering\"," + + " \"name\": \"service-instance\"," + + " \"plan\": \"standard\"," + + " \"tags\": [" + + " \"cloud-service\"" + + " ]," + + " \"volume_mounts\": []" + + " }" + + " ]" + + "}"; + + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(vcapServices, new TypeReference>() {}); + } + + private Map> wrapVcap(final Map serviceData) { + return new HashMap>() {{ + put(VCAP_SERVICES_KEY, serviceData); + }}; + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTestsBase.java b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTestsBase.java new file mode 100644 index 0000000..7911361 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/core/CredHubTemplateUnitTestsBase.java @@ -0,0 +1,44 @@ +/* + * 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 org.junit.Before; +import org.junit.Rule; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; + +import org.springframework.credhub.support.SimpleCredentialName; +import org.springframework.web.client.RestTemplate; + +public abstract class CredHubTemplateUnitTestsBase { + protected static final SimpleCredentialName NAME = new SimpleCredentialName("example", "credential"); + + @Rule + public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + + @Mock + protected RestTemplate restTemplate; + + protected CredHubTemplate credHubTemplate; + + @Before + public void setUpCredHubTemplateUnitTests() { + credHubTemplate = new CredHubTemplate(restTemplate); + } +} diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDataResponseUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDetailsDataUnitTests.java similarity index 56% rename from spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDataResponseUnitTests.java rename to spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDetailsDataUnitTests.java index 550d477..052da32 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDataResponseUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialDetailsDataUnitTests.java @@ -18,19 +18,16 @@ package org.springframework.credhub.support; -import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Map; + import org.hamcrest.CoreMatchers; import org.junit.Test; -import java.util.Map; - import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; -public class CredentialDataResponseUnitTests { - private ObjectMapper objectMapper = new ObjectMapper(); +public class CredentialDetailsDataUnitTests extends JsonParsingUnitTestsBase { @Test public void deserializationWithPasswordValue() throws Exception { @@ -38,7 +35,7 @@ public class CredentialDataResponseUnitTests { " \"data\": [" + " {" + " \"type\": \"password\"," + - " \"version_created_at\": \"2017-04-14T19:37:28Z\"," + + " \"version_created_at\": \"" + testDateString + "\"," + " \"id\": \"80cbb13f-7562-4e72-92de-f3ccf69eaa59\"," + " \"name\": \"/c/service-broker-name/service-instance-name/binding-id/credentials-json\"," + " \"value\": \"secret\"" + @@ -46,21 +43,20 @@ public class CredentialDataResponseUnitTests { " ]" + "}"; - CredentialDataResponse response = parseResponse(json); + CredentialDetailsData response = parseResponse(json); assertThat(response.getData().size(), equalTo(1)); - CredentialData data = response.getData().get(0); + CredentialDetails data = response.getData().get(0); assertThat(data.getValueType(), equalTo(ValueType.PASSWORD)); - assertThat(data.getVersionCreatedAt(), equalTo("2017-04-14T19:37:28Z")); + assertThat(data.getVersionCreatedAt(), equalTo(testDate)); assertThat(data.getId(), equalTo("80cbb13f-7562-4e72-92de-f3ccf69eaa59")); - assertThat(data.getName().getName(), equalTo("/c/service-broker-name/service-instance-name/binding-id/credentials-json")); + assertThat(data.getName().getName(), equalTo( + "/c/service-broker-name/service-instance-name/binding-id/credentials-json")); assertThat(data.getValue(), instanceOf(String.class)); - assertThat(data.getValue(), CoreMatchers.equalTo("secret")); - - assertThat(response.getErrorMessage(), nullValue()); + assertThat(data.getValue(), CoreMatchers. equalTo("secret")); } @Test @@ -69,7 +65,7 @@ public class CredentialDataResponseUnitTests { " \"data\": [" + " {" + " \"type\": \"json\"," + - " \"version_created_at\": \"2017-04-14T19:37:28Z\"," + + " \"version_created_at\": \"" + testDateString + "\"," + " \"id\": \"80cbb13f-7562-4e72-92de-f3ccf69eaa59\"," + " \"name\": \"/c/service-broker-name/service-instance-name/binding-id/credentials-json\"," + " \"value\": {" + @@ -81,40 +77,29 @@ public class CredentialDataResponseUnitTests { " ]" + "}"; - CredentialDataResponse response = parseResponse(json); + CredentialDetailsData response = parseResponse(json); assertThat(response.getData().size(), equalTo(1)); - CredentialData data = response.getData().get(0); - + CredentialDetails data = response.getData().get(0); + assertThat(data.getValueType(), equalTo(ValueType.JSON)); - assertThat(data.getVersionCreatedAt(), equalTo("2017-04-14T19:37:28Z")); + assertThat(data.getVersionCreatedAt(), equalTo(testDate)); assertThat(data.getId(), equalTo("80cbb13f-7562-4e72-92de-f3ccf69eaa59")); - assertThat(data.getName().getName(), equalTo("/c/service-broker-name/service-instance-name/binding-id/credentials-json")); + assertThat(data.getName().getName(), equalTo( + "/c/service-broker-name/service-instance-name/binding-id/credentials-json")); assertThat(data.getValue(), instanceOf(Map.class)); Map valueMap = (Map) data.getValue(); - assertThat(valueMap.get("client_id"), CoreMatchers.equalTo("test-id")); - assertThat(valueMap.get("client_secret"), CoreMatchers.equalTo("test-secret")); - assertThat(valueMap.get("uri"), CoreMatchers.equalTo("https://example.com")); - - - assertThat(response.getErrorMessage(), nullValue()); + assertThat(valueMap.get("client_id"), CoreMatchers. equalTo("test-id")); + assertThat(valueMap.get("client_secret"), + CoreMatchers. equalTo("test-secret")); + assertThat(valueMap.get("uri"), + CoreMatchers. equalTo("https://example.com")); } - @Test - public void deserializationWithError() throws Exception { - String json = "{" + - " \"errorMessage\": \"some errorMessage text\"" + - "}"; - - CredentialDataResponse response = parseResponse(json); - assertThat(response.getErrorMessage(), equalTo("some errorMessage text")); - - assertThat(response.getData(), nullValue()); - } - - private CredentialDataResponse parseResponse(String json) throws java.io.IOException { - return objectMapper.readValue(json, CredentialDataResponse.class); + private CredentialDetailsData parseResponse(String json) + throws java.io.IOException { + return objectMapper.readValue(json, CredentialDetailsData.class); } } diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialSummaryDataUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialSummaryDataUnitTests.java new file mode 100644 index 0000000..2aa004f --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredentialSummaryDataUnitTests.java @@ -0,0 +1,82 @@ +/* + * 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 java.util.List; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class CredentialSummaryDataUnitTests extends JsonParsingUnitTestsBase { + @Test + public void deserializationWithCredentials() throws Exception { + String json = "{\n" + + " \"credentials\": [\n" + + " {\n" + + " \"name\": \"/c/deploy123/example1\",\n" + + " \"version_created_at\": \"" + testDateString + "\"\n" + + " },\n" + + " {\n" + + " \"name\": \"/c/deploy123/example2\",\n" + + " \"version_created_at\": \"" + testDateString + "\"\n" + + " },\n" + + " {\n" + + " \"name\": \"/c/deploy123/example3\",\n" + + " \"version_created_at\": \"" + testDateString + "\"\n" + + " }\n" + + " ]\n" + + "}"; + + CredentialSummaryData response = parseResponse(json); + + assertThat(response.getCredentials().size(), equalTo(3)); + + List credentials = response.getCredentials(); + + assertThat(credentials.get(0).getName().getName(), + equalTo("/c/deploy123/example1")); + assertThat(credentials.get(1).getName().getName(), + equalTo("/c/deploy123/example2")); + assertThat(credentials.get(2).getName().getName(), + equalTo("/c/deploy123/example3")); + + for (CredentialSummary credential : credentials) { + assertThat(credential.getVersionCreatedAt(), equalTo(testDate)); + } + } + + @Test + public void deserializationWithEmptyCredentials() throws Exception { + String json = "{\n" + + " \"credentials\": [\n" + + " ]\n" + + "}"; + + CredentialSummaryData response = parseResponse(json); + + assertThat(response.getCredentials(), notNullValue()); + assertThat(response.getCredentials().size(), equalTo(0)); + } + + private CredentialSummaryData parseResponse(String json) + throws java.io.IOException { + return objectMapper.readValue(json, CredentialSummaryData.class); + } +} diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/JsonParsingUnitTestsBase.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/JsonParsingUnitTestsBase.java new file mode 100644 index 0000000..12ea7b9 --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/JsonParsingUnitTestsBase.java @@ -0,0 +1,41 @@ +/* + * 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 java.text.DateFormat; +import java.util.Date; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.util.ISO8601DateFormat; +import org.junit.Before; + +public abstract class JsonParsingUnitTestsBase { + protected ObjectMapper objectMapper; + protected Date testDate; + protected String testDateString; + + @Before + public void setUpJsonParsing() throws Exception { + DateFormat dateFormat = new ISO8601DateFormat(); + + objectMapper = new ObjectMapper(); + objectMapper.setDateFormat(dateFormat); + + testDateString = "2017-01-31T11:22:33Z"; + testDate = dateFormat.parse(testDateString); + } +} diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/ServiceInstanceCredentialNameUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/ServiceInstanceCredentialNameUnitTests.java new file mode 100644 index 0000000..227ae7f --- /dev/null +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/ServiceInstanceCredentialNameUnitTests.java @@ -0,0 +1,32 @@ +/* + * 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 ServiceInstanceCredentialNameUnitTests { + @Test + public void simpleNameIsConstructed() { + CredentialName credentialName = + new ServiceInstanceCredentialName("broker-name", "service-name", "binding-id", "credential-name"); + + assertThat(credentialName.getName(), equalTo("/c/broker-name/service-name/binding-id/credential-name")); + } +} \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredHubRequestUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SimpleCredentialNameUnitTests.java similarity index 62% rename from spring-credhub-core/src/test/java/org/springframework/credhub/support/CredHubRequestUnitTests.java rename to spring-credhub-core/src/test/java/org/springframework/credhub/support/SimpleCredentialNameUnitTests.java index aa2512f..60c8aeb 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/support/CredHubRequestUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/SimpleCredentialNameUnitTests.java @@ -23,12 +23,19 @@ import org.junit.Test; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; -public class CredHubRequestUnitTests { +public class SimpleCredentialNameUnitTests { @Test - public void generateNameWithAllFields() { - CredHubRequest request = new CredHubRequest(new CredentialName("service-broker-name", "service-offering-name", - "service-binding-id", "credential-name")); + public void simpleNameIsConstructed() { + CredentialName credentialName = + new SimpleCredentialName("myorg", "example", "credential-name"); - assertThat(request.getName(), equalTo("/c/service-broker-name/service-offering-name/service-binding-id/credential-name")); + assertThat(credentialName.getName(), equalTo("/c/myorg/example/credential-name")); + } + + @Test + public void simpleNameIsParsed() { + CredentialName credentialName = new CredentialName("/c/myorg/example/credential-name"); + + assertThat(credentialName.getName(), equalTo("/c/myorg/example/credential-name")); } } \ No newline at end of file diff --git a/spring-credhub-core/src/test/java/org/springframework/credhub/support/WriteRequestUnitTests.java b/spring-credhub-core/src/test/java/org/springframework/credhub/support/WriteRequestUnitTests.java index 5e54e94..ad785c6 100644 --- a/spring-credhub-core/src/test/java/org/springframework/credhub/support/WriteRequestUnitTests.java +++ b/spring-credhub-core/src/test/java/org/springframework/credhub/support/WriteRequestUnitTests.java @@ -18,20 +18,19 @@ package org.springframework.credhub.support; +import java.util.HashMap; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; import org.junit.Test; -import java.util.HashMap; - -import static org.springframework.credhub.support.AccessControlEntry.Operation.READ; -import static org.springframework.credhub.support.AccessControlEntry.Operation.WRITE; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.springframework.credhub.support.AccessControlEntry.Operation.READ; +import static org.springframework.credhub.support.AccessControlEntry.Operation.WRITE; import static org.valid4j.matchers.jsonpath.JsonPathMatchers.hasJsonPath; import static org.valid4j.matchers.jsonpath.JsonPathMatchers.hasNoJsonPath; import static org.valid4j.matchers.jsonpath.JsonPathMatchers.isJson; @@ -46,10 +45,8 @@ public class WriteRequestUnitTests { public void setUp() { mapper = new ObjectMapper(); - requestBuilder = WriteRequest.builder() - .name(SimpleCredentialName.builder() - .segments("example", "credential") - .build()); + requestBuilder = WriteRequest.builder().name( + new SimpleCredentialName("example", "credential")); } @Test @@ -59,88 +56,80 @@ public class WriteRequestUnitTests { @Test public void serializationWithJsonValue() throws Exception { - requestBuilder - .jsonValue(new HashMap() {{ - put("data", "value"); - put("test", true); - }}); + requestBuilder.jsonValue(new HashMap() { + { + put("data", "value"); + put("test", true); + } + }); String jsonValue = serializeToJson(requestBuilder); - assertThat(jsonValue, allOf( - hasJsonPath("$.overwrite", equalTo(false)), - hasJsonPath("$.name", equalTo("/c/example/credential")), - hasJsonPath("$.type", equalTo("json")), - hasJsonPath("$.value.data", equalTo("value")), - hasJsonPath("$.value.test", equalTo(true)) - )); + assertThat(jsonValue, + allOf(hasJsonPath("$.overwrite", equalTo(false)), + hasJsonPath("$.name", equalTo("/c/example/credential")), + hasJsonPath("$.type", equalTo("json")), + hasJsonPath("$.value.data", equalTo("value")), + hasJsonPath("$.value.test", equalTo(true)))); assertThat(jsonValue, hasNoJsonPath("$.access_control_entries")); } @Test public void serializationWithPasswordValue() throws Exception { - requestBuilder - .overwrite(true) - .passwordValue("secret"); + requestBuilder.overwrite(true).passwordValue("secret"); String jsonValue = serializeToJson(requestBuilder); - assertThat(jsonValue, allOf( - hasJsonPath("$.overwrite", equalTo(true)), - hasJsonPath("$.name", equalTo("/c/example/credential")), - hasJsonPath("$.type", equalTo("password")), - hasJsonPath("$.value", equalTo("secret")) - )); + assertThat(jsonValue, + allOf(hasJsonPath("$.overwrite", equalTo(true)), + hasJsonPath("$.name", equalTo("/c/example/credential")), + hasJsonPath("$.type", equalTo("password")), + hasJsonPath("$.value", equalTo("secret")))); assertThat(jsonValue, hasNoJsonPath("$.access_control_entries")); } @Test public void serializationWithOneAccessControl() throws Exception { - requestBuilder - .passwordValue("secret") - .accessControlEntry(AccessControlEntry.builder() - .app("app-id") - .operation(READ) - .build()); + requestBuilder.passwordValue("secret").accessControlEntry( + AccessControlEntry.builder().app("app-id").operation(READ).build()); String jsonValue = serializeToJson(requestBuilder); - assertThat(jsonValue, allOf( - hasJsonPath("$.access_control_entries[0].actor", equalTo("mtls-app:app-id")), - hasJsonPath("$.access_control_entries[0].operations[0]", equalTo("read")) - )); + assertThat(jsonValue, + allOf(hasJsonPath("$.access_control_entries[0].actor", + equalTo("mtls-app:app-id")), + hasJsonPath("$.access_control_entries[0].operations[0]", + equalTo("read")))); } @Test public void serializationWithTwoAccessControls() throws Exception { - requestBuilder - .passwordValue("secret") - .accessControlEntry(AccessControlEntry.builder() - .app("app1-id") - .operation(READ) - .operation(WRITE) - .build()) - .accessControlEntry(AccessControlEntry.builder() - .app("app2-id") - .operation(WRITE) - .operation(READ) - .build()); + requestBuilder.passwordValue("secret") + .accessControlEntry(AccessControlEntry.builder().app("app1-id") + .operation(READ).operation(WRITE).build()) + .accessControlEntry(AccessControlEntry.builder().app("app2-id") + .operation(WRITE).operation(READ).build()); String jsonValue = serializeToJson(requestBuilder); assertThat(jsonValue, allOf( - hasJsonPath("$.access_control_entries[0].actor", equalTo("mtls-app:app1-id")), + hasJsonPath("$.access_control_entries[0].actor", + equalTo("mtls-app:app1-id")), hasJsonPath("$.access_control_entries[0].operations[0]", equalTo("read")), - hasJsonPath("$.access_control_entries[0].operations[1]", equalTo("write")), - hasJsonPath("$.access_control_entries[1].actor", equalTo("mtls-app:app2-id")), - hasJsonPath("$.access_control_entries[1].operations[0]", equalTo("write")), - hasJsonPath("$.access_control_entries[1].operations[1]", equalTo("read")) - )); + hasJsonPath("$.access_control_entries[0].operations[1]", + equalTo("write")), + hasJsonPath("$.access_control_entries[1].actor", + equalTo("mtls-app:app2-id")), + hasJsonPath("$.access_control_entries[1].operations[0]", + equalTo("write")), + hasJsonPath("$.access_control_entries[1].operations[1]", + equalTo("read")))); } - private String serializeToJson(WriteRequest.WriteRequestBuilder requestBuilder) throws JsonProcessingException { + private String serializeToJson(WriteRequest.WriteRequestBuilder requestBuilder) + throws JsonProcessingException { String jsonValue = mapper.writeValueAsString(requestBuilder.build()); assertThat(jsonValue, isJson()); return jsonValue; diff --git a/spring-credhub-demo/pom.xml b/spring-credhub-demo/pom.xml new file mode 100644 index 0000000..17471f3 --- /dev/null +++ b/spring-credhub-demo/pom.xml @@ -0,0 +1,75 @@ + + + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.3.RELEASE + + + + spring-credhub-demo + Spring CredHub Demo + Spring CredHub Demo Application + 1.0.0.BUILD-SNAPSHOT + jar + + + UTF-8 + UTF-8 + 1.6 + + + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.credhub + spring-credhub-core + 1.0.0.BUILD-SNAPSHOT + + + org.apache.httpcomponents + httpclient + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/Application.java b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/Application.java new file mode 100644 index 0000000..0469086 --- /dev/null +++ b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/Application.java @@ -0,0 +1,29 @@ +/* + * 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.demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoConfiguration.java b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoConfiguration.java new file mode 100644 index 0000000..91c9ce7 --- /dev/null +++ b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoConfiguration.java @@ -0,0 +1,26 @@ +/* + * 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.demo; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.credhub.configuration.CredHubConfiguration; + +@Configuration +@Import(CredHubConfiguration.class) +public class CredHubDemoConfiguration { +} diff --git a/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoController.java b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoController.java new file mode 100644 index 0000000..01060aa --- /dev/null +++ b/spring-credhub-demo/src/main/java/org/springframework/credhub/demo/CredHubDemoController.java @@ -0,0 +1,194 @@ +/* + * 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.demo; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.credhub.core.CredHubTemplate; +import org.springframework.credhub.support.AccessControlEntry; +import org.springframework.credhub.support.CredentialDetails; +import org.springframework.credhub.support.CredentialName; +import org.springframework.credhub.support.CredentialSummary; +import org.springframework.credhub.support.SimpleCredentialName; +import org.springframework.credhub.support.WriteRequest; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import static org.springframework.credhub.support.AccessControlEntry.Operation.READ; + +@RestController +public class CredHubDemoController { + @Value("${vcap.application.application_id:}") + private String appId; + + private CredHubTemplate credHubTemplate; + + public CredHubDemoController(CredHubTemplate credHubTemplate) { + this.credHubTemplate = credHubTemplate; + } + + @PostMapping("/test") + public Results runTests(@RequestBody Map value) { + Results results = new Results(); + + CredentialDetails credentialDetails = writeCredentials(value, results); + CredentialName credentialName = credentialDetails.getName(); + + getCredentialsById(credentialDetails.getId(), results); + + getCredentialsByName(credentialName, results); + + findCredentialsByName(credentialName, results); + + findCredentialsByPath(credentialName.getName(), results); + + interpolateServiceData(credentialName, results); + + deleteCredentials(credentialName, results); + + return results; + } + + @SuppressWarnings("unchecked") + private CredentialDetails writeCredentials(T value, Results results) { + try { + WriteRequest.WriteRequestBuilder requestBuilder = WriteRequest.builder() + .overwrite(true) + .name(new SimpleCredentialName("spring-credhub", "demo", "credentials_json")); + + if (value instanceof String) { + requestBuilder.passwordValue((String) value); + } + else { + requestBuilder.jsonValue((Map) value); + } + + if (StringUtils.hasText(appId)) { + requestBuilder.accessControlEntry( + AccessControlEntry.builder().app(appId).operation(READ).build()); + } + + WriteRequest request = requestBuilder.build(); + + CredentialDetails credentialDetails = credHubTemplate.write(request); + saveResults(results, "Successfully wrote credentials: ", credentialDetails); + + return credentialDetails; + } + catch (Exception e) { + saveResults(results, "Error writing credentials: ", e.getMessage()); + return null; + } + } + + private void getCredentialsById(String id, Results results) { + try { + CredentialDetails retrievedDetails = credHubTemplate.getById(id); + saveResults(results, "Successfully retrieved credentials by ID: ", retrievedDetails); + } catch (Exception e) { + saveResults(results, "Error retrieving credentials by ID: ", e.getMessage()); + } + } + + private void getCredentialsByName(CredentialName name, Results results) { + try { + List retrievedDetails = credHubTemplate.getByName(name); + saveResults(results, "Successfully retrieved credentials by name: ", retrievedDetails); + } catch (Exception e) { + saveResults(results, "Error retrieving credentials by name: ", e.getMessage()); + } + } + + private void findCredentialsByName(CredentialName name, Results results) { + try { + List retrievedDetails = credHubTemplate.findByName(name); + saveResults(results, "Successfully found credentials by name: ", retrievedDetails); + } catch (Exception e) { + saveResults(results, "Error finding credentials by name: ", e.getMessage()); + } + } + + private void findCredentialsByPath(String path, Results results) { + try { + List retrievedDetails = credHubTemplate.findByPath(path); + saveResults(results, "Successfully found credentials by path: ", retrievedDetails); + } catch (Exception e) { + saveResults(results, "Error finding credentials by path: ", e.getMessage()); + } + } + + private void interpolateServiceData(CredentialName name, Results results) { + try { + Map request = buildVcapServicesData(name.getName()); + Map interpolatedServiceData = credHubTemplate.interpolateServiceData(request); + saveResults(results, "Successfully interpolated service data: ", interpolatedServiceData); + } catch (Exception e) { + saveResults(results, "Error interpolating service data: ", e.getMessage()); + } + } + + private void deleteCredentials(CredentialName name, Results results) { + try { + credHubTemplate.deleteByName(name); + saveResults(results, "Successfully deleted credentials"); + } catch (Exception e) { + saveResults(results, "Error deleting credentials by name: ", e.getMessage()); + } + } + + private Map buildVcapServicesData(String credHubReferenceName) throws IOException { + String vcapServices = "{" + + " \"service-offering\": [" + + " {" + + " \"credentials\": {" + + " \"credhub-ref\": \"((" + credHubReferenceName + "))\"" + + " }," + + " \"label\": \"service-offering\"," + + " \"name\": \"service-instance\"," + + " \"plan\": \"standard\"," + + " \"tags\": [" + + " \"cloud-service\"" + + " ]," + + " \"volume_mounts\": []" + + " }" + + " ]" + + "}"; + + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(vcapServices, new TypeReference>() {}); + } + + private void saveResults(Results results, String message) { + saveResults(results, message, null); + } + + private void saveResults(Results results, String message, Object details) { + results.add(Collections.singletonMap(message, details)); + } + + private class Results extends ArrayList> { + } +}