From c0c92426107de6a10754b4548833f6266afaa94a Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Sun, 12 Jun 2016 14:31:42 +0200 Subject: [PATCH] Enabled autoconfiguration for Spring-Social and Spring-Security-OAuth2 --- pom.xml | 17 ++- ...FacebookErrorsOAuth2AutoConfiguration.java | 75 +++++++++++ ...okErrorsSpringSocialAutoConfiguration.java | 92 ++++++++++++++ src/main/resources/META-INF/spring.factories | 3 + ...bookErrorsOAuth2AutoConfigurationTest.java | 116 ++++++++++++++++++ ...rorsSpringSocialAutoConfigurationTest.java | 111 +++++++++++++++++ src/test/resources/logback-test.xml | 4 + 7 files changed, 417 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfiguration.java create mode 100644 src/main/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfiguration.java create mode 100644 src/main/resources/META-INF/spring.factories create mode 100644 src/test/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfigurationTest.java create mode 100644 src/test/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfigurationTest.java diff --git a/pom.xml b/pom.xml index e06266b..84b68e9 100644 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,12 @@ - + + + org.springframework.boot + spring-boot-autoconfigure + true + org.springframework.social spring-social-facebook @@ -99,6 +104,16 @@ spring-test test + + org.springframework.boot + spring-boot-configuration-processor + test + + + javax.servlet + javax.servlet-api + test + junit junit diff --git a/src/main/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfiguration.java b/src/main/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfiguration.java new file mode 100644 index 0000000..082b0d6 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfiguration.java @@ -0,0 +1,75 @@ +package de.juplo.facebook.errors; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler; + + +/** + * Automatic configuration for Srping-Security-OAuth2 + * + * @author Kai Moritz + */ +@Configuration +@ConditionalOnClass(value = OAuth2RestTemplate.class) +@AutoConfigureAfter({ + WebMvcAutoConfiguration.class, + OAuth2AutoConfiguration.class + }) +public class FacebookErrorsOAuth2AutoConfiguration +{ + private static final Logger LOG = + LoggerFactory.getLogger(FacebookErrorsOAuth2AutoConfiguration.class); + + @Bean + static public BeanPostProcessor errorHandlerInjectorOAuth2() + { + LOG.info("Configuring OAuth2GraphApiErrorHandler for handling error-messages"); + + return new BeanPostProcessor() + { + @Override + public Object postProcessBeforeInitialization( + Object bean, + String beanName + ) + throws + BeansException + { + if (bean instanceof OAuth2RestTemplate) + { + LOG.debug("Injecting OAuth2GraphApiErrorHandler in {}", bean); + OAuth2RestTemplate template = (OAuth2RestTemplate) bean; + template.setErrorHandler( + new OAuth2GraphApiErrorHandler( + (OAuth2ErrorHandler)template.getErrorHandler() + ) + ); + } + + return bean; + } + + @Override + public Object postProcessAfterInitialization( + Object bean, + String beanName + ) + throws + BeansException + { + return bean; + } + }; + } +} diff --git a/src/main/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfiguration.java b/src/main/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfiguration.java new file mode 100644 index 0000000..f474be8 --- /dev/null +++ b/src/main/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfiguration.java @@ -0,0 +1,92 @@ +package de.juplo.facebook.errors; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration; +import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.social.facebook.api.Facebook; +import org.springframework.social.facebook.api.impl.FacebookTemplate; +import org.springframework.web.client.ResponseErrorHandler; +import org.springframework.web.client.RestTemplate; + + + +/** + * Automatic configuration for Srping-Social-Facebook + * + * @author Kai Moritz + */ +@Configuration +@ConditionalOnClass(value = FacebookTemplate.class) +@AutoConfigureAfter({ + WebMvcAutoConfiguration.class, + FacebookAutoConfiguration.class + }) +public class FacebookErrorsSpringSocialAutoConfiguration +{ + private static final Logger LOG = + LoggerFactory.getLogger(FacebookErrorsSpringSocialAutoConfiguration.class); + + + @Bean + static public BeanPostProcessor errorHandlerInjectorSpringSocial() + { + LOG.info("Configuring GraphApiErrorHandler for handling error-messages"); + return new BeanPostProcessor() + { + @Override + public Object postProcessBeforeInitialization( + Object bean, + String beanName + ) + throws + BeansException + { + return bean; + } + + @Override + public Object postProcessAfterInitialization( + Object bean, + String beanName + ) + throws + BeansException + { + if (bean instanceof Facebook) + { + try + { + Facebook facebook = (Facebook) bean; + RestTemplate template = (RestTemplate) facebook.restOperations(); + ResponseErrorHandler handler = template.getErrorHandler(); + template.setErrorHandler(new GraphApiErrorHandler(handler)); + // Be sure, that the potential exception is triggered before! + LOG.debug("Injecting GraphApiErrorHandler in {}", facebook); + } + catch (BeanCreationException e) + { + /** + * This exception is called, if the BeanPostProcessor is called + * with a scoped bean, while the according scope is not + * accessible. + * This happens during initialization and can safely be ignored, + * because we only have to inject the handler for beans, that are + * actually usable. + */ + } + } + + return bean; + } + }; + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..96f4bdd --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +de.juplo.facebook.errors.SpringSocialAutoConfiguration,\ +de.juplo.facebook.errors.OAuth2AutoConfiguration diff --git a/src/test/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfigurationTest.java b/src/test/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfigurationTest.java new file mode 100644 index 0000000..7c1e156 --- /dev/null +++ b/src/test/java/de/juplo/facebook/errors/FacebookErrorsOAuth2AutoConfigurationTest.java @@ -0,0 +1,116 @@ +package de.juplo.facebook.errors; + + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.junit.After; +import org.junit.Test; +import org.springframework.context.annotation.Configuration; +import static org.junit.Assert.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer; +import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + + + +public class FacebookErrorsOAuth2AutoConfigurationTest +{ + private final Logger LOG = + LoggerFactory.getLogger(FacebookErrorsOAuth2AutoConfigurationTest.class); + + + private ConfigurableApplicationContext context; + + + @After + public void tearDown() + { + if (this.context != null) + this.context.close(); + } + + + @Test + public void defaultNonWebConfiguration() + { + LOG.info("<-- Start Of New Test-Case!"); + Map properties = new HashMap<>(); + properties.put("security.oauth2.client.client-id", "CLIENT_ID"); + context = loadNonWebApplicationContext(EmptyConfiguration.class, properties); + OAuth2RestTemplate template = context.getBean(OAuth2RestTemplate.class); + assertEquals(OAuth2GraphApiErrorHandler.class, template.getErrorHandler().getClass()); + } + + @Test + public void defaultWebConfiguration() + { + LOG.info("<-- Start Of New Test-Case!"); + Map properties = new HashMap<>(); + properties.put("security.oauth2.client.client-id", "CLIENT_ID"); + context = loadWebApplicationContext(EmptyConfiguration.class, properties); + OAuth2RestTemplate template = context.getBean(OAuth2RestTemplate.class); + assertEquals(OAuth2GraphApiErrorHandler.class, template.getErrorHandler().getClass()); + } + + + @Configuration + static class EmptyConfiguration + { + } + + + private ConfigurableApplicationContext loadNonWebApplicationContext( + Class config, + Map properties + ) + { + AnnotationConfigApplicationContext ctx = + new AnnotationConfigApplicationContext(); + if (properties != null) + { + MockEnvironment env = new MockEnvironment(); + for (Entry entry : properties.entrySet()) + env.withProperty(entry.getKey(), entry.getValue()); + ctx.setEnvironment(env); + } + ctx.register(FacebookErrorsOAuth2AutoConfiguration.class); + ctx.register(OAuth2AutoConfiguration.class); + ctx.register(config); + AutoConfigurationReportLoggingInitializer report = + new AutoConfigurationReportLoggingInitializer(); + report.initialize(ctx); + ctx.refresh(); + return ctx; + } + + private ConfigurableApplicationContext loadWebApplicationContext( + Class config, + Map properties + ) + { + AnnotationConfigWebApplicationContext ctx = + new AnnotationConfigWebApplicationContext(); + if (properties != null) + { + MockEnvironment env = new MockEnvironment(); + for (Entry entry : properties.entrySet()) + env.withProperty(entry.getKey(), entry.getValue()); + ctx.setEnvironment(env); + } + ctx.register(FacebookErrorsOAuth2AutoConfiguration.class); + ctx.register(OAuth2AutoConfiguration.class); + ctx.register(config); + AutoConfigurationReportLoggingInitializer report = + new AutoConfigurationReportLoggingInitializer(); + report.initialize(ctx); + ctx.refresh(); + return ctx; + } +} diff --git a/src/test/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfigurationTest.java b/src/test/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfigurationTest.java new file mode 100644 index 0000000..651ced5 --- /dev/null +++ b/src/test/java/de/juplo/facebook/errors/FacebookErrorsSpringSocialAutoConfigurationTest.java @@ -0,0 +1,111 @@ +package de.juplo.facebook.errors; + + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.junit.After; +import org.junit.Test; +import org.springframework.context.annotation.Configuration; +import static org.junit.Assert.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer; +import org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration; +import org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.mock.env.MockEnvironment; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.social.connect.ConnectionRepository; +import org.springframework.social.facebook.api.Facebook; +import org.springframework.social.facebook.api.impl.FacebookTemplate; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + + + +public class FacebookErrorsSpringSocialAutoConfigurationTest +{ + private final Logger LOG = + LoggerFactory.getLogger(FacebookErrorsSpringSocialAutoConfigurationTest.class); + + + private ConfigurableApplicationContext context; + + + @After + public void tearDown() + { + if (this.context != null) + this.context.close(); + } + + + @Test + public void defaultConfiguration() + { + LOG.info("<-- Start Of New Test-Case!"); + Map properties = new HashMap<>(); + properties.put("spring.social.facebook.app-id", "APP_ID"); + properties.put("spring.social.facebook.app-secret", "APP_SECRET"); + context = loadWebApplicationContext(EmptyConfiguration.class, properties); + Facebook facebook = context.getBean("facebook", Facebook.class); + RestTemplate template = (RestTemplate) facebook.restOperations(); + assertEquals(GraphApiErrorHandler.class, template.getErrorHandler().getClass()); + } + + + @Configuration + static class EmptyConfiguration + { + /** + * We have to provide this scoped bean for all our tests. + * Otherwise, the tests will fail, if we do not set up a complete + * environment with a connection-repository and a properly mocked request, + * that holds appropriate information to fetch a connection from that + * repository. + * @param repository + * @return + */ + @Bean + @Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES) + public Facebook facebook(ConnectionRepository repository) + { + return new FacebookTemplate("ACCESS_TOKEN"); + } + } + + + private ConfigurableApplicationContext loadWebApplicationContext( + Class config, + Map properties + ) + { + AnnotationConfigWebApplicationContext ctx = + new AnnotationConfigWebApplicationContext(); + if (properties != null) + { + MockEnvironment env = new MockEnvironment(); + for (Entry entry : properties.entrySet()) + env.withProperty(entry.getKey(), entry.getValue()); + ctx.setEnvironment(env); + } + ctx.register(FacebookErrorsSpringSocialAutoConfiguration.class); + ctx.register(FacebookAutoConfiguration.class); + ctx.register(SocialWebAutoConfiguration.class); + ctx.register(config); + AutoConfigurationReportLoggingInitializer report = + new AutoConfigurationReportLoggingInitializer(); + report.initialize(ctx); + MockHttpServletRequest request = new MockHttpServletRequest(); + ServletRequestAttributes attributes = new ServletRequestAttributes(request); + RequestContextHolder.setRequestAttributes(attributes); + ctx.refresh(); + return ctx; + } +} diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml index 0638ecb..e6f6c58 100644 --- a/src/test/resources/logback-test.xml +++ b/src/test/resources/logback-test.xml @@ -11,6 +11,10 @@ + + + + -- 2.20.1