Add CORS interceptor for Cloud Foundry actuators

This interceptor processes the response with CORS headers
and apepars before the Cloud Foundry security interceptor.

See gh-7108
This commit is contained in:
Madhura Bhave 2016-11-17 16:55:16 -08:00
parent f35fa87366
commit 3a3228fc70
2 changed files with 48 additions and 1 deletions

View File

@ -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<? extends NamedMvcEndpoint> 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<HandlerInterceptor> interceptors = new ArrayList<HandlerInterceptor>();
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);
}
}
}

View File

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