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.
This commit is contained in:
Gary Russell
2016-10-14 16:12:47 -04:00
committed by Artem Bilan
parent 8d70463c7a
commit 3c284871c3
4 changed files with 61 additions and 25 deletions

View File

@@ -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 {};
}

View File

@@ -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");
}
}
}

View File

@@ -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 {
}

View File

@@ -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:
<int-http:graph-controller path="/myIntegration" />
----
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());
}
//...
}