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:
committed by
Artem Bilan
parent
8d70463c7a
commit
3c284871c3
@@ -58,4 +58,12 @@ public @interface EnableIntegrationGraphController {
|
|||||||
@AliasFor("value")
|
@AliasFor("value")
|
||||||
String path() default HttpContextUtils.GRAPH_CONTROLLER_DEFAULT_PATH;
|
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 {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,14 @@ import org.springframework.integration.context.IntegrationContextUtils;
|
|||||||
import org.springframework.integration.http.management.IntegrationGraphController;
|
import org.springframework.integration.http.management.IntegrationGraphController;
|
||||||
import org.springframework.integration.http.support.HttpContextUtils;
|
import org.springframework.integration.http.support.HttpContextUtils;
|
||||||
import org.springframework.integration.support.management.graph.IntegrationGraphServer;
|
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 Artem Bilan
|
||||||
|
* @author Gary Russell
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistrar {
|
class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistrar {
|
||||||
@@ -56,6 +61,16 @@ class IntegrationGraphControllerRegistrar implements ImportBeanDefinitionRegistr
|
|||||||
new RootBeanDefinition(IntegrationGraphServer.class));
|
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)) {
|
if (!registry.containsBeanDefinition(HttpContextUtils.GRAPH_CONTROLLER_BEAN_NAME)) {
|
||||||
AbstractBeanDefinition controllerPropertiesPopulator =
|
AbstractBeanDefinition controllerPropertiesPopulator =
|
||||||
BeanDefinitionBuilder.genericBeanDefinition(GraphControllerPropertiesPopulator.class)
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.hamcrest.Matchers.not;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertThat;
|
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.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
|
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.annotation.Configuration;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.integration.channel.DirectChannel;
|
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.context.WebApplicationContext;
|
||||||
import org.springframework.web.servlet.HandlerAdapter;
|
import org.springframework.web.servlet.HandlerAdapter;
|
||||||
import org.springframework.web.servlet.HandlerExecutionChain;
|
import org.springframework.web.servlet.HandlerExecutionChain;
|
||||||
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
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.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.RequestMappingHandlerAdapter;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Artem Bilan
|
* @author Artem Bilan
|
||||||
|
* @author Gary Russell
|
||||||
* @since 4.3
|
* @since 4.3
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@@ -121,6 +121,11 @@ public class IntegrationGraphControllerTests {
|
|||||||
|
|
||||||
Object handler = executionChain.getHandler();
|
Object handler = executionChain.getHandler();
|
||||||
|
|
||||||
|
for (HandlerInterceptor handlerInterceptor : executionChain.getInterceptors()) {
|
||||||
|
// Assert the CORS config
|
||||||
|
assertTrue(handlerInterceptor.preHandle(request, response, handler));
|
||||||
|
}
|
||||||
|
|
||||||
handlerAdapter.handle(request, response, handler);
|
handlerAdapter.handle(request, response, handler);
|
||||||
assertEquals(HttpStatus.OK.value(), response.getStatus());
|
assertEquals(HttpStatus.OK.value(), response.getStatus());
|
||||||
assertThat(response.getContentAsString(), containsString("\"name\":\"nullChannel\","));
|
assertThat(response.getContentAsString(), containsString("\"name\":\"nullChannel\","));
|
||||||
@@ -138,6 +143,11 @@ public class IntegrationGraphControllerTests {
|
|||||||
|
|
||||||
handler = executionChain.getHandler();
|
handler = executionChain.getHandler();
|
||||||
|
|
||||||
|
for (HandlerInterceptor handlerInterceptor : executionChain.getInterceptors()) {
|
||||||
|
// Assert the CORS config
|
||||||
|
assertTrue(handlerInterceptor.preHandle(request, response, handler));
|
||||||
|
}
|
||||||
|
|
||||||
handlerAdapter.handle(request, response, handler);
|
handlerAdapter.handle(request, response, handler);
|
||||||
assertEquals(HttpStatus.OK.value(), response.getStatus());
|
assertEquals(HttpStatus.OK.value(), response.getStatus());
|
||||||
assertThat(response.getContentAsString(), containsString("\"name\":\"myChannel\","));
|
assertThat(response.getContentAsString(), containsString("\"name\":\"myChannel\","));
|
||||||
@@ -151,16 +161,8 @@ public class IntegrationGraphControllerTests {
|
|||||||
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
|
@EnableIntegrationManagement(statsEnabled = "_org.springframework.integration.errorLogger.handler",
|
||||||
countsEnabled = "!*",
|
countsEnabled = "!*",
|
||||||
defaultLoggingEnabled = "false")
|
defaultLoggingEnabled = "false")
|
||||||
@EnableIntegrationGraphController(path = "/testIntegration")
|
@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins = "http://foo.bar.com")
|
||||||
public static class ContextConfiguration extends WebMvcConfigurerAdapter {
|
public static class ContextConfiguration {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/testIntegration/**")
|
|
||||||
.allowedOrigins("http://foo.bar.com")
|
|
||||||
.allowedMethods(HttpMethod.GET.name());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
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.
|
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]
|
[source,xml]
|
||||||
----
|
----
|
||||||
@@ -236,7 +236,8 @@ The simple example of that may be:
|
|||||||
<int-http:graph-controller path="/myIntegration" />
|
<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]
|
[source,java]
|
||||||
----
|
----
|
||||||
@@ -244,9 +245,8 @@ and the Java & Annotation Configuration variant is:
|
|||||||
@EnableWebMvc
|
@EnableWebMvc
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@EnableIntegration
|
@EnableIntegration
|
||||||
@EnableIntegrationGraphController(path = "/testIntegration")
|
@EnableIntegrationGraphController(path = "/testIntegration", allowedOrigins="http://localhost:9090")
|
||||||
public class IntegrationConfiguration extends WebSecurityConfigurerAdapter
|
public class IntegrationConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
@@ -257,13 +257,6 @@ public class IntegrationConfiguration extends WebSecurityConfigurerAdapter
|
|||||||
.formLogin();
|
.formLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/testIntegration/**")
|
|
||||||
.allowedOrigins("http://localhost:9090")
|
|
||||||
.allowedMethods(HttpMethod.GET.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
//...
|
//...
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user