From 79341986fec8b663f5a3c059e61823c24765d9ec Mon Sep 17 00:00:00 2001 From: Craig Walls Date: Fri, 10 Nov 2017 10:19:18 -0500 Subject: [PATCH] Spring Social carries its own auto-configuration --- build.gradle | 10 + gradle.properties | 1 + settings.gradle | 1 + .../SocialAutoConfigurerAdapter.java | 41 ++++ .../autoconfigure/SocialProperties.java | 55 ++++++ .../SocialWebAutoConfiguration.java | 187 ++++++++++++++++++ .../social/autoconfigure/package-info.java | 20 ++ ...itional-spring-configuration-metadata.json | 8 + .../main/resources/META-INF/spring.factories | 3 + 9 files changed, 326 insertions(+) create mode 100644 spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialAutoConfigurerAdapter.java create mode 100644 spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialProperties.java create mode 100644 spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialWebAutoConfiguration.java create mode 100644 spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/package-info.java create mode 100644 spring-social-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json create mode 100644 spring-social-autoconfigure/src/main/resources/META-INF/spring.factories diff --git a/build.gradle b/build.gradle index 21c4e642f..d1c4af82d 100644 --- a/build.gradle +++ b/build.gradle @@ -250,6 +250,16 @@ project("spring-social-security") { } } +project("spring-social-autoconfigure") { + description = "Spring Social Boot Auto-Configuration" + dependencies { + compile project(":spring-social-config") + compile project(":spring-social-core") + compile project(":spring-social-web") + compile("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion") + } +} + configure(rootProject) { description = "Spring Social" diff --git a/gradle.properties b/gradle.properties index e2b84cb24..43965a12d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,4 @@ mockitoVersion=2.11.0 javaxInjectVersion=1 thymeleaf3Version=3.0.8.RELEASE thymeleafSpring5Version=3.0.8.RELEASE +springBootVersion=2.0.0.M6 diff --git a/settings.gradle b/settings.gradle index 2770d3989..cb006b581 100644 --- a/settings.gradle +++ b/settings.gradle @@ -24,3 +24,4 @@ include 'spring-social-core' include 'spring-social-web' include 'spring-social-config' include 'spring-social-security' +include 'spring-social-autoconfigure' diff --git a/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialAutoConfigurerAdapter.java b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialAutoConfigurerAdapter.java new file mode 100644 index 000000000..eae8d33b0 --- /dev/null +++ b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialAutoConfigurerAdapter.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-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.social.autoconfigure; + +import org.springframework.core.env.Environment; +import org.springframework.social.config.annotation.ConnectionFactoryConfigurer; +import org.springframework.social.config.annotation.SocialConfigurerAdapter; +import org.springframework.social.connect.ConnectionFactory; + +/** + * Base class for auto-configured {@link SocialConfigurerAdapter}s. + * + * @author Craig Walls + * @author Phillip Webb + * @since 1.4.0 + */ +public abstract class SocialAutoConfigurerAdapter extends SocialConfigurerAdapter { + + @Override + public void addConnectionFactories(ConnectionFactoryConfigurer configurer, + Environment environment) { + configurer.addConnectionFactory(createConnectionFactory()); + } + + protected abstract ConnectionFactory createConnectionFactory(); + +} diff --git a/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialProperties.java b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialProperties.java new file mode 100644 index 000000000..6a1c31ba0 --- /dev/null +++ b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialProperties.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-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.social.autoconfigure; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Base {@link ConfigurationProperties properties} for spring social. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public abstract class SocialProperties { + + /** + * Application id. + */ + private String appId; + + /** + * Application secret. + */ + private String appSecret; + + public String getAppId() { + return this.appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppSecret() { + return this.appSecret; + } + + public void setAppSecret(String appSecret) { + this.appSecret = appSecret; + } + +} diff --git a/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialWebAutoConfiguration.java b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialWebAutoConfiguration.java new file mode 100644 index 000000000..9d8ff57af --- /dev/null +++ b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/SocialWebAutoConfiguration.java @@ -0,0 +1,187 @@ +/* + * Copyright 2012-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.social.autoconfigure; + +import java.util.List; + +import org.thymeleaf.spring5.SpringTemplateEngine; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.social.UserIdSource; +import org.springframework.social.config.annotation.EnableSocial; +import org.springframework.social.config.annotation.SocialConfigurerAdapter; +import org.springframework.social.connect.ConnectionFactoryLocator; +import org.springframework.social.connect.ConnectionRepository; +import org.springframework.social.connect.UsersConnectionRepository; +import org.springframework.social.connect.web.ConnectController; +import org.springframework.social.connect.web.ConnectInterceptor; +import org.springframework.social.connect.web.DisconnectInterceptor; +import org.springframework.social.connect.web.ProviderSignInController; +import org.springframework.social.connect.web.ProviderSignInInterceptor; +import org.springframework.social.connect.web.SignInAdapter; +import org.springframework.social.connect.web.thymeleaf.SpringSocialDialect; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.web.servlet.view.BeanNameViewResolver; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Social's web connection + * support. + * + * @author Craig Walls + * @since 1.1.0 + */ +@Configuration +@ConditionalOnClass({ ConnectController.class, SocialConfigurerAdapter.class }) +@ConditionalOnBean({ ConnectionFactoryLocator.class, UsersConnectionRepository.class }) +@AutoConfigureBefore(ThymeleafAutoConfiguration.class) +@AutoConfigureAfter(WebMvcAutoConfiguration.class) +public class SocialWebAutoConfiguration { + + @Configuration + @EnableSocial + @ConditionalOnWebApplication(type = Type.SERVLET) + protected static class SocialAutoConfigurationAdapter + extends SocialConfigurerAdapter { + + private final List> connectInterceptors; + + private final List> disconnectInterceptors; + + private final List> signInInterceptors; + + public SocialAutoConfigurationAdapter( + ObjectProvider>> connectInterceptorsProvider, + ObjectProvider>> disconnectInterceptorsProvider, + ObjectProvider>> signInInterceptorsProvider) { + this.connectInterceptors = connectInterceptorsProvider.getIfAvailable(); + this.disconnectInterceptors = disconnectInterceptorsProvider.getIfAvailable(); + this.signInInterceptors = signInInterceptorsProvider.getIfAvailable(); + } + + @Bean + @ConditionalOnMissingBean(ConnectController.class) + public ConnectController connectController( + ConnectionFactoryLocator factoryLocator, + ConnectionRepository repository) { + ConnectController controller = new ConnectController(factoryLocator, + repository); + if (!CollectionUtils.isEmpty(this.connectInterceptors)) { + controller.setConnectInterceptors(this.connectInterceptors); + } + if (!CollectionUtils.isEmpty(this.disconnectInterceptors)) { + controller.setDisconnectInterceptors(this.disconnectInterceptors); + } + return controller; + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = "spring.social", name = "auto-connection-views") + public BeanNameViewResolver beanNameViewResolver() { + BeanNameViewResolver viewResolver = new BeanNameViewResolver(); + viewResolver.setOrder(Ordered.HIGHEST_PRECEDENCE); + return viewResolver; + } + + @Bean + @ConditionalOnBean(SignInAdapter.class) + @ConditionalOnMissingBean + public ProviderSignInController signInController( + ConnectionFactoryLocator factoryLocator, + UsersConnectionRepository usersRepository, SignInAdapter signInAdapter) { + ProviderSignInController controller = new ProviderSignInController( + factoryLocator, usersRepository, signInAdapter); + if (!CollectionUtils.isEmpty(this.signInInterceptors)) { + controller.setSignInInterceptors(this.signInInterceptors); + } + return controller; + } + + } + + @Configuration + @EnableSocial + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnMissingClass("org.springframework.security.core.context.SecurityContextHolder") + protected static class AnonymousUserIdSourceConfig extends SocialConfigurerAdapter { + + @Override + public UserIdSource getUserIdSource() { + return () -> "anonymous"; + } + + } + + @Configuration + @EnableSocial + @ConditionalOnWebApplication(type = Type.SERVLET) + @ConditionalOnClass(SecurityContextHolder.class) + protected static class AuthenticationUserIdSourceConfig + extends SocialConfigurerAdapter { + + @Override + public UserIdSource getUserIdSource() { + return new SecurityContextUserIdSource(); + } + + } + + @Configuration + @ConditionalOnClass(SpringTemplateEngine.class) + protected static class SpringSocialThymeleafConfig { + + @Bean + @ConditionalOnMissingBean + public SpringSocialDialect springSocialDialect() { + return new SpringSocialDialect(); + } + + } + + private static class SecurityContextUserIdSource implements UserIdSource { + + @Override + public String getUserId() { + SecurityContext context = SecurityContextHolder.getContext(); + Authentication authentication = context.getAuthentication(); + Assert.state(authentication != null, + "Unable to get a ConnectionRepository: no user signed in"); + return authentication.getName(); + } + + } + +} diff --git a/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/package-info.java b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/package-info.java new file mode 100644 index 000000000..54ae5b39b --- /dev/null +++ b/spring-social-autoconfigure/src/main/java/org/springframework/social/autoconfigure/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-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. + */ + +/** + * Auto-configuration for Spring Social. + */ + package org.springframework.social.autoconfigure; diff --git a/spring-social-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-social-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..268a4763f --- /dev/null +++ b/spring-social-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,8 @@ +{"properties": [ + { + "name": "spring.social.auto-connection-views", + "type": "java.lang.Boolean", + "description": "Enable the connection status view for supported providers.", + "defaultValue": false + } +]} diff --git a/spring-social-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-social-autoconfigure/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..858212ab1 --- /dev/null +++ b/spring-social-autoconfigure/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.springframework.social.autoconfigure.SocialWebAutoConfiguration