From fa88e52154bd186b02c70510282af407d2979ab8 Mon Sep 17 00:00:00 2001 From: Daniel Lavoie Date: Mon, 6 Nov 2017 14:04:59 -0500 Subject: [PATCH] Allow OAuth2 authentication [Closes #11] --- build.gradle | 1 - spring-credhub-core/build.gradle | 1 + .../OAuth2CredHubTemplateFactory.java | 37 +++++++++++++ .../credhub/core/CredHubClient.java | 21 ++++++-- .../credhub/core/OAuth2CredHubTemplate.java | 32 ++++++++++++ spring-credhub-starter/build.gradle | 16 +++++- .../autoconfig/CredHubAutoConfiguration.java | 11 ++-- .../CredHubOAuth2AutoConfiguration.java | 52 +++++++++++++++++++ .../security/CredHubCredentialsDetails.java | 16 ++++++ .../main/resources/META-INF/spring.factories | 3 +- .../CredHubAutoConfigurationTest.java | 8 +++ .../CredHubOAuth2AutoConfigurationTest.java | 38 ++++++++++++++ 12 files changed, 225 insertions(+), 11 deletions(-) create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/configuration/OAuth2CredHubTemplateFactory.java create mode 100644 spring-credhub-core/src/main/java/org/springframework/credhub/core/OAuth2CredHubTemplate.java create mode 100644 spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubOAuth2AutoConfiguration.java create mode 100644 spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/security/CredHubCredentialsDetails.java create mode 100644 spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubOAuth2AutoConfigurationTest.java diff --git a/build.gradle b/build.gradle index 282422d..6bc96b7 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,6 @@ buildscript { ext { springVersion = "4.3.8.RELEASE" - springBootVersion = "1.5.6.RELEASE" junitVersion = "4.12" mockitoVersion = "2.7.22" diff --git a/spring-credhub-core/build.gradle b/spring-credhub-core/build.gradle index 95be200..5458af2 100644 --- a/spring-credhub-core/build.gradle +++ b/spring-credhub-core/build.gradle @@ -22,6 +22,7 @@ dependencies { compile group: 'org.springframework', name: 'spring-web', version: "${springVersion}" compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.7' + optional group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.0.14.RELEASE' optional(group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3') { exclude(module: 'commons-logging') } diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/OAuth2CredHubTemplateFactory.java b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/OAuth2CredHubTemplateFactory.java new file mode 100644 index 0000000..da382aa --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/configuration/OAuth2CredHubTemplateFactory.java @@ -0,0 +1,37 @@ +/* + * Copyright 2016-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.credhub.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); + } +} diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java index 6983cf5..f5cea00 100644 --- a/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/CredHubClient.java @@ -18,6 +18,8 @@ package org.springframework.credhub.core; +import static java.util.Collections.singletonList; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -39,13 +41,12 @@ import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriTemplateHandler; import org.springframework.web.util.UriTemplateHandler; -import static java.util.Collections.singletonList; - /** * Factory for creating a {@link RestTemplate} configured for communication with * a CredHub server. * * @author Scott Frederick + * @author Daniel Lavoie */ public class CredHubClient { /** @@ -59,11 +60,25 @@ public class CredHubClient { public 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 + */ + public static void configureRestTemplate(RestTemplate restTemplate, String baseUri, + ClientHttpRequestFactory clientHttpRequestFactory) { restTemplate.setRequestFactory(clientHttpRequestFactory); restTemplate.setUriTemplateHandler(createUriTemplateHandler(baseUri)); restTemplate.setMessageConverters(createMessageConverters()); restTemplate.setInterceptors(createInterceptors()); - return restTemplate; } /** diff --git a/spring-credhub-core/src/main/java/org/springframework/credhub/core/OAuth2CredHubTemplate.java b/spring-credhub-core/src/main/java/org/springframework/credhub/core/OAuth2CredHubTemplate.java new file mode 100644 index 0000000..29f0089 --- /dev/null +++ b/spring-credhub-core/src/main/java/org/springframework/credhub/core/OAuth2CredHubTemplate.java @@ -0,0 +1,32 @@ +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); + + CredHubClient.configureRestTemplate(restTemplate, apiUriBase, + clientHttpRequestFactory); + + return restTemplate; + } + +} diff --git a/spring-credhub-starter/build.gradle b/spring-credhub-starter/build.gradle index 81d0f93..a7cda0d 100644 --- a/spring-credhub-starter/build.gradle +++ b/spring-credhub-starter/build.gradle @@ -16,10 +16,22 @@ description = 'Spring CredHub Starter' +apply plugin: 'org.springframework.boot' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath("org.springframework.boot:spring-boot-gradle-plugin:1.5.8.RELEASE") + } +} + dependencies { compile project(':spring-credhub-core') - compile group: 'org.springframework.boot', name: 'spring-boot-starter', version: "${springBootVersion}" + compile group: 'org.springframework.boot', name: 'spring-boot-starter' + optional group: 'org.springframework.security.oauth', name: 'spring-security-oauth2' optional(group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3') { exclude(module: 'commons-logging') } @@ -27,5 +39,5 @@ dependencies { optional group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0' optional group: 'io.netty', name: 'netty-all', version: '4.1.8.Final' - testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: "${springBootVersion}" + testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test' } diff --git a/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubAutoConfiguration.java b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubAutoConfiguration.java index 6d7d2ce..ee29849 100644 --- a/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubAutoConfiguration.java +++ b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubAutoConfiguration.java @@ -19,11 +19,13 @@ 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; 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.support.ClientOptions; @@ -44,7 +46,7 @@ public class CredHubAutoConfiguration { /** * Configuration properties for CredHub * - * @return a {@link CredHubProperties} bean + * @return a {@link CredHubProperties} bean */ @Bean @ConfigurationProperties(prefix = "spring.credhub") @@ -53,13 +55,14 @@ public class CredHubAutoConfiguration { } /** - * Create the {@link CredHubTemplate} that the application will use to interact with - * CredHub. + * Create the {@link CredHubTemplate} that the application will use to interact + * with CredHub. * * @return the {@link CredHubTemplate} bean */ @Bean - public CredHubTemplate credHubTemplate() { + @ConditionalOnMissingBean + public CredHubOperations credHubTemplate() { return credHubTemplateFactory.credHubTemplate(credHubProperties(), clientHttpRequestFactoryWrapper().getClientHttpRequestFactory()); } diff --git a/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubOAuth2AutoConfiguration.java b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubOAuth2AutoConfiguration.java new file mode 100644 index 0000000..2e30b8c --- /dev/null +++ b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/CredHubOAuth2AutoConfiguration.java @@ -0,0 +1,52 @@ +package org.springframework.credhub.autoconfig; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +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.core.CredHubOperations; +import org.springframework.credhub.core.CredHubProperties; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; + +/** + * Auto configure a {@link OAuth2RestTemplate} with + * {@link ClientCredentialsResourceDetails} if spring-security-oauth2 and proper + * properties are available. + * + * @author Daniel Lavoie + */ +@Configuration +@AutoConfigureBefore(CredHubAutoConfiguration.class) +@ConditionalOnProperty("spring.credhub.oauth2.client-id") +@ConditionalOnClass(name = "org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails") +public class CredHubOAuth2AutoConfiguration { + + public class CredHubOAuth2Configuration { + private final OAuth2CredHubTemplateFactory credHubTemplateFactory = new OAuth2CredHubTemplateFactory(); + + /** + * Bean that holds OAuth2 credential informations for CredHub. + */ + @Bean + public CredHubCredentialsDetails credHubCredentialsDetails() { + return new CredHubCredentialsDetails(); + } + + /** + * Preconfigured {@link OAuth2RestTemplate} with OAuth2 credentials for CredHub. + */ + @Bean + public CredHubOperations oauth2CredHubTemplate( + CredHubProperties credHubProperties, + ClientFactoryWrapper clientFactoryWrapper) { + return credHubTemplateFactory.credHubTemplate(credHubCredentialsDetails(), + credHubProperties, + clientFactoryWrapper.getClientHttpRequestFactory()); + } + } +} diff --git a/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/security/CredHubCredentialsDetails.java b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/security/CredHubCredentialsDetails.java new file mode 100644 index 0000000..6c666f5 --- /dev/null +++ b/spring-credhub-starter/src/main/java/org/springframework/credhub/autoconfig/security/CredHubCredentialsDetails.java @@ -0,0 +1,16 @@ +package org.springframework.credhub.autoconfig.security; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; + +/** + * Provides a {@link ClientCredentialsResourceDetails} for use to a + * {@link OAuth2RestTemplate}. + * + * @author Daniel Lavoie + */ +@ConfigurationProperties("spring.credhub.oauth2") +public class CredHubCredentialsDetails extends ClientCredentialsResourceDetails { + +} diff --git a/spring-credhub-starter/src/main/resources/META-INF/spring.factories b/spring-credhub-starter/src/main/resources/META-INF/spring.factories index 2925e54..7946c2e 100644 --- a/spring-credhub-starter/src/main/resources/META-INF/spring.factories +++ b/spring-credhub-starter/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.springframework.credhub.autoconfig.CredHubAutoConfiguration \ No newline at end of file +org.springframework.credhub.autoconfig.CredHubAutoConfiguration,\ +org.springframework.credhub.autoconfig.CredHubOAuth2AutoConfiguration \ No newline at end of file diff --git a/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubAutoConfigurationTest.java b/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubAutoConfigurationTest.java index 454e18a..217eacc 100644 --- a/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubAutoConfigurationTest.java +++ b/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubAutoConfigurationTest.java @@ -8,17 +8,25 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.credhub.configuration.CredHubAutoConfigurationTest.TestConfig; import org.springframework.credhub.core.CredHubTemplate; +import org.springframework.credhub.core.OAuth2CredHubTemplate; import org.springframework.test.context.junit4.SpringRunner; +/** + * @author Daniel Lavoie + */ @RunWith(SpringRunner.class) @SpringBootTest(classes = TestConfig.class, value = "spring.credhub.url=http://localhost") public class CredHubAutoConfigurationTest { @Autowired private CredHubTemplate credHubTemplate; + + @Autowired(required = false) + private OAuth2CredHubTemplate oauth2CredHubTemplate; @Test public void contextLoads() { Assert.assertNotNull(credHubTemplate); + Assert.assertNull(oauth2CredHubTemplate); } @SpringBootApplication diff --git a/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubOAuth2AutoConfigurationTest.java b/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubOAuth2AutoConfigurationTest.java new file mode 100644 index 0000000..f710b56 --- /dev/null +++ b/spring-credhub-starter/src/test/java/org/springframework/credhub/configuration/CredHubOAuth2AutoConfigurationTest.java @@ -0,0 +1,38 @@ +package org.springframework.credhub.configuration; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.credhub.configuration.CredHubOAuth2AutoConfigurationTest.TestConfig; +import org.springframework.credhub.core.CredHubOperations; +import org.springframework.credhub.core.OAuth2CredHubTemplate; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * @author Daniel Lavoie + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestConfig.class, value = { + "spring.credhub.url=https://localhost", + "spring.credhub.oauth2.client-id=test-user", "debug" }) +public class CredHubOAuth2AutoConfigurationTest { + @Autowired + private OAuth2CredHubTemplate oauth2CredHubTemplate; + + @Autowired + private CredHubOperations credHubOptions; + + @Test + public void contextLoads() { + Assert.assertNotNull(oauth2CredHubTemplate); + Assert.assertTrue(credHubOptions instanceof OAuth2CredHubTemplate); + } + + @SpringBootApplication + public static class TestConfig { + + } +}