CorsFilter implements ContainerRequestFilter, ContainerResponseFilter { @Override public void filter(ContainerRequestContext requestContext) throws IOException { String origin = requestContext.getHeaderString(ORIGIN); if (origin == null) { return; } URI originUri = toUriSafe(origin); if (!isValidOrigin(originUri)) { throw prepareCorsFailureRequest(new ForbiddenException("invalid origin"), requestContext); } if (sameOriginPolicy.isSameOrigin(requestContext, origin)) { return; } String accessControlRequestMethod = requestContext.getHeaderString(ACCESS_CONTROL_REQUEST_METHOD); if (!isValidAccessControlRequestMethod(accessControlRequestMethod)) { throw prepareCorsFailureRequest(new ForbiddenException("accessControlRequestMethod may not be empty"), requestContext); } String requestMethod = requestContext.getMethod(); if (isPreflightRequest(requestMethod, accessControlRequestMethod)) { String accessControlRequestHeaders = requestContext.getHeaderString(ACCESS_CONTROL_REQUEST_HEADERS); WebApplicationException corsPreflightFailure = validateCorsPreflightRequest(origin, accessControlRequestMethod, accessControlRequestHeaders); if (corsPreflightFailure != null) { throw prepareCorsFailureRequest(corsPreflightFailure, requestContext); } else { requestContext.abortWith( buildPreflightResponse(origin, accessControlRequestMethod, accessControlRequestHeaders)); } } else { WebApplicationException corsActualRequestFailure = validateCorsActualRequest(origin, requestMethod); if (corsActualRequestFailure != null) { throw prepareCorsFailureRequest(corsActualRequestFailure, requestContext); } } } private  CorsFilter(Set<String> allowedOrigins, Set<String> allowedMethods,
			boolean allowCredentials, Set<String> exposedHeaders, Set<String> allowedHeaders,
			long maxAge, SameOriginPolicy sameOriginPolicy); @Override void filter(ContainerRequestContext requestContext); @Override void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext);  }
@Test public void requestFilter_NoOriginGiven_SkipsFiltering() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = mock(ContainerRequestContext.class); filter.filter(request); verify(request, never()).abortWith(any()); }
@Test public void requestFilter_SameOriginGiven_SkipsFiltering() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_HOST, HttpMethod.GET); filter.filter(request); verify(request, never()).abortWith(any()); }
@Test public void requestFilter_CustomAlwaysSameOriginPolicyGiven_SkipsFiltering() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .sameOriginPolicy((containerRequestContext, origin) -> true) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); filter.filter(request); verify(request, never()).abortWith(any()); }
@Test public void preflightRequestFilter_AnyOriginAndCredentialsAllowdGiven_ReturnsAnyOrigingWithoutVary() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowAnyOrigin() .disallowCredentials() .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals("*", response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertNull(response.getHeaderString(HttpHeaders.VARY)); }
@Test public void preflightRequestFilter_AnyOriginAndCredentialsDisallowedGiven_ReturnsOriginWithVary() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowAnyOrigin() .allowCredentials() .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals(DEFAULT_ORIGIN, response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, response.getHeaderString(HttpHeaders.VARY)); }
@Test public void preflightRequestFilter_OriginAndCredentialsDisallowedGiven_ReturnsOriginWithVary() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_ORIGIN) .allowCredentials(false) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals(DEFAULT_ORIGIN, response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, response.getHeaderString(HttpHeaders.VARY)); }
@Test public void preflightRequestFilter_OriginAndCredentialsAllowedGiven_ReturnsOriginWithVary() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_ORIGIN) .allowCredentials() .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals(DEFAULT_ORIGIN, response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, response.getHeaderString(HttpHeaders.VARY)); }
@Test public void preflightRequestFilter_MaxAgeGiven_ReturnsMaxAge() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .maxAge(10) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals("10", response.getHeaderString(CorsHeaders.ACCESS_CONTROL_MAX_AGE)); }
@Test public void preflightRequestFilter_NoMaxAgeGiven_ReturnsMaxAge() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .maxAge(0) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertNull(response.getHeaderString(CorsHeaders.ACCESS_CONTROL_MAX_AGE)); }
@Test public void preflightRequestFilter_AccessControlRequestMethodGiven_ReturnsTheRequestMethodOnly() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowMethod(HttpMethod.DELETE) .allowMethod(HttpMethod.GET) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertEquals(HttpMethod.DELETE, response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_METHODS)); }
@Test public void preflightRequestFilter_NoAccessControlRequestHeadersGiven_DoesNotReturnAllowHeader() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowHeader("h1") .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); filter.filter(request); Response response = getAbortResponse(request); assertNull(response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_HEADERS)); }
@Test public void preflightRequestFilter_AccessControlRequestHeadersGiven_ReturnsPassedHeadersOnly() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .allowHeader("h1") .allowHeader("h2") .allowHeader("h3") .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE, " h1, h2 "); filter.filter(request); Response response = getAbortResponse(request); assertEquals(" h1, h2 ", response.getHeaderString(CorsHeaders.ACCESS_CONTROL_ALLOW_HEADERS)); }
@Test public void preflightRequestFilter_InvalidMethodGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowMethod(HttpMethod.GET) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.DELETE); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void preflightRequestFilter_BlankMethodGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowMethod(HttpMethod.GET) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, " "); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void preflightRequestFilter_InvalidOriginGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_HOST) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void preflightRequestFilter_InvalidHeaderGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowHeaders(Collections.singleton("h1")) .build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET, "h2"); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void actualRequestFilter_InvalidOriginGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_HOST) .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void actualRequestFilter_InvalidMethodGiven_CorsFails() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowMethod(HttpMethod.DELETE) .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); assertThrows(ForbiddenException.class, () -> filter.filter(request)); }
@Test public void actualRequestFilter_ValidGiven_PassesWithoutCorsHeadersRequestHeaders() throws IOException { CorsFilter filter = new CorsFilter.Builder() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); filter.filter(request); verify(request, never()).abortWith(any()); }
@Test public void actualRequestFilter_OptionsWithNoAccessControlRequestMethodGiven_PassesRequestWithoutCorsHeaders() throws IOException { CorsFilter filter = new CorsFilter.Builder() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.OPTIONS); filter.filter(request); verify(request, never()).abortWith(any()); }
@Test public void responseFilter_NoOriginGiven_NoCorsHeadersAdded() throws IOException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = mock(ContainerRequestContext.class); ContainerResponseContext response = mock(ContainerResponseContext.class); filter.filter(request, response); verifyZeroInteractions(response); }
@Test public void requestFilter_PreflightRequestGiven_NoCorsHeadersAdded() throws IOException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = createPreflightRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, "..."); ContainerResponseContext response = mock(ContainerResponseContext.class); filter.filter(request, response); verifyZeroInteractions(response); }
@Test public void responseFilter_RequestFilterFailureGiven_NoCorsHeadersAdded() throws IOException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = mock(ContainerRequestContext.class); when(request.getHeaderString(CorsHeaders.ORIGIN)).thenReturn(DEFAULT_ORIGIN); when(request.getProperty("jrestless.cors.filter.failure")).thenReturn(true); ContainerResponseContext response = mock(ContainerResponseContext.class); filter.filter(request, response); verifyZeroInteractions(response); }
@Test public void responseFilter_SameOriginGiven_NoCorsHeadersAdded() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder().build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_HOST, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); filter.filter(request, response); verifyZeroInteractions(response); }
@Test public void responseFilter_CustomAlwaysSameOriginPolicyGiven_NoCorsHeadersAdded() throws IOException, URISyntaxException { CorsFilter filter = new CorsFilter.Builder() .sameOriginPolicy((requestContext, origin) -> true) .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); filter.filter(request, response); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_AnyOriginAndDisallowCredentialsGiven_AddsAnyOriginAndNoVaryHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .disallowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals("*", headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertNull(headers.getFirst(HttpHeaders.VARY)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_AnyOriginAndAllowCredentialsGiven_AddsPassedOriginAndVaryHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals(DEFAULT_ORIGIN, headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, headers.getFirst(HttpHeaders.VARY)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_OriginAndAllowCredentialsGiven_AddsPassedOriginAndVaryHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_ORIGIN) .allowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals(DEFAULT_ORIGIN, headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, headers.getFirst(HttpHeaders.VARY)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_OriginAndDisallowCredentialsGiven_AddsPassedOriginAndVaryHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowOrigin(DEFAULT_ORIGIN) .disallowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals(DEFAULT_ORIGIN, headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)); assertEquals(CorsHeaders.ORIGIN, headers.getFirst(HttpHeaders.VARY)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_AllowCredentialsGiven_AddsAllowCredentialHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .allowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals("true", headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); assertEquals(CorsHeaders.ORIGIN, headers.getFirst(HttpHeaders.VARY)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_DisallowCredentialsGiven_DoesNotAddAllowCredentialHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .disallowCredentials() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertNull(headers.getFirst(CorsHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_NoExposedHeadersGiven_DoesNotAddExposeHeadersHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertNull(headers.getFirst(CorsHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_EmptyExposedHeadersGiven_DoesNotAddExposeHeadersHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .exposeHeaders(Collections.emptySet()) .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertNull(headers.getFirst(CorsHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)); verify(response).getHeaders(); verifyZeroInteractions(response); }
@Test public void corsResponseFilter_ExposedHeadersGiven_AddsExposeHeadersHeader() throws IOException { CorsFilter filter = new CorsFilter.Builder() .exposeHeader("h1") .exposeHeader("h2") .build(); ContainerRequestContext request = createActualRequestMock(DEFAULT_HOST, DEFAULT_ORIGIN, HttpMethod.GET); ContainerResponseContext response = mock(ContainerResponseContext.class); MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>(); when(response.getHeaders()).thenReturn(headers); filter.filter(request, response); assertEquals("h1,h2", headers.getFirst(CorsHeaders.ACCESS_CONTROL_EXPOSE_HEADERS)); verify(response).getHeaders(); verifyZeroInteractions(response); }