From 3c284871c31e044df524dd7dc574937b0467752a Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Fri, 14 Oct 2016 16:12:47 -0400 Subject: [PATCH] INT-4139: Add CORS Config to Graph Annotation JIRA: https://jira.spring.io/browse/INT-4139 Doc Polishing Polishing - Fix CORS Test and Revert XML - Use standard CORS configuration with XML. --- .../EnableIntegrationGraphController.java | 8 +++++ .../IntegrationGraphControllerRegistrar.java | 33 +++++++++++++++++++ .../IntegrationGraphControllerTests.java | 28 ++++++++-------- src/reference/asciidoc/graph.adoc | 17 +++------- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/config/EnableIntegrationGraphController.java b/spring-integration-http/src/main/java/org/springframework/integration/http/config/EnableIntegrationGraphController.java index d44ce5b9f9..3fd363dac7 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/config/EnableIntegrationGraphController.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/config/EnableIntegrationGraphController.java @@ -58,4 +58,12 @@ public @interface EnableIntegrationGraphController { @AliasFor("value") String path() default HttpContextUtils.GRAPH_CONTROLLER_DEFAULT_PATH; + /** + * Specify allowed origin URLs for cross-origin request handling. + * Only allows GET operations. + * @return the URLs. + * @since 4.3.5 + */ + String[] allowedOrigins() default {}; + } diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/config/IntegrationGraphControllerRegistrar.java b/spring-integration-http/src/main/java/org/springframework/integration/http/config/IntegrationGraphControllerRegistrar.java index da0fcb01fc..24899c9c27 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/config/IntegrationGraphControllerRegistrar.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/config/IntegrationGraphControllerRegistrar.java @@ -39,9 +39,14 @@ import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.http.management.IntegrationGraphController; import org.springframework.integration.http.support.HttpContextUtils; import org.springframework.integration.support.management.graph.IntegrationGraphServer; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; /** + * Registers the necessary beans for {@link EnableIntegrationGraphController}. + * * @author Artem Bilan + * @author Gary Russell * @since 4.3 */ class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistrar { @@ -56,6 +61,16 @@ class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistr new RootBeanDefinition(IntegrationGraphServer.class)); } + String[] allowedOrigins = (String[]) annotationAttributes.get("allowedOrigins"); + if (allowedOrigins != null && allowedOrigins.length > 0) { + AbstractBeanDefinition controllerCorsConfigurer = + BeanDefinitionBuilder.genericBeanDefinition(IntegrationGraphCorsConfigurer.class) + .addConstructorArgValue(annotationAttributes.get("value")) + .addConstructorArgValue(allowedOrigins) + .getBeanDefinition(); + BeanDefinitionReaderUtils.registerWithGeneratedName(controllerCorsConfigurer, registry); + } + if (!registry.containsBeanDefinition(HttpContextUtils.GRAPH_CONTROLLER_BEAN_NAME)) { AbstractBeanDefinition controllerPropertiesPopulator = BeanDefinitionBuilder.genericBeanDefinition(GraphControllerPropertiesPopulator.class) @@ -98,4 +113,22 @@ class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistr } + private static final class IntegrationGraphCorsConfigurer extends WebMvcConfigurerAdapter { + + private final String path; + + private final String[] allowedOrigins; + + private IntegrationGraphCorsConfigurer(String path, String[] allowedOrigins) { + this.path = path; + this.allowedOrigins = allowedOrigins; + } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping(this.path).allowedOrigins(this.allowedOrigins).allowedMethods("GET"); + } + + } + } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/management/IntegrationGraphControllerTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/management/IntegrationGraphControllerTests.java index 6f5b366bab..50b5cade3f 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/management/IntegrationGraphControllerTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/management/IntegrationGraphControllerTests.java @@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler; @@ -37,7 +38,6 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.integration.channel.DirectChannel; @@ -55,15 +55,15 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; /** * @author Artem Bilan + * @author Gary Russell * @since 4.3 */ @RunWith(SpringJUnit4ClassRunner.class) @@ -121,6 +121,11 @@ public class IntegrationGraphControllerTests { Object handler = executionChain.getHandler(); + for (HandlerInterceptor handlerInterceptor : executionChain.getInterceptors()) { + // Assert the CORS config + assertTrue(handlerInterceptor.preHandle(request, response, handler)); + } + handlerAdapter.handle(request, response, handler); assertEquals(HttpStatus.OK.value(), response.getStatus()); assertThat(response.getContentAsString(), containsString("\"name\":\"nullChannel\",")); @@ -138,6 +143,11 @@ public class IntegrationGraphControllerTests { handler = executionChain.getHandler(); + for (HandlerInterceptor handlerInterceptor : executionChain.getInterceptors()) { + // Assert the CORS config + assertTrue(handlerInterceptor.preHandle(request, response, handler)); + } + handlerAdapter.handle(request, response, handler); assertEquals(HttpStatus.OK.value(), response.getStatus()); assertThat(response.getContentAsString(), containsString("\"name\":\"myChannel\",")); @@ -151,16 +161,8 @@ public class IntegrationGraphControllerTests { @EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler", countsEnabled = "!*", defaultLoggingEnabled = "false") - @EnableIntegrationGraphController(path = "/testIntegration") - public static class ContextConfiguration extends WebMvcConfigurerAdapter { - - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/testIntegration/**") - .allowedOrigins("http://foo.bar.com") - .allowedMethods(HttpMethod.GET.name()); - - } + @EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins = "http://foo.bar.com") + public static class ContextConfiguration { } diff --git a/src/reference/asciidoc/graph.adoc b/src/reference/asciidoc/graph.adoc index a2a8067796..fee4cac4c2 100644 --- a/src/reference/asciidoc/graph.adoc +++ b/src/reference/asciidoc/graph.adoc @@ -216,7 +216,7 @@ It is not necessary to refresh the graph for metrics, they are provided in real- Refresh can be called if the application context has been modified since the graph was last retrieved and the graph is completely rebuilt. Any Security and Cross Origin restrictions for the `IntegrationGraphController` can be achieved with the standard configuration options and components provided by Spring Security and Spring MVC projects. -The simple example of that may be: +A simple example of that follows: [source,xml] ---- @@ -236,7 +236,8 @@ The simple example of that may be: ---- -and the Java & Annotation Configuration variant is: +The Java & Annotation Configuration variant follows; note that, for convenience, the annotation provides an `allowedOrigins` attribute; this just provides `GET` access to the `path`. +For more sophistication, you can configure the CORS mappings using standard Spring MVC mechanisms. [source,java] ---- @@ -244,9 +245,8 @@ and the Java & Annotation Configuration variant is: @EnableWebMvc @EnableWebSecurity @EnableIntegration -@EnableIntegrationGraphController(path = "/testIntegration") -public class IntegrationConfiguration extends WebSecurityConfigurerAdapter - implements WebMvcConfigurer { +@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins="http://localhost:9090") +public class IntegrationConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { @@ -257,13 +257,6 @@ public class IntegrationConfiguration extends WebSecurityConfigurerAdapter .formLogin(); } - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/testIntegration/**") - .allowedOrigins("http://localhost:9090") - .allowedMethods(HttpMethod.GET.name()); - } - //... }