From 9f4a5c13a574f24c44288c3e378345f4ae1c42d5 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 30 May 2018 17:58:55 -0700 Subject: [PATCH] Add auto-config for WebFlux OAuth2 Login Closes gh-13142 --- .../client/ClientsConfiguredCondition.java | 63 ++++++++++ ...h2ClientPropertiesRegistrationAdapter.java | 2 +- .../security/oauth2/client/package-info.java | 2 +- ...ReactiveOAuth2ClientAutoConfiguration.java | 43 +++++++ ...ntRegistrationRepositoryConfiguration.java | 60 +++++++++ ...eactiveOAuth2WebSecurityConfiguration.java | 44 +++++++ .../oauth2/client/reactive/package-info.java | 20 +++ .../OAuth2ClientAutoConfiguration.java | 2 +- ...ntRegistrationRepositoryConfiguration.java | 54 +-------- .../OAuth2WebSecurityConfiguration.java | 2 +- .../oauth2/client/servlet/package-info.java | 20 +++ .../main/resources/META-INF/spring.factories | 3 +- ...iveOAuth2ClientAutoConfigurationTests.java | 101 ++++++++++++++++ ...istrationRepositoryConfigurationTests.java | 65 ++++++++++ ...veOAuth2WebSecurityConfigurationTests.java | 114 ++++++++++++++++++ ...istrationRepositoryConfigurationTests.java | 2 +- .../OAuth2WebSecurityConfigurationTests.java | 2 +- .../main/asciidoc/spring-boot-features.adoc | 5 +- .../README.adoc | 12 ++ .../pom.xml | 59 +++++++++ .../oauth2/client/ExampleController.java | 32 +++++ ...SampleReactiveOAuth2ClientApplication.java | 29 +++++ .../src/main/resources/application.yml | 19 +++ ...eReactiveOAuth2ClientApplicationTests.java | 54 +++++++++ 24 files changed, 751 insertions(+), 58 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientAutoConfiguration.java (99%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientRegistrationRepositoryConfiguration.java (51%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2WebSecurityConfiguration.java (99%) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2ClientRegistrationRepositoryConfigurationTests.java (99%) rename spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/{ => servlet}/OAuth2WebSecurityConfigurationTests.java (99%) create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml create mode 100644 spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java new file mode 100644 index 00000000000..fcdbd72e4f7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/ClientsConfiguredCondition.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client; + +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * Condition that matches if any {@code spring.security.oauth2.client.registration} + * properties are defined. + */ +public class ClientsConfiguredCondition extends SpringBootCondition { + + private static final Bindable> BINDABLE_REGISTRATION = Bindable + .mapOf(String.class, OAuth2ClientProperties.Registration.class); + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + ConditionMessage.Builder message = ConditionMessage + .forCondition("OAuth2 Clients Configured Condition"); + Map registrations = this + .getRegistrations(context.getEnvironment()); + if (!registrations.isEmpty()) { + return ConditionOutcome.match(message + .foundExactly("registered clients " + registrations.values().stream() + .map(OAuth2ClientProperties.Registration::getClientId) + .collect(Collectors.joining(", ")))); + } + return ConditionOutcome.noMatch(message.notAvailable("registered clients")); + } + + private Map getRegistrations( + Environment environment) { + return Binder.get(environment) + .bind("spring.security.oauth2.client.registration", BINDABLE_REGISTRATION) + .orElse(Collections.emptyMap()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java index b0a76ddb2bb..ec4518d9e9f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientPropertiesRegistrationAdapter.java @@ -39,7 +39,7 @@ import org.springframework.util.StringUtils; * @author Thiago Hirata * @since 2.0.0 */ -final class OAuth2ClientPropertiesRegistrationAdapter { +public final class OAuth2ClientPropertiesRegistrationAdapter { private OAuth2ClientPropertiesRegistrationAdapter() { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java index 6437a3e8304..0cd3a5d08e4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/package-info.java @@ -15,6 +15,6 @@ */ /** - * Auto-configuration for Spring Security's OAuth 2 client. + * Support for Spring Security's OAuth 2 client. */ package org.springframework.boot.autoconfigure.security.oauth2.client; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java new file mode 100644 index 00000000000..dcaecfba661 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Security's Reactive + * OAuth2 client. + * + * @author Madhura Bhave + * @since 2.1.0 + */ +@Configuration +@AutoConfigureBefore(ReactiveSecurityAutoConfiguration.class) +@ConditionalOnClass({ EnableWebFluxSecurity.class, ClientRegistration.class }) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@Import({ ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class }) +public class ReactiveOAuth2ClientAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java new file mode 100644 index 00000000000..325ae96191a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfiguration.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +/** + * {@link Configuration} used to map {@link OAuth2ClientProperties} to client + * registrations. + * + * @author Madhura Bhave + */ +@Configuration +@EnableConfigurationProperties(OAuth2ClientProperties.class) +@Conditional(ClientsConfiguredCondition.class) +class ReactiveOAuth2ClientRegistrationRepositoryConfiguration { + + private final OAuth2ClientProperties properties; + + ReactiveOAuth2ClientRegistrationRepositoryConfiguration( + OAuth2ClientProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean(ReactiveClientRegistrationRepository.class) + public InMemoryReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>( + OAuth2ClientPropertiesRegistrationAdapter + .getClientRegistrations(this.properties).values()); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java new file mode 100644 index 00000000000..a1376e93fcb --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +/** + * {@link Configuration} used to create an in-memory + * {@link ReactiveOAuth2AuthorizedClientService}. + * + * @author Madhura Bhave + */ +@Configuration +public class ReactiveOAuth2WebSecurityConfiguration { + + @Bean + @ConditionalOnBean(ReactiveClientRegistrationRepository.class) + @ConditionalOnMissingBean + public ReactiveOAuth2AuthorizedClientService authorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java new file mode 100644 index 00000000000..4f9e03c3e82 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-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. + */ + +/** + * Auto-configuration for Spring Security's Reactive OAuth 2 client. + */ +package org.springframework.boot.autoconfigure.security.oauth2.client.reactive; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java index 5f2c1d513a3..3cd23fdbe26 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientAutoConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java similarity index 51% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java index 966924cffa2..8be5b23eb6c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfiguration.java @@ -14,28 +14,19 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.springframework.boot.autoconfigure.condition.ConditionMessage; -import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.SpringBootCondition; -import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties.Registration; +import org.springframework.boot.autoconfigure.security.oauth2.client.ClientsConfiguredCondition; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties; +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientPropertiesRegistrationAdapter; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.context.properties.bind.Bindable; -import org.springframework.boot.context.properties.bind.Binder; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ConditionContext; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.core.type.AnnotatedTypeMetadata; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; @@ -45,11 +36,10 @@ import org.springframework.security.oauth2.client.registration.InMemoryClientReg * registrations. * * @author Madhura Bhave - * @author Phillip Webb */ @Configuration @EnableConfigurationProperties(OAuth2ClientProperties.class) -@Conditional(OAuth2ClientRegistrationRepositoryConfiguration.ClientsConfiguredCondition.class) +@Conditional(ClientsConfiguredCondition.class) class OAuth2ClientRegistrationRepositoryConfiguration { private final OAuth2ClientProperties properties; @@ -67,38 +57,4 @@ class OAuth2ClientRegistrationRepositoryConfiguration { return new InMemoryClientRegistrationRepository(registrations); } - /** - * Condition that matches if any {@code spring.security.oauth2.client.registration} - * properties are defined. - */ - static class ClientsConfiguredCondition extends SpringBootCondition { - - private static final Bindable> BINDABLE_REGISTRATION = Bindable - .mapOf(String.class, OAuth2ClientProperties.Registration.class); - - @Override - public ConditionOutcome getMatchOutcome(ConditionContext context, - AnnotatedTypeMetadata metadata) { - ConditionMessage.Builder message = ConditionMessage - .forCondition("OAuth2 Clients Configured Condition"); - Map registrations = this - .getRegistrations(context.getEnvironment()); - if (!registrations.isEmpty()) { - return ConditionOutcome.match(message.foundExactly( - "registered clients " + registrations.values().stream() - .map(OAuth2ClientProperties.Registration::getClientId) - .collect(Collectors.joining(", ")))); - } - return ConditionOutcome.noMatch(message.notAvailable("registered clients")); - } - - private Map getRegistrations(Environment environment) { - return Binder.get(environment) - .bind("spring.security.oauth2.client.registration", - BINDABLE_REGISTRATION) - .orElse(Collections.emptyMap()); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java index 60e9494b7bd..953c41262cd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfiguration.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java new file mode 100644 index 00000000000..573079129a7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-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. + */ + +/** + * Auto-configuration for Spring Security's OAuth 2 client. + */ +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 424c6edb5a5..8abd511201e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -103,7 +103,8 @@ org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoCon org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\ org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\ -org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\ +org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\ org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\ org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java new file mode 100644 index 00000000000..99c69ba4c9e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientAutoConfigurationTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; +import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.oauth2.client.registration.ClientRegistration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2ClientAutoConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2ClientAutoConfigurationTests { + + private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(ReactiveOAuth2ClientAutoConfiguration.class)); + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + + @Test + public void autoConfigurationShouldImportConfigurations() { + this.contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { + assertThat(context).hasSingleBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context) + .hasSingleBean(ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnClassEnableWebFluxSecurity() { + FilteredClassLoader classLoader = new FilteredClassLoader( + EnableWebFluxSecurity.class); + this.contextRunner.withClassLoader(classLoader) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnClassClientRegistration() { + FilteredClassLoader classLoader = new FilteredClassLoader( + ClientRegistration.class); + this.contextRunner.withClassLoader(classLoader) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + + @Test + public void autoConfigurationConditionalOnReactiveWebApplication() { + WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withConfiguration(AutoConfigurations + .of(ReactiveOAuth2ClientAutoConfiguration.class)); + contextRunner.withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github").run((context) -> { + assertThat(context).doesNotHaveBean( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class); + assertThat(context).doesNotHaveBean( + ReactiveOAuth2WebSecurityConfiguration.class); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java new file mode 100644 index 00000000000..4ca71fc738f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import org.junit.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2ClientRegistrationRepositoryConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2ClientRegistrationRepositoryConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + private static final String REGISTRATION_PREFIX = "spring.security.oauth2.client.registration"; + + @Test + public void clientRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ClientRegistrationRepository.class)); + } + + @Test + public void clientRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() { + this.contextRunner + .withUserConfiguration( + ReactiveOAuth2ClientRegistrationRepositoryConfiguration.class) + .withPropertyValues(REGISTRATION_PREFIX + ".foo.client-id=abcd", + REGISTRATION_PREFIX + ".foo.client-secret=secret", + REGISTRATION_PREFIX + ".foo.provider=github") + .run((context) -> { + ReactiveClientRegistrationRepository repository = context + .getBean(ReactiveClientRegistrationRepository.class); + ClientRegistration registration = repository + .findByRegistrationId("foo").block(); + assertThat(registration).isNotNull(); + assertThat(registration.getClientSecret()).isEqualTo("secret"); + }); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java new file mode 100644 index 00000000000..4d1b9016324 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/reactive/ReactiveOAuth2WebSecurityConfigurationTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-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.boot.autoconfigure.security.oauth2.client.reactive; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.InMemoryReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository; +import org.springframework.security.oauth2.core.AuthorizationGrantType; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ReactiveOAuth2WebSecurityConfiguration}. + * + * @author Madhura Bhave + */ +public class ReactiveOAuth2WebSecurityConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(); + + @Test + public void authorizedClientServiceBeanIsConditionalOnClientRegistrationRepository() { + this.contextRunner + .withUserConfiguration(ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveOAuth2AuthorizedClientService.class)); + } + + @Test + public void configurationRegistersAuthorizedClientServiceBean() { + this.contextRunner + .withUserConfiguration(ReactiveClientRepositoryConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class)); + } + + @Test + public void authorizedClientServiceBeanIsConditionalOnMissingBean() { + this.contextRunner + .withUserConfiguration(OAuth2AuthorizedClientServiceConfiguration.class, + ReactiveOAuth2WebSecurityConfiguration.class) + .run((context) -> { + assertThat(context) + .hasSingleBean(ReactiveOAuth2AuthorizedClientService.class); + assertThat(context).hasBean("testAuthorizedClientService"); + }); + } + + @Configuration + static class ReactiveClientRepositoryConfiguration { + + @Bean + public ReactiveClientRegistrationRepository clientRegistrationRepository() { + List registrations = new ArrayList<>(); + registrations.add(getClientRegistration("first", "http://user-info-uri.com")); + registrations.add(getClientRegistration("second", "http://other-user-info")); + return new InMemoryReactiveClientRegistrationRepository(registrations); + } + + private ClientRegistration getClientRegistration(String id, String userInfoUri) { + ClientRegistration.Builder builder = ClientRegistration + .withRegistrationId(id); + builder.clientName("foo").clientId("foo").clientAuthenticationMethod( + org.springframework.security.oauth2.core.ClientAuthenticationMethod.BASIC) + .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) + .scope("read").clientSecret("secret") + .redirectUriTemplate("http://redirect-uri.com") + .authorizationUri("http://authorization-uri.com") + .tokenUri("http://token-uri.com").userInfoUri(userInfoUri) + .userNameAttributeName("login"); + return builder.build(); + } + + } + + @Configuration + @Import(ReactiveClientRepositoryConfiguration.class) + static class OAuth2AuthorizedClientServiceConfiguration { + + @Bean + public ReactiveOAuth2AuthorizedClientService testAuthorizedClientService( + ReactiveClientRegistrationRepository clientRegistrationRepository) { + return new InMemoryReactiveOAuth2AuthorizedClientService( + clientRegistrationRepository); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java index a7a6639be6f..039f4c476b5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2ClientRegistrationRepositoryConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2ClientRegistrationRepositoryConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import org.junit.Test; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java similarity index 99% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java index efba0c68e0a..d6803ce5d01 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/OAuth2WebSecurityConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/client/servlet/OAuth2WebSecurityConfigurationTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.security.oauth2.client; +package org.springframework.boot.autoconfigure.security.oauth2.client.servlet; import java.util.ArrayList; import java.util.List; diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 6e362044b18..e1fea87b01c 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -3151,7 +3151,8 @@ Spring. ==== Client If you have `spring-security-oauth2-client` on your classpath, you can take advantage of some auto-configuration to make it easy to set up an OAuth2 Client. This configuration -makes use of the properties under `OAuth2ClientProperties`. +makes use of the properties under `OAuth2ClientProperties`. The same properties are applicable +for both servlet and reactive applications. You can register multiple OAuth2 clients and providers under the `spring.security.oauth2.client` prefix, as shown in the following example: @@ -3186,7 +3187,7 @@ You can register multiple OAuth2 clients and providers under the By default, Spring Security's `OAuth2LoginAuthenticationFilter` only processes URLs matching `/login/oauth2/code/*`. If you want to customize the `redirect-uri-template` to use a different pattern, you need to provide configuration to process that custom pattern. -For example, you can add your own `WebSecurityConfigurerAdapter` that resembles the +For example, for servlet applications, you can add your own `WebSecurityConfigurerAdapter` that resembles the following: [source,java,indent=0] diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc new file mode 100644 index 00000000000..ba8ce9869f2 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/README.adoc @@ -0,0 +1,12 @@ += Spring Boot Sample Reactive OAuth2 Client + +== Register Github OAuth2 application +To run the sample, you need to link:https://github.com/settings/applications/new[register an OAuth application on Github]. +While registering your application, ensure the Authorization callback URL is set to http://localhost:8080/login/oauth2/code/github. +After completing the registration, you will have a new OAuth Application with a Client ID and Client Secret. + +== Configuring application.yml +Once the OAuth application is registered with GitHub, you need to configure the sample application to use this OAuth application (client). +Edit the link:src/main/resources/application.yml[application.yml] and replace ${APP-CLIENT-ID} and ${APP-CLIENT-SECRET} with the OAuth client credentials created in the previous section. + +The sample can now be run and you can login with your Github user credentials. diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml new file mode 100644 index 00000000000..69c4759b16f --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/pom.xml @@ -0,0 +1,59 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-samples + ${revision} + + spring-boot-sample-reactive-oauth2-client + Spring Boot Sample Reactive OAuth2 Client + Spring Boot Sample Reactive OAuth2 Client + + ${basedir}/../.. + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-webflux + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-oauth2-client + + + org.springframework.security + spring-security-oauth2-jose + + + + org.apache.httpcomponents + httpclient + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java new file mode 100644 index 00000000000..90cc03ac182 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/ExampleController.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-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 sample.oauth2.client; + +import java.security.Principal; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ExampleController { + + @RequestMapping("/") + public String email(Principal principal) { + return "Hello " + principal.getName(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java new file mode 100644 index 00000000000..0b4b49e8d59 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplication.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-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 sample.oauth2.client; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleReactiveOAuth2ClientApplication { + + public static void main(String[] args) { + SpringApplication.run(SampleReactiveOAuth2ClientApplication.class); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml new file mode 100644 index 00000000000..220007d7e4b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + security: + oauth2: + client: + registration: + github-client-1: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github user + provider: github + scope: user + redirect-uri-template: http://localhost:8080/login/oauth2/code/github + github-client-2: + client-id: ${APP-CLIENT-ID} + client-secret: ${APP-CLIENT-SECRET} + client-name: Github email + provider: github + scope: user:email + redirect-uri-template: http://localhost:8080/login/oauth2/code/github \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java new file mode 100644 index 00000000000..74fd195dac6 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-reactive-oauth2-client/src/test/java/sample/oauth2/client/SampleReactiveOAuth2ClientApplicationTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-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 sample.oauth2.client; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.reactive.server.WebTestClient; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = { + "APP-CLIENT-ID=my-client-id", "APP-CLIENT-SECRET=my-client-secret" }) +public class SampleReactiveOAuth2ClientApplicationTests { + + @Autowired + private WebTestClient webTestClient; + + @Test + public void everythingShouldRedirectToLogin() { + this.webTestClient.get().uri("/").exchange() + .expectStatus().isFound() + .expectHeader().valueEquals("Location", "/login"); + } + + @Test + public void loginShouldHaveBothOAuthClientsToChooseFrom() { + byte[] body = this.webTestClient.get().uri("/login").exchange() + .expectStatus().isOk() + .returnResult(String.class).getResponseBodyContent(); + String bodyString = new String(body); + assertThat(bodyString).contains("/oauth2/authorization/github-client-1"); + assertThat(bodyString).contains("/oauth2/authorization/github-client-2"); + } + +}