Add ReactiveCredHubTemplate. Update OAuth2 support to use Spring
Security 5.1.
This commit is contained in:
@@ -29,10 +29,11 @@ buildscript {
|
||||
}
|
||||
|
||||
ext {
|
||||
springVersion = "5.0.10.RELEASE"
|
||||
springBootVersion = "2.0.6.RELEASE"
|
||||
springVersion = "5.1.2.RELEASE"
|
||||
springBootVersion = "2.1.0.RELEASE"
|
||||
springSecurityVersion = "5.1.1.RELEASE"
|
||||
springCloudConnectorsVersion = "1.2.5.RELEASE"
|
||||
reactorVersion = "Bismuth-SR13"
|
||||
reactorVersion = "Californium-SR2"
|
||||
|
||||
junitVersion = "4.12"
|
||||
mockitoVersion = "2.7.22"
|
||||
@@ -44,6 +45,7 @@ ext {
|
||||
'http://docs.spring.io/spring/docs/current/javadoc-api/',
|
||||
] as String[]
|
||||
}
|
||||
ext['spring-security.version'] = springSecurityVersion
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
|
||||
@@ -31,11 +31,10 @@ dependencies {
|
||||
compile("com.fasterxml.jackson.core:jackson-databind:2.9.7")
|
||||
|
||||
optional("org.springframework:spring-webflux")
|
||||
optional("io.projectreactor.ipc:reactor-netty")
|
||||
optional("io.projectreactor.netty:reactor-netty")
|
||||
|
||||
optional("org.springframework.security.oauth:spring-security-oauth2:2.0.14.RELEASE") {
|
||||
exclude(group: 'org.springframework')
|
||||
}
|
||||
optional("org.springframework.security:spring-security-config:${springSecurityVersion}")
|
||||
optional("org.springframework.security:spring-security-oauth2-client:${springSecurityVersion}")
|
||||
|
||||
optional("org.apache.httpcomponents:httpclient:4.5.3") {
|
||||
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||
@@ -44,6 +43,7 @@ dependencies {
|
||||
optional("io.netty:netty-all:4.1.30.Final")
|
||||
|
||||
testImplementation("org.springframework:spring-test")
|
||||
testImplementation("io.projectreactor:reactor-test")
|
||||
testImplementation("junit:junit")
|
||||
testImplementation("org.mockito:mockito-core")
|
||||
testImplementation("org.assertj:assertj-core:${assertJVersion}")
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2017-2018 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 io.netty.handler.ssl.SslContextBuilder;
|
||||
import io.netty.handler.ssl.SslProvider;
|
||||
import org.springframework.credhub.support.ClientOptions;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import reactor.netty.http.client.HttpClient;
|
||||
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
/**
|
||||
* Factory for {@link ClientHttpConnector} that supports {@link ReactorClientHttpConnector}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ClientHttpConnectorFactory {
|
||||
|
||||
private static SslCertificateUtils sslCertificateUtils = new SslCertificateUtils();
|
||||
|
||||
/**
|
||||
* Create a {@link ClientHttpConnector} for the given {@link ClientOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}
|
||||
* @return a new {@link ClientHttpConnector}.
|
||||
*/
|
||||
public static ClientHttpConnector create(ClientOptions options) {
|
||||
HttpClient httpClient = HttpClient.create();
|
||||
|
||||
if (usingCustomCerts(options)) {
|
||||
TrustManagerFactory trustManagerFactory =
|
||||
sslCertificateUtils.createTrustManagerFactory(options.getCaCertFiles());
|
||||
|
||||
httpClient.secure(sslContextSpec -> sslContextSpec
|
||||
.sslContext(SslContextBuilder.forClient()
|
||||
.sslProvider(SslProvider.JDK)
|
||||
.trustManager(trustManagerFactory)));
|
||||
} else {
|
||||
httpClient.secure(sslContextSpec -> sslContextSpec
|
||||
.sslContext(SslContextBuilder.forClient()
|
||||
.sslProvider(SslProvider.JDK)));
|
||||
}
|
||||
|
||||
if (options.getConnectionTimeout() != null) {
|
||||
// httpClient.sslHandshakeTimeout(options.getConnectionTimeout());
|
||||
// httpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
// Math.toIntExact(options.getConnectionTimeout().toMillis()));
|
||||
}
|
||||
|
||||
return new ReactorClientHttpConnector(httpClient);
|
||||
}
|
||||
|
||||
private static boolean usingCustomCerts(ClientOptions options) {
|
||||
return options.getCaCertFiles() != null;
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,15 @@ package org.springframework.credhub.configuration;
|
||||
|
||||
import org.springframework.credhub.core.CredHubProperties;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.core.ReactiveCredHubTemplate;
|
||||
import org.springframework.credhub.support.ClientOptions;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
|
||||
/**
|
||||
* Factory for {@link CredHubTemplate} used to communicate with CredHub.
|
||||
@@ -29,9 +36,34 @@ import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
*/
|
||||
public class CredHubTemplateFactory {
|
||||
|
||||
/**
|
||||
* Create a {@link CredHubTemplate} for interaction with a CredHub server.
|
||||
*
|
||||
* @param credHubProperties connection properties
|
||||
* @param clientHttpRequestFactory a factory for HTTP connections
|
||||
* @return a {@code CredHubTemplate}
|
||||
*/
|
||||
public CredHubTemplate credHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
return new CredHubTemplate(credHubProperties.getUrl(), clientHttpRequestFactory);
|
||||
return new CredHubTemplate(credHubProperties, clientHttpRequestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link CredHubTemplate} for interaction with a CredHub server
|
||||
* using OAuth2 for authentication.
|
||||
*
|
||||
* @param credHubProperties connection properties
|
||||
* @param clientHttpRequestFactory a factory for HTTP connections
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientService a repository of authorized OAuth2 clients
|
||||
* @return a {@code CredHubTemplate}
|
||||
*/
|
||||
public CredHubTemplate credHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
ClientRegistrationRepository clientRegistrationRepository,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
return new CredHubTemplate(credHubProperties, clientHttpRequestFactory,
|
||||
clientRegistrationRepository, authorizedClientService);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,6 +75,46 @@ public class CredHubTemplateFactory {
|
||||
return ClientHttpRequestFactoryFactory.create(new ClientOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ReactiveCredHubTemplate} for interaction with a CredHub server.
|
||||
*
|
||||
* @param credHubProperties connection properties
|
||||
* @param clientHttpConnector a factory for HTTP connections
|
||||
* @return a {@code ReactiveCredHubTemplate}
|
||||
*/
|
||||
public ReactiveCredHubTemplate credHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpConnector clientHttpConnector) {
|
||||
return new ReactiveCredHubTemplate(credHubProperties, clientHttpConnector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ReactiveCredHubTemplate} for interaction with a CredHub server
|
||||
* using OAuth2 for authentication.
|
||||
*
|
||||
* @param credHubProperties connection properties
|
||||
* @param clientHttpConnector a factory for HTTP connections
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientRepository a repository of OAuth2 client authorizations
|
||||
* @return a {@code ReactiveCredHubTemplate}
|
||||
*/
|
||||
public ReactiveCredHubOperations credHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpConnector clientHttpConnector,
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository,
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
return new ReactiveCredHubTemplate(credHubProperties, clientHttpConnector,
|
||||
clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @param clientOptions options for creating the client connection
|
||||
* @return the {@link ClientHttpRequestFactory} instance.
|
||||
*/
|
||||
public ClientHttpConnector clientHttpConnector(ClientOptions clientOptions) {
|
||||
return ClientHttpConnectorFactory.create(clientOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.credhub.configuration;
|
||||
|
||||
import org.springframework.credhub.core.CredHubProperties;
|
||||
import org.springframework.credhub.core.OAuth2CredHubTemplate;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
|
||||
/**
|
||||
* Factory for {@link OAuth2CredHubTemplate} used to communicate with CredHub.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class OAuth2CredHubTemplateFactory {
|
||||
|
||||
public OAuth2CredHubTemplate credHubTemplate(OAuth2ProtectedResourceDetails resource,
|
||||
CredHubProperties credHubProperties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
return new OAuth2CredHubTemplate(resource, credHubProperties.getUrl(),
|
||||
clientHttpRequestFactory);
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2013-2017 the original author or authors.
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.credhub.core;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.credhub.support.utils.JsonUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.support.HttpRequestWrapper;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.DefaultUriTemplateHandler;
|
||||
import org.springframework.web.util.UriTemplateHandler;
|
||||
|
||||
/**
|
||||
* Factory for creating a {@link RestTemplate} configured for communication with
|
||||
* a CredHub server.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
class CredHubClientFactory {
|
||||
/**
|
||||
* Create a {@link RestTemplate} configured for communication with a CredHub server.
|
||||
*
|
||||
* @param baseUri the base URI for the CredHub server
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* @return a configured {@link RestTemplate}
|
||||
*/
|
||||
static RestTemplate createRestTemplate(String baseUri,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
configureRestTemplate(restTemplate, baseUri, clientHttpRequestFactory);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a {@link RestTemplate} for communication with a CredHub server.
|
||||
*
|
||||
* @param restTemplate an existing {@link RestTemplate} to configure
|
||||
* @param baseUri the base URI for the CredHub server
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
*/
|
||||
static void configureRestTemplate(RestTemplate restTemplate, String baseUri,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||
restTemplate.setUriTemplateHandler(createUriTemplateHandler(baseUri));
|
||||
restTemplate.setMessageConverters(createMessageConverters());
|
||||
restTemplate.setInterceptors(createInterceptors());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link UriTemplateHandler} that prefixes all {@link RestTemplate} calls
|
||||
* with the configured {@literal baseUri}.
|
||||
*
|
||||
* @param baseUri the base URI for the CredHub server
|
||||
* @return a configured {@link UriTemplateHandler}
|
||||
*/
|
||||
private static DefaultUriTemplateHandler createUriTemplateHandler(String baseUri) {
|
||||
DefaultUriTemplateHandler uriTemplateHandler = new DefaultUriTemplateHandler();
|
||||
uriTemplateHandler.setBaseUrl(baseUri);
|
||||
return uriTemplateHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link HttpMessageConverter}s necessary to build request to
|
||||
* and parse responses from CredHub.
|
||||
*
|
||||
* @return the list of {@link HttpMessageConverter}s
|
||||
*/
|
||||
private static List<HttpMessageConverter<?>> createMessageConverters() {
|
||||
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(3);
|
||||
messageConverters.add(new ByteArrayHttpMessageConverter());
|
||||
messageConverters.add(new StringHttpMessageConverter());
|
||||
messageConverters.add(new MappingJackson2HttpMessageConverter(JsonUtils.buildObjectMapper()));
|
||||
|
||||
return messageConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link ClientHttpRequestInterceptor} necessary to configure requests and responses.
|
||||
*
|
||||
* @return the list of {@link ClientHttpRequestInterceptor}s
|
||||
*/
|
||||
private static List<ClientHttpRequestInterceptor> createInterceptors() {
|
||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>(1);
|
||||
interceptors.add(new CredHubRequestInterceptor());
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* A request interceptor that sets headers common to all CredHub requests.
|
||||
*/
|
||||
private static class CredHubRequestInterceptor implements ClientHttpRequestInterceptor {
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
|
||||
|
||||
HttpHeaders headers = requestWrapper.getHeaders();
|
||||
headers.setAccept(singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
return execution.execute(requestWrapper, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.credhub.core;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
|
||||
@@ -25,7 +24,7 @@ import org.springframework.web.client.HttpStatusCodeException;
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class CredHubException extends NestedRuntimeException {
|
||||
public class CredHubException extends HttpStatusCodeException {
|
||||
/**
|
||||
* Create a new exception with the provided root cause.
|
||||
*
|
||||
@@ -33,8 +32,7 @@ public class CredHubException extends NestedRuntimeException {
|
||||
* with CredHub
|
||||
*/
|
||||
public CredHubException(HttpStatusCodeException e) {
|
||||
super("Error calling CredHub: " + e.getStatusCode() + ": "
|
||||
+ e.getResponseBodyAsString());
|
||||
super(e.getStatusCode(), e.getStatusText(), e.getResponseHeaders(), e.getResponseBodyAsByteArray(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,6 +42,6 @@ public class CredHubException extends NestedRuntimeException {
|
||||
* communicate with CredHub
|
||||
*/
|
||||
public CredHubException(HttpStatus statusCode) {
|
||||
super("Error calling CredHub: " + statusCode);
|
||||
super(statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.support.HttpRequestWrapper;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.endpoint.DefaultClientCredentialsTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A request interceptor that sets OAuth2 bearer authentication headers to all CredHub requests.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class CredHubOAuth2RequestInterceptor implements ClientHttpRequestInterceptor {
|
||||
private final ClientRegistration clientRegistration;
|
||||
private final OAuth2AuthorizedClientService authorizedClientService;
|
||||
|
||||
private final DefaultClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient;
|
||||
|
||||
private final Clock clock = Clock.systemUTC();
|
||||
private final Duration accessTokenExpiresSkew = Duration.ofMinutes(1);
|
||||
|
||||
CredHubOAuth2RequestInterceptor(RestOperations tokenServerRestTemplate,
|
||||
ClientRegistration clientRegistration,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
this.clientRegistration = clientRegistration;
|
||||
this.authorizedClientService = authorizedClientService;
|
||||
|
||||
this.clientCredentialsTokenResponseClient = createClientCredentialsTokenResponseClient(tokenServerRestTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an OAuth2 bearer token header to each request.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
|
||||
|
||||
HttpHeaders headers = requestWrapper.getHeaders();
|
||||
headers.setBearerAuth(getAccessToken().getTokenValue());
|
||||
|
||||
return execution.execute(requestWrapper, body);
|
||||
}
|
||||
|
||||
private OAuth2AccessToken getAccessToken() {
|
||||
OAuth2AuthorizedClient client = authorizedClientService
|
||||
.loadAuthorizedClient(clientRegistration.getRegistrationId(), clientRegistration.getClientId());
|
||||
|
||||
if (client == null || tokenExpiring(client)) {
|
||||
client = authorizeClient();
|
||||
}
|
||||
|
||||
return client.getAccessToken();
|
||||
}
|
||||
|
||||
private OAuth2AuthorizedClient authorizeClient() {
|
||||
OAuth2ClientCredentialsGrantRequest request =
|
||||
new OAuth2ClientCredentialsGrantRequest(clientRegistration);
|
||||
OAuth2AccessTokenResponse tokenResponse = clientCredentialsTokenResponseClient.getTokenResponse(request);
|
||||
|
||||
OAuth2AccessToken accessToken = tokenResponse.getAccessToken();
|
||||
OAuth2RefreshToken refreshToken = tokenResponse.getRefreshToken();
|
||||
|
||||
OAuth2AuthorizedClient authorizedClient =
|
||||
new OAuth2AuthorizedClient(clientRegistration,
|
||||
clientRegistration.getClientId(),
|
||||
accessToken, refreshToken);
|
||||
|
||||
saveAuthorizedClient(clientRegistration, accessToken, authorizedClient);
|
||||
|
||||
return authorizedClient;
|
||||
}
|
||||
|
||||
private boolean tokenExpiring(OAuth2AuthorizedClient client) {
|
||||
Instant now = this.clock.instant();
|
||||
Instant expiresAt = client.getAccessToken().getExpiresAt();
|
||||
if (expiresAt != null && now.isAfter(expiresAt.minus(this.accessTokenExpiresSkew))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void saveAuthorizedClient(ClientRegistration clientRegistration,
|
||||
OAuth2AccessToken accessToken,
|
||||
OAuth2AuthorizedClient authorizedClient) {
|
||||
OAuth2ClientCredentialsGrantAuthenticationToken authentication =
|
||||
new OAuth2ClientCredentialsGrantAuthenticationToken(clientRegistration, accessToken);
|
||||
authorizedClientService.saveAuthorizedClient(authorizedClient, authentication);
|
||||
}
|
||||
|
||||
private static DefaultClientCredentialsTokenResponseClient createClientCredentialsTokenResponseClient(RestOperations restTemplate) {
|
||||
DefaultClientCredentialsTokenResponseClient clientCredentialsTokenResponseClient =
|
||||
new DefaultClientCredentialsTokenResponseClient();
|
||||
clientCredentialsTokenResponseClient.setRestOperations(restTemplate);
|
||||
return clientCredentialsTokenResponseClient;
|
||||
}
|
||||
|
||||
private static class OAuth2ClientCredentialsGrantAuthenticationToken extends AbstractAuthenticationToken {
|
||||
private final ClientRegistration clientRegistration;
|
||||
private final OAuth2AccessToken accessToken;
|
||||
|
||||
OAuth2ClientCredentialsGrantAuthenticationToken(ClientRegistration clientRegistration,
|
||||
OAuth2AccessToken accessToken) {
|
||||
super(Collections.emptyList());
|
||||
this.clientRegistration = clientRegistration;
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return accessToken.getTokenValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return this.clientRegistration.getClientId();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,22 +26,12 @@ package org.springframework.credhub.core;
|
||||
*/
|
||||
public class CredHubProperties {
|
||||
private String url;
|
||||
private OAuth2 oauth2;
|
||||
|
||||
/**
|
||||
* Create a new instance without initializing properties.
|
||||
*/
|
||||
public CredHubProperties() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance with the provided properties. Intended to be used internally
|
||||
* for testing.
|
||||
*
|
||||
* @param url the base URI for the CredHub server
|
||||
*/
|
||||
CredHubProperties(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,4 +53,53 @@ public class CredHubProperties {
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OAuth2 properties.
|
||||
*
|
||||
* @return the OAuth2 properties.
|
||||
*/
|
||||
public OAuth2 getOauth2() {
|
||||
return oauth2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the OAuth2 properties.
|
||||
*
|
||||
* @param oauth2 the OAuth2 properties
|
||||
*/
|
||||
public void setOauth2(OAuth2 oauth2) {
|
||||
this.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Properties containing OAuth2 credentials for CredHub connectivity.
|
||||
*/
|
||||
public static class OAuth2 {
|
||||
private String clientId;
|
||||
|
||||
/**
|
||||
* Create a new instance without initializing properties.
|
||||
*/
|
||||
public OAuth2() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the OAuth2 client ID used to authenticate with CredHub.
|
||||
*
|
||||
* @return the OAuth2 client ID
|
||||
*/
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the OAuth2 client ID used to authentiate with CredHub.
|
||||
*
|
||||
* @param clientId the OAuth2 client ID
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 static java.util.Collections.singletonList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.credhub.support.utils.JsonUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.support.HttpRequestWrapper;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.FormHttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
|
||||
/**
|
||||
* Factory for creating a {@link RestTemplate} configured for communication with
|
||||
* a CredHub server.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
class CredHubRestTemplateFactory {
|
||||
|
||||
/**
|
||||
* Create a {@link RestTemplate} configured for communication with a CredHub server.
|
||||
*
|
||||
* @param properties CredHub connection properties
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* @return a configured {@link RestTemplate}
|
||||
*/
|
||||
static RestTemplate createRestTemplate(CredHubProperties properties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
configureRestTemplate(restTemplate, properties.getUrl(), clientHttpRequestFactory);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link RestTemplate} configured for communication with a CredHub server.
|
||||
*
|
||||
* @param properties CredHub connection properties
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientService a repository of authorized OAuth2 clients
|
||||
* @return a configured {@link RestTemplate}
|
||||
*/
|
||||
static RestTemplate createRestTemplate(CredHubProperties properties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
ClientRegistrationRepository clientRegistrationRepository,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
configureRestTemplate(restTemplate, properties.getUrl(), clientHttpRequestFactory);
|
||||
configureOAuth2(restTemplate, clientHttpRequestFactory,
|
||||
properties.getOauth2().getClientId(),
|
||||
clientRegistrationRepository,
|
||||
authorizedClientService);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a {@link RestTemplate} for communication with a CredHub server.
|
||||
*
|
||||
* @param restTemplate an existing {@link RestTemplate} to configure
|
||||
* @param baseUri the base URI for the CredHub server
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
*/
|
||||
private static void configureRestTemplate(RestTemplate restTemplate, String baseUri,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(baseUri));
|
||||
restTemplate.getInterceptors().add(new CredHubRequestInterceptor());
|
||||
restTemplate.setMessageConverters(Arrays.asList(
|
||||
new ByteArrayHttpMessageConverter(),
|
||||
new StringHttpMessageConverter(),
|
||||
new MappingJackson2HttpMessageConverter(JsonUtils.buildObjectMapper())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure OAuth2 features of a {@link RestTemplate}.
|
||||
*
|
||||
* @param restTemplate an existing {@link RestTemplate} to configure
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* @param clientId the OAuth2 client ID for authentication
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientService a repository of authorized OAuth2 clients
|
||||
*/
|
||||
private static void configureOAuth2(RestTemplate restTemplate,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
String clientId,
|
||||
ClientRegistrationRepository clientRegistrationRepository,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
ClientRegistration clientRegistration = clientRegistrationRepository.findByRegistrationId(clientId);
|
||||
|
||||
RestOperations tokenServerRestTemplate = createTokenServerRestTemplate(clientHttpRequestFactory);
|
||||
|
||||
restTemplate.getInterceptors()
|
||||
.add(new CredHubOAuth2RequestInterceptor(tokenServerRestTemplate,
|
||||
clientRegistration, authorizedClientService));
|
||||
}
|
||||
|
||||
private static RestTemplate createTokenServerRestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
RestTemplate restOperations = new RestTemplate(Arrays.asList(
|
||||
new FormHttpMessageConverter(),
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter()));
|
||||
restOperations.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
|
||||
restOperations.setRequestFactory(clientHttpRequestFactory);
|
||||
return restOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* A request interceptor that sets headers common to all CredHub requests.
|
||||
*/
|
||||
private static class CredHubRequestInterceptor implements ClientHttpRequestInterceptor {
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
|
||||
|
||||
HttpHeaders headers = requestWrapper.getHeaders();
|
||||
headers.setAccept(singletonList(MediaType.APPLICATION_JSON));
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
return execution.execute(requestWrapper, body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import org.springframework.credhub.core.permission.CredHubPermissionTemplate;
|
||||
import org.springframework.credhub.core.permissionV2.CredHubPermissionV2Operations;
|
||||
import org.springframework.credhub.core.permissionV2.CredHubPermissionV2Template;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -54,22 +56,43 @@ public class CredHubTemplate implements CredHubOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CredHubTemplate} using the provided base URI and
|
||||
* Create a new {@link CredHubTemplate} using the provided connection properties and
|
||||
* {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @param apiUriBase the base URI for the CredHub server (scheme, host, and port);
|
||||
* must not be {@literal null}
|
||||
* @param properties CredHub connection properties; must not be {@literal null}
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* creating new connections
|
||||
*/
|
||||
public CredHubTemplate(String apiUriBase, ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
Assert.notNull(apiUriBase, "apiUriBase must not be null");
|
||||
public CredHubTemplate(CredHubProperties properties, ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
Assert.notNull(properties, "properties must not be null");
|
||||
Assert.notNull(clientHttpRequestFactory, "clientHttpRequestFactory must not be null");
|
||||
|
||||
this.restTemplate = CredHubClientFactory.createRestTemplate(apiUriBase,
|
||||
this.restTemplate = CredHubRestTemplateFactory.createRestTemplate(properties,
|
||||
clientHttpRequestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CredHubTemplate} using the provided connection properties,
|
||||
* {@link ClientHttpRequestFactory}, and OAuth2 support.
|
||||
*
|
||||
* @param properties CredHub connection properties; must not be {@literal null}
|
||||
* @param clientHttpRequestFactory the {@link ClientHttpRequestFactory} to use when
|
||||
* creating new connections
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientService a repository of authorized OAuth2 clients
|
||||
*/
|
||||
public CredHubTemplate(CredHubProperties properties,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
ClientRegistrationRepository clientRegistrationRepository,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
Assert.notNull(properties, "properties must not be null");
|
||||
Assert.notNull(clientHttpRequestFactory, "clientHttpRequestFactory must not be null");
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository must not be null");
|
||||
|
||||
this.restTemplate = CredHubRestTemplateFactory.createRestTemplate(properties,
|
||||
clientHttpRequestFactory, clientRegistrationRepository, authorizedClientService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for saving, retrieving, and deleting credentials.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.credhub.security.oauth2.client.endpoint.WebClientReactiveClientCredentialsTokenResponseClient;
|
||||
import org.springframework.credhub.support.utils.JsonUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.codec.CodecConfigurer;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
|
||||
|
||||
/**
|
||||
* Factory for creating a {@link WebClient} configured for communication with
|
||||
* a CredHub server.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class CredHubWebClientFactory {
|
||||
/**
|
||||
* Create a {@link WebClient} configured for communication with a CredHub server.
|
||||
*
|
||||
* @param properties CredHub connection properties
|
||||
* @param clientHttpConnector the {@link ClientHttpConnector} to use when
|
||||
* creating new connections
|
||||
* @return a configured {@link WebClient}
|
||||
*/
|
||||
static WebClient createWebClient(CredHubProperties properties,
|
||||
ClientHttpConnector clientHttpConnector) {
|
||||
return buildWebClient(properties.getUrl(), clientHttpConnector)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link WebClient} configured for communication with a CredHub server.
|
||||
*
|
||||
* @param properties CredHub connection properties
|
||||
* @param clientHttpConnector the {@link ClientHttpConnector} to use when
|
||||
* creating new connections
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientRepository a repository of OAuth2 authorized clients
|
||||
* @return a configured {@link WebClient}
|
||||
*/
|
||||
static WebClient createWebClient(CredHubProperties properties, ClientHttpConnector clientHttpConnector,
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository,
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
WebClientReactiveClientCredentialsTokenResponseClient tokenResponseClient =
|
||||
new WebClientReactiveClientCredentialsTokenResponseClient();
|
||||
tokenResponseClient.setWebClient(WebClient.builder()
|
||||
.clientConnector(clientHttpConnector)
|
||||
.build());
|
||||
|
||||
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
|
||||
new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository,
|
||||
authorizedClientRepository);
|
||||
oauth.setClientCredentialsTokenResponseClient(tokenResponseClient);
|
||||
|
||||
return buildWebClient(properties.getUrl(), clientHttpConnector)
|
||||
.filter(oauth)
|
||||
.defaultRequest(requestHeadersSpec ->
|
||||
requestHeadersSpec.attributes(clientRegistrationId(properties.getOauth2().getClientId())))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static WebClient.Builder buildWebClient(String baseUri, ClientHttpConnector clientHttpConnector) {
|
||||
ExchangeStrategies strategies = ExchangeStrategies.builder()
|
||||
.codecs(configurer -> {
|
||||
ObjectMapper mapper = JsonUtils.buildObjectMapper();
|
||||
|
||||
CodecConfigurer.DefaultCodecs dc = configurer.defaultCodecs();
|
||||
dc.jackson2JsonDecoder(new Jackson2JsonDecoder(mapper));
|
||||
dc.jackson2JsonEncoder(new Jackson2JsonEncoder(mapper));
|
||||
}).build();
|
||||
|
||||
return WebClient.builder()
|
||||
.clientConnector(clientHttpConnector)
|
||||
.baseUrl(baseUri)
|
||||
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
|
||||
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.exchangeStrategies(strategies);
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,9 @@ package org.springframework.credhub.core;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
public class ExceptionUtils {
|
||||
/**
|
||||
@@ -32,4 +35,14 @@ public class ExceptionUtils {
|
||||
throw new CredHubException(response.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to return an appropriate error if a request to CredHub
|
||||
* returns with an error code.
|
||||
*
|
||||
* @param response a {@link ClientResponse} returned from {@link WebClient}
|
||||
*/
|
||||
public static Mono<Throwable> buildError(ClientResponse response) {
|
||||
return Mono.error(new CredHubException(response.statusCode()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.springframework.credhub.core;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Superclass of {@link CredHubTemplate}. Provides a pre configured
|
||||
* {@link OAuth2RestTemplate} for CredHub.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
*
|
||||
*/
|
||||
public class OAuth2CredHubTemplate extends CredHubTemplate {
|
||||
|
||||
public OAuth2CredHubTemplate(OAuth2ProtectedResourceDetails resource,
|
||||
String apiUriBase, ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
super(buildRestTemplate(resource, apiUriBase, clientHttpRequestFactory));
|
||||
}
|
||||
|
||||
private static RestTemplate buildRestTemplate(OAuth2ProtectedResourceDetails resource,
|
||||
String apiUriBase, ClientHttpRequestFactory clientHttpRequestFactory) {
|
||||
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource);
|
||||
|
||||
CredHubClientFactory.configureRestTemplate(restTemplate, apiUriBase,
|
||||
clientHttpRequestFactory);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.reactivestreams.Publisher;
|
||||
import org.springframework.credhub.core.certificate.ReactiveCredHubCertificateOperations;
|
||||
import org.springframework.credhub.core.credential.ReactiveCredHubCredentialOperations;
|
||||
import org.springframework.credhub.core.info.ReactiveCredHubInfoOperations;
|
||||
import org.springframework.credhub.core.interpolation.ReactiveCredHubInterpolationOperations;
|
||||
import org.springframework.credhub.core.permission.ReactiveCredHubPermissionOperations;
|
||||
import org.springframework.credhub.core.permissionV2.ReactiveCredHubPermissionV2Operations;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Specifies the main interaction with CredHub.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubOperations {
|
||||
/**
|
||||
* Get the operations for saving, retrieving, and deleting credentials.
|
||||
*
|
||||
* @return the credentials operations
|
||||
*/
|
||||
ReactiveCredHubCredentialOperations credentials();
|
||||
|
||||
/**
|
||||
* Get the operations for adding, retrieving, and deleting credential permissions.
|
||||
*
|
||||
* @return the permissions operations
|
||||
*/
|
||||
ReactiveCredHubPermissionOperations permissions();
|
||||
|
||||
/**
|
||||
* Get the operations for adding, retrieving, and deleting credential permissions.
|
||||
*
|
||||
* @return the permissions operations
|
||||
*/
|
||||
ReactiveCredHubPermissionV2Operations permissionsV2();
|
||||
|
||||
/**
|
||||
* Get the operations for retrieving, regenerating, and updating certificates.
|
||||
*
|
||||
* @return the certificates operations
|
||||
*/
|
||||
ReactiveCredHubCertificateOperations certificates();
|
||||
|
||||
/**
|
||||
* Get the operations for interpolating service binding credentials.
|
||||
*
|
||||
* @return the interpolation operations
|
||||
*/
|
||||
ReactiveCredHubInterpolationOperations interpolation();
|
||||
|
||||
/**
|
||||
* Get the operations for retrieving CredHub server information.
|
||||
*
|
||||
* @return the info operations
|
||||
*/
|
||||
ReactiveCredHubInfoOperations info();
|
||||
|
||||
/**
|
||||
* Allow interaction with the configured {@link WebClient} not provided
|
||||
* by other methods.
|
||||
*
|
||||
* @param callback wrapper for the callback method
|
||||
* @param <V> the publisher type
|
||||
* @param <T> the credential implementation type
|
||||
* @return the return value from the callback method
|
||||
*/
|
||||
<V, T extends Publisher<V>> T doWithWebClient(Function<WebClient, ? extends T> callback);
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.reactivestreams.Publisher;
|
||||
import org.springframework.credhub.core.certificate.ReactiveCredHubCertificateOperations;
|
||||
import org.springframework.credhub.core.certificate.ReactiveCredHubCertificateTemplate;
|
||||
import org.springframework.credhub.core.credential.ReactiveCredHubCredentialOperations;
|
||||
import org.springframework.credhub.core.credential.ReactiveCredHubCredentialTemplate;
|
||||
import org.springframework.credhub.core.info.ReactiveCredHubInfoOperations;
|
||||
import org.springframework.credhub.core.info.ReactiveCredHubInfoTemplate;
|
||||
import org.springframework.credhub.core.interpolation.ReactiveCredHubInterpolationOperations;
|
||||
import org.springframework.credhub.core.interpolation.ReactiveCredHubInterpolationTemplate;
|
||||
import org.springframework.credhub.core.permission.ReactiveCredHubPermissionOperations;
|
||||
import org.springframework.credhub.core.permission.ReactiveCredHubPermissionTemplate;
|
||||
import org.springframework.credhub.core.permissionV2.ReactiveCredHubPermissionV2Operations;
|
||||
import org.springframework.credhub.core.permissionV2.ReactiveCredHubPermissionV2Template;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Implements the main interaction with CredHub.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubTemplate implements ReactiveCredHubOperations {
|
||||
private final WebClient webClient;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubTemplate} using the provided {@link WebClient}.
|
||||
* Intended for internal testing only.
|
||||
*
|
||||
* @param webClient the {@link WebClient} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubTemplate(WebClient webClient) {
|
||||
Assert.notNull(webClient, "webClient must not be null");
|
||||
|
||||
this.webClient = webClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubTemplate} using the provided base URI and
|
||||
* {@link ClientHttpRequestFactory}.
|
||||
*
|
||||
* @param credHubProperties connection properties for the CredHub server
|
||||
* @param clientHttpConnector the {@link ClientHttpConnector} to use when
|
||||
* creating new connections
|
||||
*/
|
||||
public ReactiveCredHubTemplate(CredHubProperties credHubProperties, ClientHttpConnector clientHttpConnector) {
|
||||
Assert.notNull(credHubProperties, "credHubProperties must not be null");
|
||||
Assert.notNull(clientHttpConnector, "clientHttpConnector must not be null");
|
||||
|
||||
this.webClient = CredHubWebClientFactory.createWebClient(credHubProperties, clientHttpConnector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubTemplate} using the provided base URI and
|
||||
* {@link ClientHttpRequestFactory}.
|
||||
* @param credHubProperties connection properties for the CredHub server
|
||||
* @param clientHttpConnector the {@link ClientHttpConnector} to use when
|
||||
* creating new connections
|
||||
*/
|
||||
public ReactiveCredHubTemplate(CredHubProperties credHubProperties, ClientHttpConnector clientHttpConnector,
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository,
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
Assert.notNull(credHubProperties, "credHubProperties must not be null");
|
||||
Assert.notNull(clientHttpConnector, "clientHttpConnector must not be null");
|
||||
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository must not be null");
|
||||
Assert.notNull(authorizedClientRepository, "authorizedClientRepository must not be null");
|
||||
|
||||
this.webClient = CredHubWebClientFactory.createWebClient(credHubProperties, clientHttpConnector,
|
||||
clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for saving, retrieving, and deleting credentials.
|
||||
*
|
||||
* @return the credentials operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubCredentialOperations credentials() {
|
||||
return new ReactiveCredHubCredentialTemplate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for adding, retrieving, and deleting permissions from a credential.
|
||||
*
|
||||
* @return the permissions operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubPermissionOperations permissions() {
|
||||
return new ReactiveCredHubPermissionTemplate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for adding, retrieving, and deleting permissions from a credential.
|
||||
*
|
||||
* @return the permissions operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubPermissionV2Operations permissionsV2() {
|
||||
return new ReactiveCredHubPermissionV2Template(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for retrieving, regenerating, and updating certificates.
|
||||
*
|
||||
* @return the certificates operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubCertificateOperations certificates() {
|
||||
return new ReactiveCredHubCertificateTemplate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for interpolating service binding credentials.
|
||||
*
|
||||
* @return the interpolation operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubInterpolationOperations interpolation() {
|
||||
return new ReactiveCredHubInterpolationTemplate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operations for retrieving CredHub server information.
|
||||
*
|
||||
* @return the info operations
|
||||
*/
|
||||
@Override
|
||||
public ReactiveCredHubInfoOperations info() {
|
||||
return new ReactiveCredHubInfoTemplate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow interaction with the configured {@link WebClient} not provided
|
||||
* by other methods.
|
||||
*
|
||||
* @param callback wrapper for the callback method
|
||||
* @param <T> the credential implementation type
|
||||
* @return the return value from the callback method
|
||||
*/
|
||||
@Override
|
||||
public <V, T extends Publisher<V>> T doWithWebClient(Function<WebClient, ? extends T> callback) {
|
||||
Assert.notNull(callback, "callback must not be null");
|
||||
|
||||
try {
|
||||
return callback.apply(webClient);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new CredHubException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.certificate;
|
||||
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.certificate.CertificateCredentialDetails;
|
||||
import org.springframework.credhub.support.certificate.CertificateSummary;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Specifies the interactions with CredHub to retrieve, regenerate, and update
|
||||
* certificates.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubCertificateOperations {
|
||||
/**
|
||||
* Retrieve all certificates from CredHub.
|
||||
*
|
||||
* @return a collection of certificates
|
||||
*/
|
||||
Flux<CertificateSummary> getAll();
|
||||
|
||||
/**
|
||||
* Retrieve a certificate using its name.
|
||||
*
|
||||
* @param name the name of the certificate credential; must not be {@literal null}
|
||||
* @return the details of the retrieved certificate credential
|
||||
*/
|
||||
Mono<CertificateSummary> getByName(final CredentialName name);
|
||||
|
||||
/**
|
||||
* Regenerate a certificate.
|
||||
*
|
||||
* @param id the CredHub-generated ID of the certificate credential; must not be {@literal null}
|
||||
* and must be an ID returned by {@link #getAll()}
|
||||
* or {@link #getByName(CredentialName)}
|
||||
* @param setAsTransitional {@code true} to mark the certificate version transitional;
|
||||
* {@code false} otherwise
|
||||
* @return the details of the certificate credential
|
||||
*/
|
||||
Mono<CertificateCredentialDetails> regenerate(final String id, final boolean setAsTransitional);
|
||||
|
||||
/**
|
||||
* Regenerate all certificates in CredHub that were signed by the specified certificate.
|
||||
*
|
||||
* @param certificateName the name of the signing certificate credential; must not be {@literal null}
|
||||
* @return the names of all regenerated certificate credentials
|
||||
*/
|
||||
Flux<CredentialName> regenerate(CredentialName certificateName);
|
||||
|
||||
/**
|
||||
* Make the specified version of a certificate the {@literal transitional} version.
|
||||
*
|
||||
* @param id the CredHub-generated ID of the certificate credential; must not be {@literal null}
|
||||
* and must be an ID returned by {@link #getAll()}
|
||||
* or {@link #getByName(CredentialName)}
|
||||
* @param versionId the CredHub-generated ID of the version of the certificate credential that should be
|
||||
* marked {@literal transitional}, or {@literal null} to indicate that no version
|
||||
* is {@literal transitional}
|
||||
* @return the details of the certificate credential, including all versions
|
||||
*/
|
||||
Flux<CertificateCredentialDetails> updateTransitionalVersion(final String id, final String versionId);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.certificate;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.certificate.CertificateCredentialDetails;
|
||||
import org.springframework.credhub.support.certificate.CertificateSummary;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements the interactions with CredHub to retrieve, regenerate, and update
|
||||
* certificates.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubCertificateTemplate implements ReactiveCredHubCertificateOperations {
|
||||
private static final String BASE_URL_PATH = "/api/v1/certificates";
|
||||
private static final String NAME_URL_QUERY = BASE_URL_PATH + "?name={name}";
|
||||
private static final String REGENERATE_URL_PATH = BASE_URL_PATH + "/{id}/regenerate";
|
||||
private static final String UPDATE_TRANSITIONAL_URL_PATH = BASE_URL_PATH + "/{id}/update_transitional_version";
|
||||
private static final String BULK_REGENERATE_URL_PATH = "/api/v1/bulk-regenerate";
|
||||
|
||||
private static final String TRANSITIONAL_REQUEST_FIELD = "set_as_transitional";
|
||||
private static final String VERSION_REQUEST_FIELD = "version";
|
||||
private static final String SIGNED_BY_REQUEST_FIELD = "signed_by";
|
||||
private static final String REGENERATED_CREDENTIALS_RESPONSE_FIELD = "regenerated_credentials";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubCertificateTemplate}.
|
||||
*
|
||||
* @param credHubOperations the {@link ReactiveCredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubCertificateTemplate(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<CertificateSummary> getAll() {
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(BASE_URL_PATH)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(CertificateSummary.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CertificateSummary> getByName(final CredentialName name) {
|
||||
Assert.notNull(name, "certificate name must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(NAME_URL_QUERY, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(CertificateSummary.class)
|
||||
.single());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CertificateCredentialDetails> regenerate(final String id, final boolean setAsTransitional) {
|
||||
Assert.notNull(id, "credential ID must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CertificateCredentialDetails> ref =
|
||||
new ParameterizedTypeReference<CertificateCredentialDetails>() {};
|
||||
|
||||
Map<String, Boolean> request = new HashMap<>(1);
|
||||
request.put(TRANSITIONAL_REQUEST_FIELD, setAsTransitional);
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.put()
|
||||
.uri(REGENERATE_URL_PATH, id)
|
||||
.syncBody(request)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<CredentialName> regenerate(final CredentialName certificateName) {
|
||||
Assert.notNull(certificateName, "certificate name must not be null");
|
||||
|
||||
final ParameterizedTypeReference<Map<String, List<CredentialName>>> ref =
|
||||
new ParameterizedTypeReference<Map<String, List<CredentialName>>>() {};
|
||||
|
||||
Map<String, Object> request = new HashMap<>(1);
|
||||
request.put(SIGNED_BY_REQUEST_FIELD, certificateName.getName());
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.put()
|
||||
.uri(BULK_REGENERATE_URL_PATH)
|
||||
.syncBody(request)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(ref)
|
||||
.flatMap(body -> Flux.fromIterable(body.get(REGENERATED_CREDENTIALS_RESPONSE_FIELD))));
|
||||
}
|
||||
|
||||
public Flux<CertificateCredentialDetails> updateTransitionalVersion(final String id,
|
||||
final String versionId) {
|
||||
Assert.notNull(id, "credential ID must not be null");
|
||||
|
||||
Map<String, String> request = new HashMap<>(1);
|
||||
request.put(VERSION_REQUEST_FIELD, versionId);
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.put()
|
||||
.uri(UPDATE_TRANSITIONAL_URL_PATH, id)
|
||||
.syncBody(request)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(CertificateCredentialDetails.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.credential;
|
||||
|
||||
import org.springframework.credhub.support.CredentialDetails;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.CredentialRequest;
|
||||
import org.springframework.credhub.support.CredentialSummary;
|
||||
import org.springframework.credhub.support.ParametersRequest;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Specifies the interactions with CredHub to save, generate, retrieve,
|
||||
* and delete credentials.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubCredentialOperations {
|
||||
/**
|
||||
* Write a new credential to CredHub, or overwrite an existing credential with a new
|
||||
* value.
|
||||
*
|
||||
* @param credentialRequest the credential to write to CredHub; must not be {@literal null}
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the written credential
|
||||
*/
|
||||
<T> Mono<CredentialDetails<T>> write(final CredentialRequest<T> credentialRequest);
|
||||
|
||||
/**
|
||||
* Generate a new credential in CredHub, or overwrite an existing credential with a new
|
||||
* generated value.
|
||||
*
|
||||
* @param parametersRequest the parameters of the new credential to generate in CredHub;
|
||||
* must not be {@literal null}
|
||||
* @param credentialType the type of the credential to be regenerated; must not be {@literal null}
|
||||
* @param <T> the credential implementation type
|
||||
* @param <P> the credential parameter implementation type
|
||||
* @return the details of the generated credential
|
||||
*/
|
||||
<T, P> Mono<CredentialDetails<T>> generate(final ParametersRequest<P> parametersRequest,
|
||||
Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Regenerate a credential in CredHub. Only credentials that were previously generated can be
|
||||
* re-generated.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param credentialType the type of the credential to be regenerated; must not be {@literal null}
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the regenerated credential
|
||||
*/
|
||||
<T> Mono<CredentialDetails<T>> regenerate(final CredentialName name, Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Retrieve a credential using its ID, as returned in a write request.
|
||||
*
|
||||
* @param id the ID of the credential; must not be {@literal null}
|
||||
* @param credentialType the type of the credential to be retrieved; must not be {@literal null}
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the retrieved credential
|
||||
*/
|
||||
<T> Mono<CredentialDetails<T>> getById(final String id, final Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Retrieve a credential using its name, as passed to a write request.
|
||||
* Only the current credential value will be returned.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param credentialType the type of credential expected to be returned
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the retrieved credential
|
||||
*/
|
||||
<T> Mono<CredentialDetails<T>> getByName(final CredentialName name, final Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Retrieve a credential using its name, as passed to a write request.
|
||||
* A collection of all stored values for the named credential will be returned,
|
||||
* including historical values.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param credentialType the type of credential expected to be returned
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the retrieved credential, including history
|
||||
*/
|
||||
<T> Flux<CredentialDetails<T>> getByNameWithHistory(final CredentialName name, final Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Retrieve a credential using its name, as passed to a write request.
|
||||
* A collection of stored values for the named credential will be returned,
|
||||
* with the specified number of historical values.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param versions the number of historical versions to retrieve
|
||||
* @param credentialType the type of credential expected to be returned
|
||||
* @param <T> the credential implementation type
|
||||
* @return the details of the retrieved credential, including history
|
||||
*/
|
||||
<T> Flux<CredentialDetails<T>> getByNameWithHistory(final CredentialName name, int versions,
|
||||
final Class<T> credentialType);
|
||||
|
||||
/**
|
||||
* Find a credential using a full or partial name.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @return a summary of the credential search results
|
||||
*/
|
||||
Flux<CredentialSummary> findByName(final CredentialName name);
|
||||
|
||||
/**
|
||||
* Find a credential using a path.
|
||||
*
|
||||
* @param path the path to the credential; must not be {@literal null}
|
||||
* @return a summary of the credential search results
|
||||
*/
|
||||
Flux<CredentialSummary> findByPath(final String path);
|
||||
|
||||
/**
|
||||
* Delete a credential by its full name.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @return an empty {@code Mono}
|
||||
*/
|
||||
Mono<Void> deleteByName(final CredentialName name);
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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.credential;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialDetails;
|
||||
import org.springframework.credhub.support.CredentialDetailsData;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.CredentialRequest;
|
||||
import org.springframework.credhub.support.CredentialSummary;
|
||||
import org.springframework.credhub.support.CredentialSummaryData;
|
||||
import org.springframework.credhub.support.ParametersRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements the interactions with CredHub to save, retrieve,
|
||||
* and delete credentials.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubCredentialTemplate implements ReactiveCredHubCredentialOperations {
|
||||
private static final String BASE_URL_PATH = "/api/v1/data";
|
||||
private static final String ID_URL_PATH = BASE_URL_PATH + "/{id}";
|
||||
private static final String NAME_URL_QUERY = BASE_URL_PATH + "?name={name}";
|
||||
private static final String NAME_URL_QUERY_CURRENT = NAME_URL_QUERY + "¤t=true";
|
||||
private static final String NAME_URL_QUERY_VERSIONS = NAME_URL_QUERY + "&versions={versions}";
|
||||
private static final String NAME_LIKE_URL_QUERY = BASE_URL_PATH + "?name-like={name}";
|
||||
private static final String PATH_URL_QUERY = BASE_URL_PATH + "?path={path}";
|
||||
private static final String REGENERATE_URL_PATH = "/api/v1/regenerate";
|
||||
|
||||
private static final String NAME_REQUEST_FIELD = "name";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubCredentialTemplate}.
|
||||
*
|
||||
* @param credHubOperations the {@link ReactiveCredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubCredentialTemplate(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<CredentialDetails<T>> write(final CredentialRequest<T> credentialRequest) {
|
||||
Assert.notNull(credentialRequest, "credentialRequest must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetails<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetails<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.put()
|
||||
.uri(BASE_URL_PATH)
|
||||
.syncBody(credentialRequest)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, P> Mono<CredentialDetails<T>> generate(final ParametersRequest<P> parametersRequest,
|
||||
Class<T> credentialType) {
|
||||
Assert.notNull(parametersRequest, "parametersRequest must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetails<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetails<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.post()
|
||||
.uri(BASE_URL_PATH)
|
||||
.syncBody(parametersRequest)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<CredentialDetails<T>> regenerate(final CredentialName name, Class<T> credentialType) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
Assert.notNull(credentialType, "credential type must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetails<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetails<T>>() {};
|
||||
|
||||
Map<String, Object> request = new HashMap<>(1);
|
||||
request.put(NAME_REQUEST_FIELD, name.getName());
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.post()
|
||||
.uri(REGENERATE_URL_PATH)
|
||||
.syncBody(request)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<CredentialDetails<T>> getById(final String id, final Class<T> credentialType) {
|
||||
Assert.notNull(id, "credential id must not be null");
|
||||
Assert.notNull(credentialType, "credential type must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetails<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetails<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(ID_URL_PATH, id)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<CredentialDetails<T>> getByName(final CredentialName name, final Class<T> credentialType) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
Assert.notNull(credentialType, "credential type must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetailsData<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetailsData<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(NAME_URL_QUERY_CURRENT, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ref)
|
||||
.map(body -> body.getData().get(0)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<CredentialDetails<T>> getByNameWithHistory(final CredentialName name, final Class<T> credentialType) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
Assert.notNull(credentialType, "credential type must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetailsData<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetailsData<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(NAME_URL_QUERY, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(ref)
|
||||
.flatMap(body -> Flux.fromIterable(body.getData())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<CredentialDetails<T>> getByNameWithHistory(final CredentialName name, final int versions,
|
||||
final Class<T> credentialType) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
Assert.notNull(credentialType, "credential type must not be null");
|
||||
|
||||
final ParameterizedTypeReference<CredentialDetailsData<T>> ref =
|
||||
new ParameterizedTypeReference<CredentialDetailsData<T>>() {};
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(NAME_URL_QUERY_VERSIONS, name.getName(), versions)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(ref)
|
||||
.flatMap(body -> Flux.fromIterable(body.getData())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<CredentialSummary> findByName(final CredentialName name) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(NAME_LIKE_URL_QUERY, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(CredentialSummaryData.class)
|
||||
.flatMapMany(data -> Flux.fromIterable(data.getCredentials())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<CredentialSummary> findByPath(final String path) {
|
||||
Assert.notNull(path, "credential path must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(PATH_URL_QUERY, path)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(CredentialSummaryData.class)
|
||||
.flatMapMany(data -> Flux.fromIterable(data.getCredentials())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deleteByName(final CredentialName name) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.delete()
|
||||
.uri(NAME_URL_QUERY, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(Void.class));
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,23 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.credhub.core.info;
|
||||
|
||||
import org.springframework.credhub.support.info.VersionInfo;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Spring auto configuration support for Spring CredHub.
|
||||
* Specifies the interactions with CredHub for retrieving server information.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
package org.springframework.credhub.autoconfig.security;
|
||||
public interface ReactiveCredHubInfoOperations {
|
||||
|
||||
/**
|
||||
* Retrieve the version information from the CredHub server.
|
||||
*
|
||||
* @return the server version information
|
||||
*/
|
||||
Mono<VersionInfo> version();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.info;
|
||||
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.info.VersionInfo;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Implements the interaction with CredHub retrieve server information.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubInfoTemplate implements ReactiveCredHubInfoOperations {
|
||||
private static final String VERSION_URL_PATH = "/version";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubInfoTemplate}.
|
||||
*
|
||||
* @param credHubOperations the {@link ReactiveCredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubInfoTemplate(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the version information from the CredHub server.
|
||||
*
|
||||
* @return the server version information
|
||||
*/
|
||||
@Override
|
||||
public Mono<VersionInfo> version() {
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(VERSION_URL_PATH)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(VersionInfo.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.interpolation;
|
||||
|
||||
import org.springframework.credhub.support.ServicesData;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Specifies the interactions with CredHub to interpolate service binding credentials.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubInterpolationOperations {
|
||||
/**
|
||||
* Search the provided data structure of bound service credentials, looking for
|
||||
* references to CredHub credentials. Any CredHub credentials found in the data
|
||||
* structure will be replaced by the credential value stored in CredHub.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* A JSON data structure parsed from a {@literal VCAP_SERVICES} environment
|
||||
* variable might look like this if the service broker that provided the binding
|
||||
* is integrated with CredHub:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* {
|
||||
* "service-offering": [{
|
||||
* "credentials": {
|
||||
* "credhub-ref": "((/c/service-broker/service-offering/1111-2222-3333-4444/credentials))"
|
||||
* }
|
||||
* "label": "service-offering",
|
||||
* "name": "service-instance",
|
||||
* "plan": "standard",
|
||||
* "tags": ["
|
||||
* "cloud-service"
|
||||
* ]
|
||||
* }]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Assuming that CredHub has a credential with the name
|
||||
* {@literal /c/service-broker/service-offering/1111-2222-3333-4444/credentials},
|
||||
* passing the data structure above to this method would result in the
|
||||
* {@literal credhub-ref} field being replaced by the credentials stored in CredHub:
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* {
|
||||
* "service-offering": [{
|
||||
* "credentials": {
|
||||
* "url": "https://servicehost.example.com/",
|
||||
* "username": "someuser",
|
||||
* "password": "secret"
|
||||
* }
|
||||
* "label": "service-offering",
|
||||
* "name": "service-instance",
|
||||
* "plan": "standard",
|
||||
* "tags": ["
|
||||
* "cloud-service"
|
||||
* ]
|
||||
* }]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param serviceData a data structure of bound service credentials, as would be
|
||||
* parsed from the {@literal VCAP_SERVICES} environment variable provided to
|
||||
* applications running on Cloud Foundry
|
||||
* @return the serviceData structure with CredHub references replaced by stored
|
||||
* credential values
|
||||
*/
|
||||
Mono<ServicesData> interpolateServiceData(final ServicesData serviceData);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.interpolation;
|
||||
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.ServicesData;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Implements the main interaction with CredHub to interpolate service binding credentials.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubInterpolationTemplate implements ReactiveCredHubInterpolationOperations {
|
||||
private static final String INTERPOLATE_URL_PATH = "/api/v1/interpolate";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubInterpolationTemplate}.
|
||||
*
|
||||
* @param credHubOperations the {@link CredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubInterpolationTemplate(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ServicesData> interpolateServiceData(final ServicesData serviceData) {
|
||||
Assert.notNull(serviceData, "serviceData must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.post()
|
||||
.uri(INTERPOLATE_URL_PATH)
|
||||
.syncBody(serviceData)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(ServicesData.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.permissions.Actor;
|
||||
import org.springframework.credhub.support.permissions.Permission;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Specifies the interactions with CredHub to add, retrieve, and delete permissions.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubPermissionOperations {
|
||||
/**
|
||||
* Get the permissions associated with a credential.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @return the collection of permissions associated with the credential
|
||||
*/
|
||||
Flux<Permission> getPermissions(final CredentialName name);
|
||||
|
||||
/**
|
||||
* Add permissions to an existing credential.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param permissions a collection of permissions to add
|
||||
* @return an empty {@code Mono}
|
||||
*/
|
||||
Mono<Void> addPermissions(final CredentialName name, final Permission... permissions);
|
||||
|
||||
/**
|
||||
* Delete a permission associated with a credential.
|
||||
*
|
||||
* @param name the name of the credential; must not be {@literal null}
|
||||
* @param actor the actor of the permission; must not be {@literal null}
|
||||
* @return an empty {@code Mono}
|
||||
*/
|
||||
Mono<Void> deletePermission(final CredentialName name, final Actor actor);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.permission;
|
||||
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.CredentialPermissions;
|
||||
import org.springframework.credhub.support.permissions.Actor;
|
||||
import org.springframework.credhub.support.permissions.Permission;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Implements the main interaction with CredHub to add, retrieve,
|
||||
* and delete permissions.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubPermissionTemplate implements ReactiveCredHubPermissionOperations {
|
||||
private static final String PERMISSIONS_URL_PATH = "/api/v1/permissions";
|
||||
private static final String PERMISSIONS_URL_QUERY = PERMISSIONS_URL_PATH + "?credential_name={name}";
|
||||
private static final String PERMISSIONS_ACTOR_URL_QUERY = PERMISSIONS_URL_QUERY + "&actor={actor}";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubPermissionTemplate}.
|
||||
*
|
||||
* @param credHubOperations the {@link ReactiveCredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubPermissionTemplate(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Permission> getPermissions(final CredentialName name) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(PERMISSIONS_URL_QUERY, name.getName())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToFlux(Permission.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> addPermissions(final CredentialName name,
|
||||
final Permission... permissions) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
|
||||
final CredentialPermissions credentialPermissions = new CredentialPermissions(name, permissions);
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.post()
|
||||
.uri(PERMISSIONS_URL_PATH)
|
||||
.syncBody(credentialPermissions)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(Void.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deletePermission(final CredentialName name, final Actor actor) {
|
||||
Assert.notNull(name, "credential name must not be null");
|
||||
Assert.notNull(actor, "actor must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.delete()
|
||||
.uri(PERMISSIONS_ACTOR_URL_QUERY, name.getName(), actor.getIdentity())
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(Void.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.permissionV2;
|
||||
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.CredentialPermission;
|
||||
import org.springframework.credhub.support.permissions.Permission;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Specifies the interactions with CredHub to add, retrieve, and delete permissions.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public interface ReactiveCredHubPermissionV2Operations {
|
||||
/**
|
||||
* Get a permission.
|
||||
*
|
||||
* @param id the CredHub-assigned ID of the permission; must not be {@literal null}
|
||||
* @return the details if the specified permission
|
||||
*/
|
||||
Mono<CredentialPermission> getPermissions(final String id);
|
||||
|
||||
/**
|
||||
* Add permissions to an credential path.
|
||||
*
|
||||
* @param path the path of the credentials; must not be {@literal null}
|
||||
* @param permission a permission to add
|
||||
* @return the details if the added permission
|
||||
*/
|
||||
Mono<CredentialPermission> addPermissions(final CredentialName path, final Permission permission);
|
||||
|
||||
/**
|
||||
* Add permissions to an existing credential.
|
||||
*
|
||||
* @param id the CredHub-assigned ID of the permission; must not be {@literal null}
|
||||
* @param path the path of the credentials; must not be {@literal null}
|
||||
* @param permission a permission to add
|
||||
* @return the details if the added permission
|
||||
*/
|
||||
Mono<CredentialPermission> updatePermissions(final String id, final CredentialName path, final Permission permission);
|
||||
|
||||
/**
|
||||
* Delete a permission.
|
||||
*
|
||||
* @param id the CredHub-assigned ID of the permission; must not be {@literal null}
|
||||
* @return an empty {@code Mono}
|
||||
*/
|
||||
Mono<Void> deletePermission(final String id);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.credhub.core.permissionV2;
|
||||
|
||||
import org.springframework.credhub.core.ExceptionUtils;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.CredentialPermission;
|
||||
import org.springframework.credhub.support.permissions.Permission;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Implements the main interaction with CredHub to add, retrieve,
|
||||
* and delete permissions.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class ReactiveCredHubPermissionV2Template implements ReactiveCredHubPermissionV2Operations {
|
||||
private static final String PERMISSIONS_URL_PATH = "/api/v2/permissions";
|
||||
private static final String PERMISSIONS_ID_URL_PATH = PERMISSIONS_URL_PATH + "/{id}";
|
||||
|
||||
private ReactiveCredHubOperations credHubOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveCredHubPermissionV2Template}.
|
||||
*
|
||||
* @param credHubOperations the {@link ReactiveCredHubOperations} to use for interactions with CredHub
|
||||
*/
|
||||
public ReactiveCredHubPermissionV2Template(ReactiveCredHubOperations credHubOperations) {
|
||||
this.credHubOperations = credHubOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CredentialPermission> getPermissions(final String id) {
|
||||
Assert.notNull(id, "credential ID must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.get()
|
||||
.uri(PERMISSIONS_ID_URL_PATH, id)
|
||||
.retrieve()
|
||||
.bodyToMono(CredentialPermission.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CredentialPermission> addPermissions(final CredentialName path,
|
||||
final Permission permission) {
|
||||
Assert.notNull(path, "credential path must not be null");
|
||||
Assert.notNull(permission, "credential permission must not be null");
|
||||
|
||||
final CredentialPermission credentialPermission = new CredentialPermission(path, permission);
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.post()
|
||||
.uri(PERMISSIONS_URL_PATH)
|
||||
.syncBody(credentialPermission)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(CredentialPermission.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<CredentialPermission> updatePermissions(final String id, final CredentialName path,
|
||||
final Permission permission) {
|
||||
Assert.notNull(id, "credential ID must not be null");
|
||||
Assert.notNull(path, "credential path must not be null");
|
||||
Assert.notNull(permission, "credential permission must not be null");
|
||||
|
||||
final CredentialPermission credentialPermission = new CredentialPermission(path, permission);
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.put()
|
||||
.uri(PERMISSIONS_ID_URL_PATH, id)
|
||||
.syncBody(credentialPermission)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(CredentialPermission.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> deletePermission(final String id) {
|
||||
Assert.notNull(id, "credential ID must not be null");
|
||||
|
||||
return credHubOperations.doWithWebClient(webClient -> webClient
|
||||
.delete()
|
||||
.uri(PERMISSIONS_ID_URL_PATH, id)
|
||||
.retrieve()
|
||||
.onStatus(HttpStatus::isError, ExceptionUtils::buildError)
|
||||
.bodyToMono(Void.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.springframework.credhub.security.oauth2.client.endpoint;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
|
||||
import org.springframework.security.oauth2.client.endpoint.ReactiveOAuth2AccessTokenResponseClient;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.springframework.security.oauth2.core.web.reactive.function.OAuth2BodyExtractors.oauth2AccessTokenResponse;
|
||||
|
||||
/**
|
||||
* An implementation of an {@link ReactiveOAuth2AccessTokenResponseClient} that "exchanges"
|
||||
* an authorization code credential for an access token credential
|
||||
* at the Authorization Server's Token Endpoint.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.1
|
||||
* @see OAuth2AccessTokenResponseClient
|
||||
* @see OAuth2AuthorizationCodeGrantRequest
|
||||
* @see OAuth2AccessTokenResponse
|
||||
* @see <a target="_blank" href="https://connect2id.com/products/nimbus-oauth-openid-connect-sdk">Nimbus OAuth 2.0 SDK</a>
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request (Authorization Code Grant)</a>
|
||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response (Authorization Code Grant)</a>
|
||||
*/
|
||||
public class WebClientReactiveClientCredentialsTokenResponseClient implements ReactiveOAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> {
|
||||
private WebClient webClient = WebClient.builder()
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Mono<OAuth2AccessTokenResponse> getTokenResponse(OAuth2ClientCredentialsGrantRequest authorizationGrantRequest) {
|
||||
return Mono.defer(() -> {
|
||||
ClientRegistration clientRegistration = authorizationGrantRequest.getClientRegistration();
|
||||
|
||||
String tokenUri = clientRegistration.getProviderDetails().getTokenUri();
|
||||
BodyInserters.FormInserter<String> body = body(authorizationGrantRequest);
|
||||
|
||||
return this.webClient.post()
|
||||
.uri(tokenUri)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.headers(headers(clientRegistration))
|
||||
.body(body)
|
||||
.exchange()
|
||||
.flatMap(response -> response.body(oauth2AccessTokenResponse()))
|
||||
.map(response -> {
|
||||
if (response.getAccessToken().getScopes().isEmpty()) {
|
||||
response = OAuth2AccessTokenResponse.withResponse(response)
|
||||
.scopes(authorizationGrantRequest.getClientRegistration().getScopes())
|
||||
.build();
|
||||
}
|
||||
return response;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Consumer<HttpHeaders> headers(ClientRegistration clientRegistration) {
|
||||
return headers -> {
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
|
||||
if (ClientAuthenticationMethod.BASIC.equals(clientRegistration.getClientAuthenticationMethod())) {
|
||||
headers.setBasicAuth(clientRegistration.getClientId(), clientRegistration.getClientSecret());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static BodyInserters.FormInserter<String> body(OAuth2ClientCredentialsGrantRequest authorizationGrantRequest) {
|
||||
ClientRegistration clientRegistration = authorizationGrantRequest.getClientRegistration();
|
||||
BodyInserters.FormInserter<String> body = BodyInserters
|
||||
.fromFormData(OAuth2ParameterNames.GRANT_TYPE, authorizationGrantRequest.getGrantType().getValue());
|
||||
Set<String> scopes = clientRegistration.getScopes();
|
||||
if (!CollectionUtils.isEmpty(scopes)) {
|
||||
String scope = StringUtils.collectionToDelimitedString(scopes, " ");
|
||||
body.with(OAuth2ParameterNames.SCOPE, scope);
|
||||
}
|
||||
if (ClientAuthenticationMethod.POST.equals(clientRegistration.getClientAuthenticationMethod())) {
|
||||
body.with(OAuth2ParameterNames.CLIENT_ID, clientRegistration.getClientId());
|
||||
body.with(OAuth2ParameterNames.CLIENT_SECRET, clientRegistration.getClientSecret());
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setWebClient(WebClient webClient) {
|
||||
this.webClient = webClient;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.jsontype.NamedType;
|
||||
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
|
||||
import com.fasterxml.jackson.databind.util.StdDateFormat;
|
||||
import org.springframework.credhub.support.CredentialType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -42,7 +42,7 @@ public class JsonUtils {
|
||||
*/
|
||||
public static ObjectMapper buildObjectMapper() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setDateFormat(new ISO8601DateFormat());
|
||||
objectMapper.setDateFormat(new StdDateFormat());
|
||||
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategy.SnakeCaseStrategy());
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
@@ -61,7 +61,7 @@ public class JsonUtils {
|
||||
* @param objectMapper the {@link ObjectMapper} to configure
|
||||
*/
|
||||
private static void configureCredentialDetailTypeMapping(ObjectMapper objectMapper) {
|
||||
List<NamedType> subtypes = new ArrayList<NamedType>();
|
||||
List<NamedType> subtypes = new ArrayList<>();
|
||||
for (CredentialType type : CredentialType.values()) {
|
||||
subtypes.add(new NamedType(type.getModelClass(), type.getValueType()));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.credhub.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.credhub.support.ClientOptions;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ClientHttpConnectorFactoryTests {
|
||||
@Test
|
||||
public void nettyClientIsCreated() {
|
||||
ClientHttpConnector clientHttpConnector = ClientHttpConnectorFactory.create(new ClientOptions());
|
||||
|
||||
assertThat(clientHttpConnector).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -25,27 +25,21 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.AbstractUriTemplateHandler;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CredHubClientFactoryUnitTests {
|
||||
private static final String CREDHUB_URI = "https://credhub.cf.example.com:8844";
|
||||
|
||||
public class CredHubRestTemplateFactoryUnitTests {
|
||||
@Mock
|
||||
private ClientHttpRequestFactory clientHttpRequestFactory;
|
||||
|
||||
@Test
|
||||
public void restTemplateIsCreated() {
|
||||
RestTemplate restTemplate = CredHubClientFactory.createRestTemplate(CREDHUB_URI,
|
||||
clientHttpRequestFactory);
|
||||
CredHubProperties properties = new CredHubProperties();
|
||||
properties.setUrl("https://credhub.cf.example.com:8844");
|
||||
RestTemplate restTemplate = CredHubRestTemplateFactory
|
||||
.createRestTemplate(properties, clientHttpRequestFactory);
|
||||
|
||||
assertThat(restTemplate.getUriTemplateHandler())
|
||||
.isInstanceOf(AbstractUriTemplateHandler.class);
|
||||
|
||||
AbstractUriTemplateHandler uriTemplateHandler = (AbstractUriTemplateHandler) restTemplate
|
||||
.getUriTemplateHandler();
|
||||
assertThat(uriTemplateHandler.getBaseUrl()).isEqualTo(CREDHUB_URI);
|
||||
assertThat(restTemplate).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CredHubWebClientFactoryTests {
|
||||
@Mock
|
||||
private ClientHttpConnector clientHttpConnector;
|
||||
|
||||
@Mock
|
||||
private ReactiveClientRegistrationRepository clientRegistrationRepository;
|
||||
|
||||
@Mock
|
||||
private ServerOAuth2AuthorizedClientRepository authorizedClientRepository;
|
||||
|
||||
@Test
|
||||
public void webClientIsCreated() {
|
||||
WebClient webClient = CredHubWebClientFactory
|
||||
.createWebClient(new CredHubProperties(), clientHttpConnector,
|
||||
clientRegistrationRepository, authorizedClientRepository);
|
||||
|
||||
assertThat(webClient).isNotNull();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ package org.springframework.credhub.support;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
|
||||
import com.fasterxml.jackson.databind.util.StdDateFormat;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -43,7 +43,7 @@ public abstract class JsonParsingUnitTestsBase {
|
||||
|
||||
@Before
|
||||
public void setUpJsonParsing() throws Exception {
|
||||
testDate = new ISO8601DateFormat().parse(TEST_DATE_STRING);
|
||||
testDate = new StdDateFormat().parse(TEST_DATE_STRING);
|
||||
}
|
||||
|
||||
protected <T> T parseResponse(String json, Class<T> type) {
|
||||
|
||||
@@ -18,13 +18,13 @@ description = 'Spring CredHub Demo'
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
springBootVersion = "1.5.8.RELEASE"
|
||||
springBootVersion = "2.0.6.RELEASE"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'org.springframework.build.gradle:propdeps-plugin:0.0.7'
|
||||
classpath 'io.spring.gradle:spring-io-plugin:0.0.7.RELEASE'
|
||||
classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
|
||||
classpath('io.spring.gradle:propdeps-plugin:0.0.10.RELEASE')
|
||||
classpath('io.spring.gradle:dependency-management-plugin:1.0.5.RELEASE')
|
||||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -41,16 +41,18 @@ apply plugin: 'propdeps'
|
||||
apply plugin: 'propdeps-maven'
|
||||
apply plugin: 'propdeps-idea'
|
||||
apply plugin: 'propdeps-eclipse'
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
dependencies {
|
||||
compile("org.springframework.credhub:spring-credhub-starter:1.1.0.BUILD-SNAPSHOT")
|
||||
|
||||
compile("org.springframework.boot:spring-boot-starter-web")
|
||||
compile("org.springframework.boot:spring-boot-starter-webflux")
|
||||
compile("org.springframework.boot:spring-boot-starter-actuator")
|
||||
|
||||
compile("org.springframework.credhub:spring-credhub-starter:2.0.0.BUILD-SNAPSHOT")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo.spring.io/libs-snapshot" }
|
||||
mavenCentral()
|
||||
maven { url "https://repo.spring.io/libs-snapshot-local" }
|
||||
maven { url "https://repo.spring.io/libs-milestone-local" }
|
||||
}
|
||||
|
||||
@@ -42,8 +42,12 @@ apply plugin: 'org.springframework.boot'
|
||||
dependencies {
|
||||
compile project(":spring-credhub-starter")
|
||||
compile("org.springframework.boot:spring-boot-starter")
|
||||
compile("org.springframework.security.oauth:spring-security-oauth2")
|
||||
compile("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE")
|
||||
|
||||
compile("org.springframework.boot:spring-boot-starter-webflux")
|
||||
compile("io.projectreactor.netty:reactor-netty")
|
||||
|
||||
compile("org.springframework.security:spring-security-config")
|
||||
compile("org.springframework.security:spring-security-oauth2-client")
|
||||
|
||||
if (project.hasProperty("useHttpComponents")) {
|
||||
compile("org.apache.httpcomponents:httpclient:4.5.3")
|
||||
@@ -56,6 +60,7 @@ dependencies {
|
||||
}
|
||||
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test")
|
||||
testCompile("io.projectreactor:reactor-test")
|
||||
testCompile("org.assertj:assertj-core:${assertJVersion}")
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ package org.springframework.credhub.integration;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration;
|
||||
import org.springframework.credhub.core.CredHubException;
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
@@ -29,10 +26,7 @@ import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {TestApplication.class,
|
||||
CredHubAutoConfiguration.class,
|
||||
CredHubTemplateAutoConfiguration.class,
|
||||
CredHubOAuth2TemplateAutoConfiguration.class})
|
||||
@SpringBootTest(classes = {TestApplication.class})
|
||||
@ActiveProfiles("test")
|
||||
public abstract class CredHubIntegrationTests {
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2017-2018 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.integration;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration;
|
||||
import org.springframework.credhub.core.CredHubException;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.support.CredentialName;
|
||||
import org.springframework.credhub.support.info.VersionInfo;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = {TestApplication.class,
|
||||
CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2TemplateAutoConfiguration.class,
|
||||
CredHubTemplateAutoConfiguration.class})
|
||||
@ActiveProfiles("test")
|
||||
public abstract class ReactiveCredHubIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
protected ReactiveCredHubOperations operations;
|
||||
|
||||
boolean serverApiIsV1() {
|
||||
return getVersion().isVersion1();
|
||||
}
|
||||
|
||||
boolean serverApiIsV2() {
|
||||
return getVersion().isVersion2();
|
||||
}
|
||||
|
||||
private VersionInfo getVersion() {
|
||||
return operations.info().version().single().block();
|
||||
}
|
||||
|
||||
void deleteCredentialIfExists(CredentialName credentialName) {
|
||||
try {
|
||||
operations.credentials().deleteByName(credentialName).block();
|
||||
} catch (CredHubException e) {
|
||||
// ignore failing deletes on cleanup
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* 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.integration;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.credhub.core.credential.ReactiveCredHubCredentialOperations;
|
||||
import org.springframework.credhub.support.CredentialDetails;
|
||||
import org.springframework.credhub.support.CredentialType;
|
||||
import org.springframework.credhub.support.SimpleCredentialName;
|
||||
import org.springframework.credhub.support.WriteMode;
|
||||
import org.springframework.credhub.support.password.PasswordParameters;
|
||||
import org.springframework.credhub.support.user.UserCredential;
|
||||
import org.springframework.credhub.support.user.UserParametersRequest;
|
||||
import org.springframework.credhub.support.value.ValueCredential;
|
||||
import org.springframework.credhub.support.value.ValueCredentialRequest;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class ReactiveCredentialIntegrationTests extends ReactiveCredHubIntegrationTests {
|
||||
private static final SimpleCredentialName CREDENTIAL_NAME =
|
||||
new SimpleCredentialName("spring-credhub", "integration-test", "test-credential");
|
||||
private static final String CREDENTIAL_VALUE = "test-value";
|
||||
|
||||
private ReactiveCredHubCredentialOperations credentials;
|
||||
|
||||
private PasswordParameters.PasswordParametersBuilder passwordParameters;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
credentials = operations.credentials();
|
||||
|
||||
passwordParameters = PasswordParameters.builder()
|
||||
.length(12)
|
||||
.excludeLower(false)
|
||||
.excludeUpper(false)
|
||||
.excludeNumber(false)
|
||||
.includeSpecial(true);
|
||||
|
||||
deleteCredentialIfExists(CREDENTIAL_NAME);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
deleteCredentialIfExists(CREDENTIAL_NAME);
|
||||
|
||||
StepVerifier.create(credentials.findByName(CREDENTIAL_NAME))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeCredential() {
|
||||
AtomicReference<CredentialDetails<ValueCredential>> written = new AtomicReference<>();
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value(CREDENTIAL_VALUE)
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
assertThat(response.getCredentialType()).isEqualTo(CredentialType.VALUE);
|
||||
assertThat(response.getId()).isNotNull();
|
||||
|
||||
written.set(response);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.getById(written.get().getId(), ValueCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
assertThat(response.getCredentialType()).isEqualTo(CredentialType.VALUE);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.getByName(CREDENTIAL_NAME, ValueCredential.class))
|
||||
.assertNext(byName -> {
|
||||
assertThat(byName.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(byName.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
assertThat(byName.getCredentialType()).isEqualTo(CredentialType.VALUE);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.findByName(new SimpleCredentialName("/test")))
|
||||
.assertNext(response -> assertThat(response)
|
||||
.extracting("name").extracting("name")
|
||||
.containsExactly(CREDENTIAL_NAME.getName()))
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.findByPath("/spring-credhub/integration-test"))
|
||||
.assertNext(response ->
|
||||
assertThat(response)
|
||||
.extracting("name").extracting("name")
|
||||
.containsExactly(CREDENTIAL_NAME.getName()))
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overwriteCredentialV2() {
|
||||
assumeTrue(serverApiIsV2());
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value(CREDENTIAL_VALUE)
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
assertThat(response.getCredentialType()).isEqualTo(CredentialType.VALUE);
|
||||
assertThat(response.getId()).isNotNull();
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value("new-value")
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo("new-value");
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overwriteCredentialV1() {
|
||||
assumeTrue(serverApiIsV1());
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value(CREDENTIAL_VALUE)
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
assertThat(response.getCredentialType()).isEqualTo(CredentialType.VALUE);
|
||||
assertThat(response.getId()).isNotNull();
|
||||
}).verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value("new-value")
|
||||
.mode(WriteMode.NO_OVERWRITE)
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo(CREDENTIAL_VALUE);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.write(ValueCredentialRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.value("new-value")
|
||||
.mode(WriteMode.OVERWRITE)
|
||||
.build()))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getValue()).isEqualTo("new-value");
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateCredential() {
|
||||
AtomicReference<CredentialDetails<UserCredential>> generated = new AtomicReference<>();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getCredentialType()).isEqualTo(CredentialType.USER);
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).matches("^[a-zA-Z0-9\\p{Punct}]{12}$");
|
||||
assertThat(response.getValue().getPasswordHash()).isNotNull();
|
||||
|
||||
generated.set(response);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.getById(generated.get().getId(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.regenerate(CREDENTIAL_NAME, UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).matches("^[a-zA-Z0-9\\p{Punct}]{12}$");
|
||||
assertThat(response.getValue().getPassword())
|
||||
.isNotEqualTo(generated.get().getValue().getPassword());
|
||||
assertThat(response.getValue().getPasswordHash())
|
||||
.isNotEqualTo(generated.get().getValue().getPasswordHash());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateNoOverwriteCredential() {
|
||||
AtomicReference<CredentialDetails<UserCredential>> generated = new AtomicReference<>();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).matches("^[a-zA-Z0-9\\p{Punct}]{12}$");
|
||||
assertThat(response.getValue().getPasswordHash()).isNotNull();
|
||||
|
||||
generated.set(response);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.mode(WriteMode.NO_OVERWRITE)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).isEqualTo(generated.get().getValue().getPassword());
|
||||
assertThat(response.getValue().getPasswordHash()).isEqualTo(generated.get().getValue().getPasswordHash());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateOverwriteCredential() {
|
||||
AtomicReference<CredentialDetails<UserCredential>> generated = new AtomicReference<>();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).matches("^[a-zA-Z0-9\\p{Punct}]{12}$");
|
||||
assertThat(response.getValue().getPasswordHash()).isNotNull();
|
||||
|
||||
generated.set(response);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.mode(WriteMode.OVERWRITE)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).isNotEqualTo(generated.get().getValue().getPassword());
|
||||
assertThat(response.getValue().getPasswordHash()).isNotEqualTo(generated.get().getValue().getPasswordHash());
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateConvergeCredential() {
|
||||
AtomicReference<CredentialDetails<UserCredential>> generated = new AtomicReference<>();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getName().getName()).isEqualTo(CREDENTIAL_NAME.getName());
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword()).matches("^[a-zA-Z0-9\\p{Punct}]{12}$");
|
||||
assertThat(response.getValue().getPasswordHash()).isNotNull();
|
||||
|
||||
generated.set(response);
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.mode(WriteMode.CONVERGE)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword())
|
||||
.isEqualTo(generated.get().getValue().getPassword());
|
||||
assertThat(response.getValue().getPasswordHash())
|
||||
.isEqualTo(generated.get().getValue().getPasswordHash());
|
||||
})
|
||||
.verifyComplete();
|
||||
|
||||
passwordParameters.includeSpecial(false);
|
||||
|
||||
StepVerifier.create(credentials.generate(UserParametersRequest.builder()
|
||||
.name(CREDENTIAL_NAME)
|
||||
.mode(WriteMode.CONVERGE)
|
||||
.username("test-user")
|
||||
.parameters(passwordParameters.build())
|
||||
.build(), UserCredential.class))
|
||||
.assertNext(response -> {
|
||||
assertThat(response.getValue().getUsername()).isEqualTo("test-user");
|
||||
assertThat(response.getValue().getPassword())
|
||||
.isNotEqualTo(generated.get().getValue().getPassword());
|
||||
assertThat(response.getValue().getPasswordHash())
|
||||
.isNotEqualTo(generated.get().getValue().getPasswordHash());
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,11 @@ dependencies {
|
||||
compile project(':spring-credhub-core')
|
||||
compile("org.springframework.boot:spring-boot-autoconfigure")
|
||||
|
||||
optional("org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.1.0.RELEASE")
|
||||
|
||||
optional("org.springframework.boot:spring-boot-starter-webflux")
|
||||
|
||||
optional("org.springframework.security:spring-security-config")
|
||||
optional("org.springframework.security:spring-security-oauth2-client")
|
||||
|
||||
optional("org.apache.httpcomponents:httpclient") {
|
||||
exclude(group: 'commons-logging', module: 'commons-logging')
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.credhub.autoconfig;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -29,6 +30,8 @@ import org.springframework.credhub.core.CredHubProperties;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.credhub.support.ClientOptions;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CredHubTemplate}.
|
||||
@@ -81,6 +84,18 @@ public class CredHubAutoConfiguration {
|
||||
credHubTemplateFactory.clientHttpRequestFactoryWrapper(clientOptions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClientHttpConnector}.
|
||||
*
|
||||
* @param clientOptions the populated {@link ClientOptions} bean
|
||||
* @return the {@link ClientHttpConnector}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
public ClientHttpConnector clientHttpConnector(ClientOptions clientOptions) {
|
||||
return credHubTemplateFactory.clientHttpConnector(clientOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for {@link ClientHttpRequestFactory} to not expose the bean globally.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package org.springframework.credhub.autoconfig;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.UnAuthenticatedServerOAuth2AuthorizedClientRepository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
@AutoConfigureBefore(ReactiveOAuth2ClientAutoConfiguration.class)
|
||||
@ConditionalOnClass(ClientRegistration.class)
|
||||
public class CredHubOAuth2AutoConfiguration {
|
||||
|
||||
private final OAuth2ClientProperties properties;
|
||||
|
||||
CredHubOAuth2AutoConfiguration(OAuth2ClientProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ClientRegistrationRepository credHubClientRegistrationRepository() {
|
||||
List<ClientRegistration> registrations = new ArrayList<>(
|
||||
OAuth2ClientPropertiesRegistrationAdapter
|
||||
.getClientRegistrations(this.properties).values());
|
||||
return new InMemoryClientRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public OAuth2AuthorizedClientService credHubAuthorizedClientService(
|
||||
ClientRegistrationRepository clientRegistrationRepository) {
|
||||
return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ServerOAuth2AuthorizedClientRepository} bean to override the default
|
||||
* provided by Spring Boot auto-configuration.
|
||||
*
|
||||
* @return the {@code ServerOAuth2AuthorizedClientRepository}
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ServerOAuth2AuthorizedClientRepository credHubAuthorizedClientRepository() {
|
||||
return new UnAuthenticatedServerOAuth2AuthorizedClientRepository();
|
||||
}
|
||||
}
|
||||
@@ -16,64 +16,84 @@
|
||||
|
||||
package org.springframework.credhub.autoconfig;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration.ClientFactoryWrapper;
|
||||
import org.springframework.credhub.autoconfig.security.CredHubCredentialsDetails;
|
||||
import org.springframework.credhub.configuration.OAuth2CredHubTemplateFactory;
|
||||
import org.springframework.credhub.configuration.CredHubTemplateFactory;
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.credhub.core.CredHubProperties;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.core.ReactiveCredHubTemplate;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CredHubTemplate} with
|
||||
* OAuth2 credentials if spring-security-oauth2 and OAuth2 properties are provided.
|
||||
*
|
||||
* OAuth2 credentials.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(CredHubTemplateAutoConfiguration.class)
|
||||
@AutoConfigureAfter({CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2AutoConfiguration.class,
|
||||
OAuth2ClientAutoConfiguration.class,
|
||||
ReactiveOAuth2ClientAutoConfiguration.class})
|
||||
@ConditionalOnProperty("spring.credhub.oauth2.client-id")
|
||||
@ConditionalOnClass(name = "org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails")
|
||||
public class CredHubOAuth2TemplateAutoConfiguration {
|
||||
private final OAuth2CredHubTemplateFactory credHubTemplateFactory = new OAuth2CredHubTemplateFactory();
|
||||
private final CredHubTemplateFactory credHubTemplateFactory = new CredHubTemplateFactory();
|
||||
|
||||
/**
|
||||
* Bean that holds OAuth2 credential information for CredHub.
|
||||
*
|
||||
* @return the {@link ClientCredentialsResourceDetails} bean
|
||||
*/
|
||||
@Bean
|
||||
@CredHubCredentialsDetails
|
||||
@ConfigurationProperties("spring.credhub.oauth2")
|
||||
public ClientCredentialsResourceDetails credHubCredentialsDetails() {
|
||||
return new ClientCredentialsResourceDetails();
|
||||
}
|
||||
|
||||
/**
|
||||
* Preconfigured {@link OAuth2RestTemplate} with OAuth2 credentials for CredHub.
|
||||
*
|
||||
* @param credHubProperties {@link CredHubProperties} for CredHub
|
||||
* @param credHubCredentialsDetails OAuth2 credentials for use with the {@link OAuth2RestTemplate}
|
||||
* @param clientFactoryWrapper a {@link ClientFactoryWrapper}
|
||||
* to customize CredHub http requests
|
||||
* Create the {@link CredHubTemplate} that the application will use to interact
|
||||
* with CredHub.
|
||||
*
|
||||
* @param credHubProperties {@link CredHubProperties} for CredHub
|
||||
* @param clientFactoryWrapper a {@link ClientFactoryWrapper}
|
||||
* to customize CredHub http requests
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientService a repository of authorized OAuth2 clients
|
||||
* @return the {@link CredHubOperations} bean
|
||||
*/
|
||||
@Bean
|
||||
public CredHubOperations credHubTemplate(
|
||||
CredHubProperties credHubProperties,
|
||||
@CredHubCredentialsDetails ClientCredentialsResourceDetails credHubCredentialsDetails,
|
||||
ClientFactoryWrapper clientFactoryWrapper) {
|
||||
return credHubTemplateFactory.credHubTemplate(credHubCredentialsDetails,
|
||||
credHubProperties,
|
||||
clientFactoryWrapper.getClientHttpRequestFactory());
|
||||
public CredHubOperations oAuth2credHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientFactoryWrapper clientFactoryWrapper,
|
||||
ClientRegistrationRepository clientRegistrationRepository,
|
||||
OAuth2AuthorizedClientService authorizedClientService) {
|
||||
return credHubTemplateFactory.credHubTemplate(credHubProperties,
|
||||
clientFactoryWrapper.getClientHttpRequestFactory(),
|
||||
clientRegistrationRepository,
|
||||
authorizedClientService);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link ReactiveCredHubTemplate} that the application will use to interact
|
||||
* with CredHub.
|
||||
*
|
||||
* @param credHubProperties {@link CredHubProperties} for CredHub
|
||||
* @param clientHttpConnector a {@link ClientHttpConnector} to customize CredHub
|
||||
* http requests
|
||||
* @param clientRegistrationRepository a repository of OAuth2 client registrations
|
||||
* @param authorizedClientRepository a repository of OAuth2 authorized clients
|
||||
* @return the {@link CredHubTemplate} bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
public ReactiveCredHubOperations oAuth2reactiveCredHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpConnector clientHttpConnector,
|
||||
ReactiveClientRegistrationRepository clientRegistrationRepository,
|
||||
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
|
||||
return credHubTemplateFactory.credHubTemplate(credHubProperties, clientHttpConnector,
|
||||
clientRegistrationRepository, authorizedClientRepository);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.credhub.autoconfig;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -27,6 +28,10 @@ import org.springframework.credhub.configuration.CredHubTemplateFactory;
|
||||
import org.springframework.credhub.core.CredHubOperations;
|
||||
import org.springframework.credhub.core.CredHubProperties;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.credhub.core.ReactiveCredHubOperations;
|
||||
import org.springframework.credhub.core.ReactiveCredHubTemplate;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link CredHubTemplate}.
|
||||
@@ -35,7 +40,7 @@ import org.springframework.credhub.core.CredHubTemplate;
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter(CredHubOAuth2TemplateAutoConfiguration.class)
|
||||
@AutoConfigureAfter({CredHubAutoConfiguration.class, CredHubOAuth2TemplateAutoConfiguration.class})
|
||||
@ConditionalOnProperty(value = "spring.credhub.url")
|
||||
public class CredHubTemplateAutoConfiguration {
|
||||
private final CredHubTemplateFactory credHubTemplateFactory = new CredHubTemplateFactory();
|
||||
@@ -46,7 +51,7 @@ public class CredHubTemplateAutoConfiguration {
|
||||
*
|
||||
* @param credHubProperties {@link CredHubProperties} for CredHub
|
||||
* @param clientFactoryWrapper a {@link ClientFactoryWrapper} to customize CredHub
|
||||
* http requests
|
||||
* HTTP requests
|
||||
* @return the {@link CredHubTemplate} bean
|
||||
*/
|
||||
@Bean
|
||||
@@ -56,4 +61,22 @@ public class CredHubTemplateAutoConfiguration {
|
||||
return credHubTemplateFactory.credHubTemplate(credHubProperties,
|
||||
clientFactoryWrapper.getClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link ReactiveCredHubTemplate} that the application will use to interact
|
||||
* with CredHub.
|
||||
*
|
||||
* @param credHubProperties {@link CredHubProperties} for CredHub
|
||||
* @param clientHttpConnector a {@link ClientHttpConnector} to customize CredHub
|
||||
* HTTP requests
|
||||
* @return the {@link CredHubTemplate} bean
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
public ReactiveCredHubOperations reactiveCredHubTemplate(CredHubProperties credHubProperties,
|
||||
ClientHttpConnector clientHttpConnector) {
|
||||
return credHubTemplateFactory.credHubTemplate(credHubProperties, clientHttpConnector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.springframework.credhub.autoconfig.security;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Qualifies a {@link ClientCredentialsResourceDetails} used by Spring CredHub.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Qualifier
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface CredHubCredentialsDetails {
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.credhub.autoconfig.CredHubAutoConfiguration,\
|
||||
org.springframework.credhub.autoconfig.CredHubOAuth2AutoConfiguration,\
|
||||
org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration,\
|
||||
org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration
|
||||
org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration
|
||||
|
||||
@@ -37,12 +37,14 @@ public class CredHubAutoConfigurationTests {
|
||||
.withPropertyValues(
|
||||
"spring.credhub.url=https://localhost",
|
||||
"spring.credhub.connection-timeout=30",
|
||||
"spring.credhub.read-timeout=60"
|
||||
"spring.credhub.read-timeout=60",
|
||||
"spring.credhub.oauth2.client-id=test-client"
|
||||
)
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(CredHubProperties.class);
|
||||
CredHubProperties properties = context.getBean(CredHubProperties.class);
|
||||
assertThat(properties.getUrl()).isEqualTo("https://localhost");
|
||||
assertThat(properties.getOauth2().getClientId()).isEqualTo("test-client");
|
||||
|
||||
assertThat(context).hasSingleBean(ClientOptions.class);
|
||||
ClientOptions options = context.getBean(ClientOptions.class);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2AutoConfiguration;
|
||||
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CredHubOAuth2AutoConfigurationTests {
|
||||
|
||||
private ApplicationContextRunner context = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2AutoConfiguration.class,
|
||||
ReactiveOAuth2ClientAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.security.oauth2.client.registration.credhub-client.provider=uaa",
|
||||
"spring.security.oauth2.client.registration.credhub-client.client-id=test-client",
|
||||
"spring.security.oauth2.client.registration.credhub-client.client-secret=test-secret",
|
||||
"spring.security.oauth2.client.registration.credhub-client.authorization-grant-type=client_credentials",
|
||||
"spring.security.oauth2.client.provider.uaa.token-uri=http://example.com/uaa/oauth/token",
|
||||
"debug=true"
|
||||
);
|
||||
|
||||
@Test
|
||||
public void oauth2ContextConfigured() {
|
||||
context.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ClientRegistrationRepository.class);
|
||||
assertThat(context).hasSingleBean(OAuth2AuthorizedClientService.class);
|
||||
|
||||
assertThat(context).hasSingleBean(ReactiveClientRegistrationRepository.class);
|
||||
assertThat(context).hasSingleBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -18,14 +18,18 @@ package org.springframework.credhub.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2AutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.credhub.core.OAuth2CredHubTemplate;
|
||||
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
|
||||
import org.springframework.credhub.core.ReactiveCredHubTemplate;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -35,41 +39,41 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class CredHubOAuth2TemplateAutoConfigurationTests {
|
||||
|
||||
private ApplicationContextRunner context = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CredHubAutoConfiguration.class,
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
ReactiveOAuth2ClientAutoConfiguration.class,
|
||||
CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2AutoConfiguration.class,
|
||||
CredHubOAuth2TemplateAutoConfiguration.class,
|
||||
CredHubTemplateAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.credhub.url=https://localhost",
|
||||
"spring.credhub.oauth2.client-id=test-user",
|
||||
"spring.credhub.oauth2.client-secret=test-secret",
|
||||
"spring.credhub.oauth2.access-token-uri=https://uaa.example.com/oauth/token",
|
||||
"debug"
|
||||
"spring.credhub.oauth2.client-id=credhub-client",
|
||||
"spring.security.oauth2.client.registration.credhub-client.provider=uaa",
|
||||
"spring.security.oauth2.client.registration.credhub-client.client-id=test-client",
|
||||
"spring.security.oauth2.client.registration.credhub-client.client-secret=test-secret",
|
||||
"spring.security.oauth2.client.registration.credhub-client.authorization-grant-type=client_credentials",
|
||||
"spring.security.oauth2.client.provider.uaa.token-uri=http://example.com/uaa/oauth/token",
|
||||
"debug=true"
|
||||
);
|
||||
|
||||
@Test
|
||||
public void contextLoadsWithSpringSecurityOAuth2() {
|
||||
public void credHubTemplateConfiguredWithOAuth2() {
|
||||
context.run((context) -> {
|
||||
assertThat(context).hasSingleBean(OAuth2CredHubTemplate.class);
|
||||
assertThat(context).hasSingleBean(CredHubTemplate.class);
|
||||
assertThat(context).hasSingleBean(CredHubAutoConfiguration.ClientFactoryWrapper.class);
|
||||
|
||||
assertThat(context).hasSingleBean(ClientCredentialsResourceDetails.class);
|
||||
ClientCredentialsResourceDetails credentialsDetails =
|
||||
context.getBean(ClientCredentialsResourceDetails.class);
|
||||
assertThat(credentialsDetails).isNotNull();
|
||||
assertThat(credentialsDetails.getClientId()).isEqualTo("test-user");
|
||||
assertThat(credentialsDetails.getClientSecret()).isEqualTo("test-secret");
|
||||
assertThat(credentialsDetails.getAccessTokenUri())
|
||||
.isEqualTo("https://uaa.example.com/oauth/token");
|
||||
assertThat(context).hasSingleBean(ClientRegistrationRepository.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextLoadsWithoutSpringSecurityOAuth2() {
|
||||
context.withClassLoader(new FilteredClassLoader(ClientCredentialsResourceDetails.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(CredHubTemplate.class);
|
||||
assertThat(context).doesNotHaveBean(OAuth2CredHubTemplate.class);
|
||||
public void reactiveCredHubTemplateConfiguredWithOAuth2() {
|
||||
context.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ReactiveCredHubTemplate.class);
|
||||
assertThat(context).hasSingleBean(ClientHttpConnector.class);
|
||||
|
||||
assertThat(context).doesNotHaveBean(ClientCredentialsResourceDetails.class);
|
||||
});
|
||||
assertThat(context).hasSingleBean(ReactiveClientRegistrationRepository.class);
|
||||
assertThat(context).hasSingleBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,32 +18,53 @@ package org.springframework.credhub.configuration;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.credhub.autoconfig.CredHubAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubOAuth2TemplateAutoConfiguration;
|
||||
import org.springframework.credhub.autoconfig.CredHubTemplateAutoConfiguration;
|
||||
import org.springframework.credhub.core.CredHubTemplate;
|
||||
import org.springframework.credhub.core.OAuth2CredHubTemplate;
|
||||
import org.springframework.credhub.core.ReactiveCredHubTemplate;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
|
||||
import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class CredHubTemplateAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner context = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2TemplateAutoConfiguration.class,
|
||||
CredHubTemplateAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.credhub.url=https://localhost",
|
||||
"debug");
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(CredHubAutoConfiguration.class,
|
||||
CredHubOAuth2TemplateAutoConfiguration.class,
|
||||
CredHubTemplateAutoConfiguration.class))
|
||||
.withPropertyValues(
|
||||
"spring.credhub.url=https://localhost",
|
||||
"debug"
|
||||
)
|
||||
.run((context) -> {
|
||||
public void credHubTemplateConfigured() {
|
||||
context.run((context) -> {
|
||||
assertThat(context).hasSingleBean(CredHubTemplate.class);
|
||||
assertThat(context).doesNotHaveBean(OAuth2CredHubTemplate.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactiveCredHubTemplateConfigured() {
|
||||
context.run((context) -> {
|
||||
assertThat(context).hasSingleBean(ReactiveCredHubTemplate.class);
|
||||
assertThat(context).hasSingleBean(ClientHttpConnector.class);
|
||||
assertThat(context).doesNotHaveBean(ReactiveClientRegistrationRepository.class);
|
||||
assertThat(context).doesNotHaveBean(ServerOAuth2AuthorizedClientRepository.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reactiveCredHubTemplateNotConfiguredWithoutWebClient() {
|
||||
context.withClassLoader(new FilteredClassLoader(WebClient.class))
|
||||
.run((context) -> {
|
||||
assertThat(context).doesNotHaveBean(ReactiveCredHubTemplate.class);
|
||||
assertThat(context).doesNotHaveBean(ClientHttpConnector.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user