diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java index 6a9555f53da..ebee4c2a81a 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMapping.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.mvc.AbstractEndpointHandlerMapping; @@ -34,6 +35,7 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; /** * {@link HandlerMapping} to map {@link Endpoint}s to Cloud Foundry specific URLs. @@ -45,10 +47,13 @@ class CloudFoundryEndpointHandlerMapping private final HandlerInterceptor securityInterceptor; + private final CorsConfiguration corsConfiguration; + CloudFoundryEndpointHandlerMapping(Set endpoints, CorsConfiguration corsConfiguration, HandlerInterceptor securityInterceptor) { super(endpoints, corsConfiguration); this.securityInterceptor = securityInterceptor; + this.corsConfiguration = corsConfiguration; } @Override @@ -97,6 +102,7 @@ class CloudFoundryEndpointHandlerMapping private HandlerInterceptor[] addSecurityInterceptor(HandlerInterceptor[] existing) { List interceptors = new ArrayList(); + interceptors.add(new CorsInterceptor(this.corsConfiguration)); interceptors.add(this.securityInterceptor); if (existing != null) { interceptors.addAll(Arrays.asList(existing)); @@ -104,4 +110,23 @@ class CloudFoundryEndpointHandlerMapping return interceptors.toArray(new HandlerInterceptor[interceptors.size()]); } + /** + * {@link HandlerInterceptor} that processes the response for CORS. + * + */ + class CorsInterceptor extends HandlerInterceptorAdapter { + private final CorsConfiguration config; + + CorsInterceptor(CorsConfiguration config) { + this.config = config; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, + Object handler) throws Exception { + return getCorsProcessor().processRequest(this.config, request, response); + } + + } + } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMappingTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMappingTests.java index a83559390ef..08e029686da 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMappingTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/cloudfoundry/CloudFoundryEndpointHandlerMappingTests.java @@ -33,6 +33,9 @@ import org.springframework.boot.actuate.health.HealthIndicator; import org.springframework.boot.actuate.health.OrderedHealthAggregator; import org.springframework.context.support.StaticApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsProcessor; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerInterceptor; @@ -47,6 +50,25 @@ import static org.assertj.core.api.Assertions.assertThat; public class CloudFoundryEndpointHandlerMappingTests extends AbstractEndpointHandlerMappingTests { + @Test + public void corsInterceptorShouldBeFirstAndCallCorsProcessor() throws Exception { + TestMvcEndpoint endpoint = new TestMvcEndpoint(new TestEndpoint("a")); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + CloudFoundryEndpointHandlerMapping handlerMapping = new CloudFoundryEndpointHandlerMapping( + Collections.singleton(endpoint), corsConfiguration, null); + CorsProcessor corsProcessor = Mockito.mock(CorsProcessor.class); + handlerMapping.setCorsProcessor(corsProcessor); + MockHttpServletRequest request = new MockHttpServletRequest(); + HandlerExecutionChain handlerExecutionChain = handlerMapping + .getHandlerExecutionChain(endpoint, request); + HandlerInterceptor[] interceptors = handlerExecutionChain.getInterceptors(); + CloudFoundryEndpointHandlerMapping.CorsInterceptor corsInterceptor = (CloudFoundryEndpointHandlerMapping.CorsInterceptor) interceptors[0]; + MockHttpServletResponse response = new MockHttpServletResponse(); + corsInterceptor.preHandle(request, response, new Object()); + Mockito.verify(corsProcessor).processRequest(corsConfiguration, request, + response); + } + @Test public void getHandlerExecutionChainShouldHaveSecurityInterceptor() throws Exception { CloudFoundrySecurityInterceptor securityInterceptor = Mockito @@ -57,7 +79,7 @@ public class CloudFoundryEndpointHandlerMappingTests HandlerExecutionChain handlerExecutionChain = handlerMapping .getHandlerExecutionChain(endpoint, new MockHttpServletRequest()); HandlerInterceptor[] interceptors = handlerExecutionChain.getInterceptors(); - assertThat(interceptors).contains(securityInterceptor); + assertThat(interceptors[1]).isEqualTo(securityInterceptor); } @Test