Initial commit.

This commit is contained in:
Scott Frederick
2017-04-21 16:16:41 -05:00
commit b5708f0df8
32 changed files with 3423 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
*.iml
*.ipr
*.iws
.idea
.classpath
.project
.settings
.checkstyle
bin
build
out
target

716
pom.xml Normal file
View File

@@ -0,0 +1,716 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<name>Spring CredHub</name>
<description>Parent project for Spring CredHub</description>
<packaging>pom</packaging>
<url>http://projects.spring.io/spring-credhub/</url>
<modules>
<module>spring-credhub-dependencies</module>
<module>spring-credhub-core</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.7.RELEASE</spring.version>
<java.version>1.6</java.version>
<project.type>multi</project.type>
<dist.id>spring-credhub</dist.id>
<project.root>${basedir}</project.root>
</properties>
<inceptionYear>2017</inceptionYear>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<scm>
<url>https://github.com/spring-projects/spring-credhub</url>
<connection>scm:git:git://github.com/spring-projects/spring-credhub.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-credhub.git</developerConnection>
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-credhub/issues</url>
</issueManagement>
<ciManagement>
<system>Bamboo</system>
<url>https://build.spring.io/browse/SPRINGCREDHUB-CREDHUB</url>
</ciManagement>
<developers>
<developer>
<id>sfrederick</id>
<name>Scott Frederick</name>
</developer>
</developers>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
<comments>
Copyright 2016 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.
</comments>
</license>
</licenses>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-dependencies</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<!-- Spring Framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.7.22</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.valid4j</groupId>
<artifactId>json-path-matchers</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java16</artifactId>
<version>1.0</version>
</signature>
</configuration>
<executions>
<execution>
<id>enforce-java-6</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<!--
Default versioned declarations of managed plugins
to be overridden when the distribute profile is active.
If this section was missing, Maven would complain about
missing version numbers for executions without the
profile active.
-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.5.1</version>
<dependencies>
<dependency><!-- add support for ssh/scp -->
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.15</version>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>wagon-maven-plugin</artifactId>
<version>1.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>springNext</id>
<properties>
<spring.version>4.3.8.BUILD-SNAPSHOT</spring.version>
</properties>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>spring5</id>
<properties>
<spring.version>5.0.0.BUILD-SNAPSHOT</spring.version>
</properties>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>milestone</id>
<distributionManagement>
<repository>
<id>repo.spring.io</id>
<name>Spring Milestone Repository</name>
<url>http://repo.spring.io/libs-milestone-local</url>
</repository>
</distributionManagement>
</profile>
<profile>
<!-- Profile to be run on the CI server, JARs JavaDocs -->
<id>ci</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<!--
Profile to be activated when building the distribution atrifacts.
Generates reference documentation, aggregates JavaDoc etc. Has to be combined with
profiles "release" or "milestone" to deploy artifacts into the appropriate places.
-->
<id>distribute</id>
<properties>
<shared.resources>${project.build.directory}/shared-resources</shared.resources>
<maven.install.skip>true</maven.install.skip>
<skipTests>true</skipTests>
</properties>
<!-- <dependencies>
<dependency>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-build-resources</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<scope>provided</scope>
<type>zip</type>
</dependency>
</dependencies>-->
<build>
<plugins>
<!--
Unpacks the content of spring-data-build-resources into the shared resources folder.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-shared-resources</id>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<phase>generate-resources</phase>
</execution>
</executions>
<configuration>
<includeGroupIds>org.springframework.data</includeGroupIds>
<includeArtifactIds>spring-data-build-resources</includeArtifactIds>
<includeTypes>zip</includeTypes>
<excludeTransitive>true</excludeTransitive>
<outputDirectory>${shared.resources}</outputDirectory>
</configuration>
</plugin>
<!--
Configures JavaDoc generation.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>aggregate-javadoc</id>
<goals>
<goal>aggregate</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
<!--
Copies all namespaces schemas to target/schemas flatten the directory structure.
Depended on by the site.xml assembly descriptor.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-documentation-resources</id>
<phase>generate-resources</phase>
<configuration>
<target>
<copy todir="${project.root}/target/site/reference/html">
<fileset dir="${shared.resources}/asciidoc" erroronmissingdir="false">
<include name="**/*.css" />
</fileset>
<flattenmapper />
</copy>
<copy todir="${project.root}/target/site/reference/html/images">
<fileset dir="${basedir}/src/main/asciidoc" erroronmissingdir="false">
<include name="**/*.png" />
<include name="**/*.gif" />
<include name="**/*.jpg" />
</fileset>
<flattenmapper />
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>collect-schema-files</id>
<phase>process-resources</phase>
<configuration>
<target>
<copy todir="${project.build.directory}/schemas">
<fileset dir="${basedir}" erroronmissingdir="false">
<include name="**/src/main/resources/**/config/spring-*.xsd" />
</fileset>
<flattenmapper />
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>rename-reference-docs</id>
<phase>process-resources</phase>
<configuration>
<target>
<copy failonerror="false" file="${project.build.directory}/generated-docs/index.pdf" tofile="${project.root}/target/site/reference/pdf/${dist.id}-reference.pdf" />
<copy failonerror="false" file="${project.build.directory}/generated-docs/index.epub" tofile="${project.root}/target/site/reference/epub/${dist.id}-reference.epub" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--
JavaDoc
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<breakiterator>true</breakiterator>
<header>${project.name}</header>
<source>${java.version}</source>
<quiet>true</quiet>
<javadocDirectory>${shared.resources}/javadoc</javadocDirectory>
<overview>${shared.resources}/javadoc/overview.html</overview>
<stylesheetfile>${shared.resources}/javadoc/spring-javadoc.css</stylesheetfile>
<!-- copies doc-files subdirectory which contains image resources -->
<docfilessubdirs>true</docfilessubdirs>
<additionalparam>-Xdoclint:none</additionalparam>
<links>
<link>http://docs.spring.io/spring/docs/current/javadoc-api/</link>
<link>http://docs.oracle.com/javase/6/docs/api</link>
</links>
</configuration>
</plugin>
<!--
Asciidoctor
-->
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>1.5.0-alpha.11</version>
</dependency>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-epub3</artifactId>
<version>1.5.0-alpha.6</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>html</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<outputDirectory>${project.root}/target/site/reference/html</outputDirectory>
<sectids>false</sectids>
<sourceHighlighter>prettify</sourceHighlighter>
<attributes>
<linkcss>true</linkcss>
<icons>font</icons>
<sectanchors>true</sectanchors>
<stylesheet>spring.css</stylesheet>
</attributes>
</configuration>
</execution>
<execution>
<id>epub</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>epub3</backend>
<sourceHighlighter>coderay</sourceHighlighter>
</configuration>
</execution>
<execution>
<id>pdf</id>
<phase>generate-resources</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<sourceHighlighter>coderay</sourceHighlighter>
</configuration>
</execution>
</executions>
<configuration>
<sourceDirectory>${project.root}/src/main/asciidoc</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<doctype>book</doctype>
<attributes>
<version>${project.version}</version>
<projectName>${project.name}</projectName>
<projectVersion>${project.version}</projectVersion>
<springVersion>${spring.version}</springVersion>
<allow-uri-read>true</allow-uri-read>
<toclevels>3</toclevels>
<numbered>true</numbered>
</attributes>
</configuration>
</plugin>
<!--
Creates two zip files for download as well as API and reference documentation distribution.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>static</id>
<goals>
<goal>single</goal>
</goals>
<phase>prepare-package</phase>
<configuration>
<descriptors>
<descriptor>${shared.resources}/assemblies/static-resources.xml</descriptor>
</descriptors>
<finalName>static-resources</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
<execution>
<id>docs</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>src/assembly/docs.xml</descriptor>
</descriptors>
<finalName>spring-credhub-${project.version}-docs</finalName>
<appendAssemblyId>false</appendAssemblyId>
<classifier>docs</classifier>
<attach>true</attach>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
<uniqueVersion>false</uniqueVersion>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-plugins-release</id>
<url>https://repo.spring.io/plugins-release</url>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
</project>

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-parent</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-credhub-core</artifactId>
<name>Spring CredHub Core</name>
<description>Spring CredHub Core Components</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.valid4j</groupId>
<artifactId>json-path-matchers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,115 @@
/*
* 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.configuration;
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;
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
*/
public class ClientHttpRequestFactoryFactory {
private static final boolean HTTP_COMPONENTS_PRESENT = ClassUtils.isPresent(
"org.apache.http.client.HttpClient",
ClientHttpRequestFactoryFactory.class.getClassLoader());
/**
* Create a {@link ClientHttpRequestFactory} for the given {@link ClientOptions} and
* {@link SslConfiguration}.
*
* @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) {
Assert.notNull(options, "ClientOptions must not be null");
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
try {
if (HTTP_COMPONENTS_PRESENT) {
return HttpComponents.usingHttpComponents(options, sslConfiguration);
}
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
} catch (IOException e) {
throw new IllegalStateException(e);
}
throw new IllegalStateException("Only Apache HTTP Components is supported.");
}
private static boolean hasSslConfiguration(SslConfiguration sslConfiguration) {
return sslConfiguration.getTrustStore() != null
|| sslConfiguration.getKeyStore() != null;
}
/**
* {@link ClientHttpRequestFactory} for Apache HttpComponents.
*/
static class HttpComponents {
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())
.build();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
httpClientBuilder.setSSLSocketFactory(sslSocketFactory);
httpClientBuilder.setSSLContext(sslContext);
}
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(options.getConnectionTimeout())
.setSocketTimeout(options.getReadTimeout())
.setAuthenticationEnabled(true)
.build();
httpClientBuilder.setDefaultRequestConfig(requestConfig);
return new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
}
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.configuration;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.credhub.core.CloudFoundryAppInstanceProperties;
import org.springframework.credhub.core.CredHubProperties;
import org.springframework.credhub.core.CredHubTemplate;
import org.springframework.credhub.support.ClientOptions;
import org.springframework.credhub.support.SslConfiguration;
import org.springframework.http.client.ClientHttpRequestFactory;
@Configuration
public class CredHubConfiguration {
@Bean
public CredHubProperties credHubProperties() {
return new CredHubProperties();
}
@Bean
public CloudFoundryAppInstanceProperties cloudFoundryAppInstanceProperties() {
return new CloudFoundryAppInstanceProperties();
}
@Bean
public CredHubTemplate credHubTemplate() {
return new CredHubTemplate(credHubProperties().getApiUriBase(),
clientHttpRequestFactoryWrapper().getClientHttpRequestFactory());
}
/**
* 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.
* @see #clientOptions()
* @see #sslConfiguration()
*/
@Bean
public ClientFactoryWrapper clientHttpRequestFactoryWrapper() {
ClientHttpRequestFactory clientHttpRequestFactory =
ClientHttpRequestFactoryFactory.create(clientOptions(), sslConfiguration());
return new ClientFactoryWrapper(clientHttpRequestFactory);
}
/**
* @return {@link ClientOptions} to configure communication parameters.
* @see ClientOptions
*/
private ClientOptions clientOptions() {
return new ClientOptions();
}
/**
* @return SSL configuration options.
* @see SslConfiguration
*/
private SslConfiguration sslConfiguration() {
CloudFoundryAppInstanceProperties properties = cloudFoundryAppInstanceProperties();
return SslConfiguration.forContainerCert(properties.getInstanceCertLocation(), properties.getInstanceKeyLocation());
}
/**
* Wrapper for {@link ClientHttpRequestFactory} to not expose the bean globally.
*/
public static class ClientFactoryWrapper implements InitializingBean, DisposableBean {
private final ClientHttpRequestFactory clientHttpRequestFactory;
public ClientFactoryWrapper(ClientHttpRequestFactory clientHttpRequestFactory) {
this.clientHttpRequestFactory = clientHttpRequestFactory;
}
@Override
public void destroy() throws Exception {
if (clientHttpRequestFactory instanceof DisposableBean) {
((DisposableBean) clientHttpRequestFactory).destroy();
}
}
@Override
public void afterPropertiesSet() throws Exception {
if (clientHttpRequestFactory instanceof InitializingBean) {
((InitializingBean) clientHttpRequestFactory).afterPropertiesSet();
}
}
public ClientHttpRequestFactory getClientHttpRequestFactory() {
return clientHttpRequestFactory;
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.beans.factory.annotation.Value;
public class CloudFoundryAppInstanceProperties {
@Value("${CF_INSTANCE_CERT}")
private String instanceCertLocation;
@Value("${CF_INSTANCE_KEY}")
private String instanceKeyLocation;
public CloudFoundryAppInstanceProperties() {
}
public CloudFoundryAppInstanceProperties(String instanceCertLocation, String instanceKeyLocation) {
this.instanceCertLocation = instanceCertLocation;
this.instanceKeyLocation = instanceKeyLocation;
}
public String getInstanceCertLocation() {
return instanceCertLocation;
}
public String getInstanceKeyLocation() {
return instanceKeyLocation;
}
}

View File

@@ -0,0 +1,38 @@
/*
*
* * 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.core;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriTemplateHandler;
public class CredHubClient {
public static RestTemplate createRestTemplate(String baseUri, ClientHttpRequestFactory clientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(createUriTemplateHandler(baseUri));
restTemplate.setRequestFactory(clientHttpRequestFactory);
return restTemplate;
}
private static DefaultUriTemplateHandler createUriTemplateHandler(String baseUri) {
DefaultUriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler();
uriTemplateHandler.setBaseUrl(baseUri);
return uriTemplateHandler;
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.core.NestedRuntimeException;
import org.springframework.http.HttpStatus;
import org.springframework.web.client.HttpStatusCodeException;
public class CredHubException extends NestedRuntimeException {
public CredHubException(HttpStatusCodeException e) {
super("Error calling CredHub: " + e.getStatusCode() + ": " + e.getResponseBodyAsString());
}
public CredHubException(HttpStatus statusCode) {
super("Error calling CredHub: " + statusCode);
}
public CredHubException(String message) {
super("Error returned from call to CredHub: " + message);
}
}

View File

@@ -0,0 +1,37 @@
/*
*
* * 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.core;
import org.springframework.beans.factory.annotation.Value;
public class CredHubProperties {
@Value("${CREDHUB_API}")
private String apiUriBase;
public CredHubProperties() {
}
public CredHubProperties(String apiUriBase) {
this.apiUriBase = apiUriBase;
}
public String getApiUriBase() {
return apiUriBase;
}
}

View File

@@ -0,0 +1,122 @@
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 org.springframework.credhub.support.WriteRequest;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.util.Assert;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;
public class CredHubTemplate {
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}";
private final RestTemplate restTemplate;
CredHubTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public CredHubTemplate(String apiUriBase, ClientHttpRequestFactory clientHttpRequestFactory) {
this.restTemplate = CredHubClient.createRestTemplate(apiUriBase, clientHttpRequestFactory);
}
public CredentialData write(final WriteRequest writeRequest) {
return doWithRest(new RestOperationsCallback<CredentialData>() {
@Override
public CredentialData doWithRestOperations(RestOperations restOperations) {
ResponseEntity<CredentialDataResponse> response =
restOperations.exchange(BASE_URL_PATH, HttpMethod.PUT,
new HttpEntity<WriteRequest>(writeRequest),
CredentialDataResponse.class);
throwExceptionOnError(response);
return response.getBody().getData().get(0);
}
});
}
public CredentialData getById(final String id) {
return doWithRest(new RestOperationsCallback<CredentialData>() {
@Override
public CredentialData doWithRestOperations(RestOperations restOperations) {
ResponseEntity<CredentialDataResponse> 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<FindResponse>() {
@Override
public FindResponse doWithRestOperations(RestOperations restOperations) {
ResponseEntity<FindResponse> response =
restOperations.getForEntity(NAME_LIKE_URL_QUERY, FindResponse.class, name);
throwExceptionOnError(response);
return response.getBody();
}
});
}
public FindResponse findByPath(final String path) {
return doWithRest(new RestOperationsCallback<FindResponse>() {
@Override
public FindResponse doWithRestOperations(RestOperations restOperations) {
ResponseEntity<FindResponse> response =
restOperations.getForEntity(PATH_URL_QUERY, FindResponse.class, path);
throwExceptionOnError(response);
return response.getBody();
}
});
}
public void deleteByName(final String name) {
doWithRest(new RestOperationsCallback<Void>() {
@Override
public Void doWithRestOperations(RestOperations restOperations) {
restOperations.delete(NAME_URL_QUERY, name);
return null;
}
});
}
public <T> T doWithRest(RestOperationsCallback<T> callback) {
Assert.notNull(callback, "Callback must not be null");
try {
return callback.doWithRestOperations(restTemplate);
} catch (HttpStatusCodeException e) {
throw new CredHubException(e);
}
}
private void throwExceptionOnError(ResponseEntity<? extends CredHubResponse> response) {
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new CredHubException(response.getStatusCode());
}
if (response.getBody().getErrorMessage() != null) {
throw new CredHubException(response.getBody().getErrorMessage());
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.web.client.RestOperations;
/**
* A callback for executing arbitrary operations on {@link RestOperations}.
*
* @author Mark Paluch
*/
public interface RestOperationsCallback<T> {
/**
* 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.
*/
T doWithRestOperations(RestOperations restOperations);
}

View File

@@ -0,0 +1,70 @@
/*
*
* * 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.AccessLevel;
import lombok.Builder;
import lombok.Data;
import lombok.Setter;
import lombok.Singular;
import java.util.ArrayList;
import java.util.List;
@Data
@Builder
public class AccessControlEntry {
private static final String APP_ACTOR_PREFIX = "mtls-app:";
@Setter(AccessLevel.PRIVATE)
private String actor;
@Singular
private List<Operation> operations;
public List<String> getOperations() {
List<String> operationValues = new ArrayList<String>(operations.size());
for (Operation operation : operations) {
operationValues.add(operation.operation());
}
return operationValues;
}
public static class AccessControlEntryBuilder {
public AccessControlEntryBuilder app(String appId) {
this.actor = APP_ACTOR_PREFIX + appId;
return this;
}
}
public enum Operation {
READ("read"),
WRITE("write");
private final String operation;
Operation(String operation) {
this.operation = operation;
}
public String operation() {
return operation;
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.concurrent.TimeUnit;
/**
* Client options for CredHubConnectivity.
*
* @author Mark Paluch
* @author Scott Frederick
*/
public class ClientOptions {
/**
* Connection timeout;
*/
private final int connectionTimeout;
/**
* Read timeout;
*/
private final int readTimeout;
/**
* Create new {@link ClientOptions} with default timeouts of {@literal 5}
* {@link TimeUnit#SECONDS} connection timeout and {@literal 15}
* {@link TimeUnit#SECONDS} read timeout.
*/
public ClientOptions() {
this((int) TimeUnit.SECONDS.toMillis(5), (int) TimeUnit.SECONDS.toMillis(15));
}
/**
* Create new {@link ClientOptions}.
*
* @param connectionTimeout connection timeout in {@link TimeUnit#MILLISECONDS}, must
* be greater {@literal 0}.
* @param readTimeout read timeout in {@link TimeUnit#MILLISECONDS}, must be greater
* {@literal 0}.
*/
public ClientOptions(int connectionTimeout, int readTimeout) {
this.connectionTimeout = connectionTimeout;
this.readTimeout = readTimeout;
}
/**
* @return the connection timeout in {@link TimeUnit#MILLISECONDS}.
*/
public int getConnectionTimeout() {
return connectionTimeout;
}
/**
* @return the read timeout in {@link TimeUnit#MILLISECONDS}.
*/
public int getReadTimeout() {
return readTimeout;
}
}

View File

@@ -0,0 +1,59 @@
/*
*
* * 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 +
'}';
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2016-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.credhub.support;
import 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 + '\'' +
'}';
}
}
}

View File

@@ -0,0 +1,156 @@
/*
* 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<String, Object> 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 + '\'' +
'}';
}
}
}

View File

@@ -0,0 +1,138 @@
/*
*
* * 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<CredentialData> data;
public CredentialDataResponse() {
}
CredentialDataResponse(String errorMessage) {
super(errorMessage);
}
CredentialDataResponse(List<CredentialData> data) {
super(null);
this.data = data;
}
CredentialDataResponse(String errorMessage, List<CredentialData> data) {
super(errorMessage);
this.data = data;
}
public static CredentialDataResponseBuilder builder() {
return new CredentialDataResponseBuilder();
}
public List<CredentialData> 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<CredentialData> 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<? extends CredentialData> data) {
initData();
this.data.addAll(data);
return this;
}
private void initData() {
if (this.data == null) {
this.data = new ArrayList<CredentialData>();
}
}
public CredentialDataResponse build() {
List<CredentialData> 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<CredentialData>(this.data));
}
return new CredentialDataResponse(errorMessage, data);
}
@Override
public String toString() {
return "CredentialDataResponseBuilder{" +
"errorMessage=" + errorMessage + "," +
"data=" + data +
'}';
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import org.springframework.util.StringUtils;
import java.util.Arrays;
@Data
public class CredentialName {
@JsonIgnore
private final String[] segments;
CredentialName(String name) {
String[] split = name.split("/");
// remove the "/c/" prefix
this.segments = Arrays.copyOfRange(split, 2, split.length);
}
CredentialName(String... segments) {
this.segments = segments;
}
@JsonInclude
public String getName() {
return "/c/" + StringUtils.arrayToDelimitedString(segments, "/");
}
}

View File

@@ -0,0 +1,204 @@
/*
* 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<FoundCredential> foundCredentials;
FindResponse(List<FoundCredential> foundCredentials) {
this.foundCredentials = foundCredentials;
}
public FindResponse(String errorMessage, List<FoundCredential> foundCredentials) {
super(errorMessage);
this.foundCredentials = foundCredentials;
}
public static FindResponseBuilder builder() {
return new FindResponseBuilder();
}
public List<FoundCredential> 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<FoundCredential> foundCredentials;
FindResponseBuilder() {
}
public FindResponse.FindResponseBuilder foundCredential(FoundCredential foundCredential) {
initFoundCredentials();
this.foundCredentials.add(foundCredential);
return this;
}
public FindResponse.FindResponseBuilder foundCredentials(Collection<? extends FoundCredential> foundCredentials) {
initFoundCredentials();
this.foundCredentials.addAll(foundCredentials);
return this;
}
private void initFoundCredentials() {
if (this.foundCredentials == null) {
this.foundCredentials = new ArrayList<FoundCredential>();
}
}
public FindResponse build() {
List<FoundCredential> 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<FoundCredential>(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 + '\'' +
'}';
}
}
}
}

View File

@@ -0,0 +1,32 @@
/*
*
* * 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);
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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 lombok.Builder;
import lombok.Data;
@Data
public class ServiceInstanceCredentialName extends CredentialName {
@Builder
public ServiceInstanceCredentialName(String serviceBrokerName, String serviceOfferingName, String serviceBindingId, String credentialName) {
super(serviceBrokerName, serviceOfferingName, serviceBindingId, credentialName);
}
@Override
public String getName() {
return null;
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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 lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class SimpleCredentialName extends CredentialName {
@Builder
public SimpleCredentialName(String... segments) {
super(segments);
}
public static class SimpleCredentialNameBuilder {
public SimpleCredentialNameBuilder segments(String... segments) {
this.segments = segments;
return this;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* 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.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;
public class SslConfiguration {
private static final char[] KEY_PASSWORD = "keystore".toCharArray();
private static final String CERTIFICATE_NAME = "credhub-cert";
private static final String KEY_NAME = "credhub-key";
private KeyStore trustStore;
private KeyStore keyStore;
public SslConfiguration() {
}
public static SslConfiguration forContainerCert(String instanceCertLocation, String instanceKeyLocation) {
SslConfiguration sslConfiguration = new SslConfiguration();
KeyStore keyStore = sslConfiguration.buildKeyStore(instanceCertLocation, instanceKeyLocation);
sslConfiguration.setKeyStore(keyStore);
sslConfiguration.setTrustStore(keyStore);
return sslConfiguration;
}
public KeyStore getKeyStore() {
return keyStore;
}
private void setKeyStore(KeyStore keyStore) {
this.keyStore = keyStore;
}
public KeyStore getTrustStore() {
return trustStore;
}
private void setTrustStore(KeyStore keyStore) {
this.trustStore = keyStore;
}
public char[] getKeyPassword() {
return KEY_PASSWORD;
}
private KeyStore buildKeyStore(String instanceCertLocation, String instanceKeyLocation) {
Certificate cert = parseCertificate(instanceCertLocation);
PrivateKey key = parsePrivateKey(instanceKeyLocation);
return createKeyStore(cert, key);
}
private Certificate parseCertificate(String certificateLocation) {
try {
PEMParser parser = new PEMParser(new FileReader(certificateLocation));
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);
}
}
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);
}
}
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});
return keystore;
} catch (Exception e) {
throw new IllegalArgumentException("Error creating keystore ", e);
}
}
}

View File

@@ -0,0 +1,46 @@
/*
*
* * 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.JsonCreator;
public enum ValueType {
PASSWORD("password"),
JSON("json");
private final String type;
ValueType(String type) {
this.type = type;
}
public String type() {
return type;
}
@JsonCreator
public static ValueType getTypeByString(String type) {
for (ValueType e : ValueType.values()) {
if (e.type().equals(type)) {
return e;
}
}
return null;
}
}

View File

@@ -0,0 +1,183 @@
/*
*
* * 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 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 static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;
import static org.springframework.credhub.support.ValueType.JSON;
@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
public class WriteRequest extends CredHubRequest {
private boolean overwrite;
private ValueType valueType;
private Object value;
@JsonInclude(NON_EMPTY)
private List<AccessControlEntry> accessControlEntries;
private WriteRequest(CredentialName name, boolean overwrite, Object value, ValueType valueType,
@Singular List<AccessControlEntry> accessControlEntries) {
super(name);
this.overwrite = overwrite;
this.valueType = valueType;
this.value = value;
this.accessControlEntries = accessControlEntries;
}
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;
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;
}
@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);
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<AccessControlEntry> getAccessControlEntries() {
return this.accessControlEntries;
}
public static class WriteRequestBuilder {
private CredentialName name;
private boolean overwrite;
private Object value;
private ValueType valueType;
private ArrayList<AccessControlEntry> accessControlEntries;
WriteRequestBuilder() {
}
public WriteRequestBuilder passwordValue(String value) {
this.valueType = ValueType.PASSWORD;
this.value = value;
return this;
}
public WriteRequestBuilder jsonValue(Map<String, Object> value) {
this.valueType = JSON;
this.value = value;
return this;
}
public WriteRequestBuilder name(CredentialName name) {
this.name = name;
return this;
}
public WriteRequestBuilder overwrite(boolean overwrite) {
this.overwrite = overwrite;
return this;
}
public WriteRequestBuilder accessControlEntry(AccessControlEntry accessControlEntry) {
if (this.accessControlEntries == null)
this.accessControlEntries = new ArrayList<AccessControlEntry>();
this.accessControlEntries.add(accessControlEntry);
return this;
}
public WriteRequestBuilder accessControlEntries(Collection<? extends AccessControlEntry> accessControlEntries) {
if (this.accessControlEntries == null)
this.accessControlEntries = new ArrayList<AccessControlEntry>();
this.accessControlEntries.addAll(accessControlEntries);
return this;
}
public WriteRequest build() {
List<AccessControlEntry> 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<AccessControlEntry>(this.accessControlEntries));
}
return new WriteRequest(name, overwrite, value, valueType, accessControlEntries);
}
@Override
public String toString() {
return "WriteRequestBuilder{" +
"name=" + name +
", overwrite=" + overwrite +
", value=" + value +
", valueType=" + valueType +
", accessControlEntries=" + accessControlEntries +
'}';
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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.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;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;
public class ClientHttpRequestFactoryFactoryTests {
@Test
public void httpComponentsClientCreated() throws Exception {
ClientHttpRequestFactory factory = ClientHttpRequestFactoryFactory.HttpComponents.usingHttpComponents(
new ClientOptions(), new SslConfiguration());
assertThat(factory, instanceOf(HttpComponentsClientHttpRequestFactory.class));
HttpClient httpClient = ((HttpComponentsClientHttpRequestFactory) factory).getHttpClient();
assertThat(httpClient, instanceOf(CloseableHttpClient.class));
((DisposableBean) factory).destroy();
}
}

View File

@@ -0,0 +1,54 @@
/*
*
* * 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.core;
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";
@Mock
private ClientHttpRequestFactory clientHttpRequestFactory;
@Test
public void restTemplateIsCreated() throws Exception {
RestTemplate restTemplate =
CredHubClient.createRestTemplate(CREDHUB_URI, clientHttpRequestFactory);
assertThat(restTemplate.getUriTemplateHandler(), instanceOf(AbstractUriTemplateHandler.class));
AbstractUriTemplateHandler uriTemplateHandler = (AbstractUriTemplateHandler) restTemplate.getUriTemplateHandler();
assertThat(uriTemplateHandler.getBaseUrl(), equalTo(CREDHUB_URI));
}
}

View File

@@ -0,0 +1,269 @@
/*
* 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<WriteRequest>(request), CredentialDataResponse.class))
.thenReturn(new ResponseEntity<CredentialDataResponse>(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<WriteRequest>(request), CredentialDataResponse.class))
.thenReturn(new ResponseEntity<CredentialDataResponse>(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<WriteRequest>(request), CredentialDataResponse.class))
.thenReturn(new ResponseEntity<CredentialDataResponse>(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<CredentialDataResponse>(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<CredentialDataResponse>(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<CredentialDataResponse>(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>(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<FindResponse>(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<FindResponse>(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>(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<FindResponse>(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<FindResponse>(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());
}
}

View File

@@ -0,0 +1,34 @@
/*
*
* * 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 org.junit.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
public class CredHubRequestUnitTests {
@Test
public void generateNameWithAllFields() {
CredHubRequest request = new CredHubRequest(new CredentialName("service-broker-name", "service-offering-name",
"service-binding-id", "credential-name"));
assertThat(request.getName(), equalTo("/c/service-broker-name/service-offering-name/service-binding-id/credential-name"));
}
}

View File

@@ -0,0 +1,120 @@
/*
*
* * 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.databind.ObjectMapper;
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();
@Test
public void deserializationWithPasswordValue() throws Exception {
String json = "{" +
" \"data\": [" +
" {" +
" \"type\": \"password\"," +
" \"version_created_at\": \"2017-04-14T19:37:28Z\"," +
" \"id\": \"80cbb13f-7562-4e72-92de-f3ccf69eaa59\"," +
" \"name\": \"/c/service-broker-name/service-instance-name/binding-id/credentials-json\"," +
" \"value\": \"secret\"" +
" }" +
" ]" +
"}";
CredentialDataResponse response = parseResponse(json);
assertThat(response.getData().size(), equalTo(1));
CredentialData data = response.getData().get(0);
assertThat(data.getValueType(), equalTo(ValueType.PASSWORD));
assertThat(data.getVersionCreatedAt(), equalTo("2017-04-14T19:37:28Z"));
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.getValue(), instanceOf(String.class));
assertThat(data.getValue(), CoreMatchers.<Object>equalTo("secret"));
assertThat(response.getErrorMessage(), nullValue());
}
@Test
public void deserializationWithJsonValue() throws Exception {
String json = "{" +
" \"data\": [" +
" {" +
" \"type\": \"json\"," +
" \"version_created_at\": \"2017-04-14T19:37:28Z\"," +
" \"id\": \"80cbb13f-7562-4e72-92de-f3ccf69eaa59\"," +
" \"name\": \"/c/service-broker-name/service-instance-name/binding-id/credentials-json\"," +
" \"value\": {" +
" \"client_id\": \"test-id\"," +
" \"client_secret\": \"test-secret\"," +
" \"uri\": \"https://example.com\"" +
" }" +
" }" +
" ]" +
"}";
CredentialDataResponse response = parseResponse(json);
assertThat(response.getData().size(), equalTo(1));
CredentialData data = response.getData().get(0);
assertThat(data.getValueType(), equalTo(ValueType.JSON));
assertThat(data.getVersionCreatedAt(), equalTo("2017-04-14T19:37:28Z"));
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.getValue(), instanceOf(Map.class));
Map<String, Object> valueMap = (Map<String, Object>) data.getValue();
assertThat(valueMap.get("client_id"), CoreMatchers.<Object>equalTo("test-id"));
assertThat(valueMap.get("client_secret"), CoreMatchers.<Object>equalTo("test-secret"));
assertThat(valueMap.get("uri"), CoreMatchers.<Object>equalTo("https://example.com"));
assertThat(response.getErrorMessage(), nullValue());
}
@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);
}
}

View File

@@ -0,0 +1,149 @@
/*
*
* * 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.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.valid4j.matchers.jsonpath.JsonPathMatchers.hasJsonPath;
import static org.valid4j.matchers.jsonpath.JsonPathMatchers.hasNoJsonPath;
import static org.valid4j.matchers.jsonpath.JsonPathMatchers.isJson;
public class WriteRequestUnitTests {
private ObjectMapper mapper;
private WriteRequest.WriteRequestBuilder requestBuilder;
@Before
public void setUp() {
mapper = new ObjectMapper();
requestBuilder = WriteRequest.builder()
.name(SimpleCredentialName.builder()
.segments("example", "credential")
.build());
}
@Test
public void typeIsSerializable() {
assertTrue(mapper.canSerialize(WriteRequest.class));
}
@Test
public void serializationWithJsonValue() throws Exception {
requestBuilder
.jsonValue(new HashMap<String, Object>() {{
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, hasNoJsonPath("$.access_control_entries"));
}
@Test
public void serializationWithPasswordValue() throws Exception {
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, hasNoJsonPath("$.access_control_entries"));
}
@Test
public void serializationWithOneAccessControl() throws Exception {
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"))
));
}
@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());
String jsonValue = serializeToJson(requestBuilder);
assertThat(jsonValue, allOf(
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"))
));
}
private String serializeToJson(WriteRequest.WriteRequestBuilder requestBuilder) throws JsonProcessingException {
String jsonValue = mapper.writeValueAsString(requestBuilder.build());
assertThat(jsonValue, isJson());
return jsonValue;
}
}

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-dependencies</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<packaging>pom</packaging>
<name>spring-credhub-dependencies</name>
<description>Spring CredHub Dependencies</description>
<url>http://projects.spring.io/spring-credhub/</url>
<inceptionYear>2017</inceptionYear>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<scm>
<url>https://github.com/spring-projects/spring-credhub</url>
<connection>scm:git:git://github.com/spring-projects/spring-credhub.git</connection>
<developerConnection>scm:git:ssh://git@github.com/spring-projects/spring-credhub.git</developerConnection>
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-credhub/issues</url>
</issueManagement>
<ciManagement>
<system>Bamboo</system>
<url>https://build.spring.io/browse/SPRINGCREDHUB-CREDHUB</url>
</ciManagement>
<developers>
<developer>
<id>sfrederick</id>
<name>Scott Frederick</name>
</developer>
</developers>
<licenses>
<license>
<name>Apache License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<properties>
<jackson.version>2.8.7</jackson.version>
<httpclient.version>4.5.3</httpclient.version>
<bouncycastle.version>1.56</bouncycastle.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring CredHub -->
<dependency>
<groupId>org.springframework.credhub</groupId>
<artifactId>spring-credhub-core</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- HTTP Client Libraries -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<profiles>
<profile>
<id>milestone</id>
<distributionManagement>
<repository>
<id>repo.spring.io</id>
<name>Spring Milestone Repository</name>
<url>http://repo.spring.io/libs-milestone-local</url>
</repository>
</distributionManagement>
</profile>
</profiles>
</project>