diff --git a/engine/src/main/java/org/entando/entando/aps/servlet/security/CORSFilter.java b/engine/src/main/java/org/entando/entando/aps/servlet/security/CORSFilter.java index 1d3e545d5..524658543 100644 --- a/engine/src/main/java/org/entando/entando/aps/servlet/security/CORSFilter.java +++ b/engine/src/main/java/org/entando/entando/aps/servlet/security/CORSFilter.java @@ -14,38 +14,83 @@ package org.entando.entando.aps.servlet.security; import java.io.IOException; +import javax.servlet.Filter; import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.web.filter.OncePerRequestFilter; /** * - * @author paddeo + * @author paddeo, f.leandro */ -public class CORSFilter extends OncePerRequestFilter { +public class CORSFilter implements Filter { private final Logger logger = LoggerFactory.getLogger(getClass()); - - public static final String ALLOWED_METHODS = "GET, POST, PUT, DELETE, OPTIONS, PATCH"; + + private boolean enabled; + private String allowedOrigins; + private String allowedMethods; + private String allowedHeaders; + private String allowedCredentials; + private String maxAge; @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - logger.trace("Sending Header...."); + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + final HttpServletRequest httpRequest = (HttpServletRequest) request; + final HttpServletResponse httpResponse = (HttpServletResponse) response; + + if (!enabled) { + filterChain.doFilter(httpRequest, httpResponse); + return; + } + + logger.trace("Configuring CORS Headers...."); // CORS "pre-flight" request - response.addHeader("Access-Control-Allow-Origin", "*"); - response.addHeader("Access-Control-Allow-Methods", ALLOWED_METHODS); - response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); - response.addHeader("Access-Control-Max-Age", "3600"); - if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { - response.setStatus(HttpServletResponse.SC_OK); + httpResponse.addHeader("Access-Control-Allow-Origin", allowedOrigins); + httpResponse.addHeader("Access-Control-Allow-Methods", allowedMethods); + httpResponse.addHeader("Access-Control-Allow-Headers", allowedHeaders); + httpResponse.addHeader("Access-Control-Allow-Credentials", allowedCredentials); + httpResponse.addHeader("Access-Control-Max-Age", maxAge); + + if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) { + httpResponse.setStatus(HttpServletResponse.SC_OK); } else { - filterChain.doFilter(request, response); + filterChain.doFilter(httpRequest, httpResponse); } } + @Override public void init(final FilterConfig filterConfig) {} + @Override public void destroy() {} + + public void setAllowedOrigins(String allowedOrigins) { + this.allowedOrigins = allowedOrigins; + } + + public void setAllowedMethods(String allowedMethods) { + this.allowedMethods = allowedMethods; + } + + public void setAllowedHeaders(String allowedHeaders) { + this.allowedHeaders = allowedHeaders; + } + + public void setAllowedCredentials(String allowedCredentials) { + this.allowedCredentials = allowedCredentials; + } + + public void setMaxAge(String maxAge) { + this.maxAge = maxAge; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } } diff --git a/engine/src/main/java/org/entando/entando/aps/servlet/security/SecurityWebApplicationInitializer.java b/engine/src/main/java/org/entando/entando/aps/servlet/security/SecurityWebApplicationInitializer.java index e0f754ee2..082e8d92a 100644 --- a/engine/src/main/java/org/entando/entando/aps/servlet/security/SecurityWebApplicationInitializer.java +++ b/engine/src/main/java/org/entando/entando/aps/servlet/security/SecurityWebApplicationInitializer.java @@ -13,7 +13,6 @@ */ package org.entando.entando.aps.servlet.security; -import javax.servlet.ServletContext; import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; /** @@ -23,10 +22,4 @@ */ public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer { - @Override - protected void beforeSpringSecurityFilterChain(ServletContext servletContext) { - super.beforeSpringSecurityFilterChain(servletContext); - super.insertFilters(servletContext, new CORSFilter()); - } - } diff --git a/engine/src/main/resources/spring/aps/cors.xml b/engine/src/main/resources/spring/aps/cors.xml new file mode 100644 index 000000000..f9b329575 --- /dev/null +++ b/engine/src/main/resources/spring/aps/cors.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/engine/src/test/java/org/entando/entando/web/AbstractControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/AbstractControllerIntegrationTest.java index 3711a2992..b1ad0b99a 100644 --- a/engine/src/test/java/org/entando/entando/web/AbstractControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/AbstractControllerIntegrationTest.java @@ -13,11 +13,12 @@ */ package org.entando.entando.web; -import javax.annotation.Resource; - +import com.agiletec.aps.system.SystemConstants; import com.agiletec.aps.system.services.authorization.IAuthorizationManager; +import com.agiletec.aps.system.services.baseconfig.ConfigInterface; import com.agiletec.aps.system.services.user.IAuthenticationProviderManager; import com.agiletec.aps.system.services.user.UserDetails; +import javax.annotation.Resource; import javax.servlet.Filter; import org.entando.entando.TestEntandoJndiUtils; import org.entando.entando.aps.servlet.security.CORSFilter; @@ -31,6 +32,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; @@ -80,8 +82,17 @@ public static void setup() throws Exception { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + + CORSFilter filter = new CORSFilter(); + filter.setEnabled(true); + filter.setAllowedOrigins("*"); + filter.setAllowedMethods("GET, POST, PUT, DELETE, OPTIONS, PATCH"); + filter.setAllowedHeaders("Content-Type, Authorization"); + filter.setAllowedCredentials("false"); + filter.setMaxAge("3600"); + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) - .addFilters(new CORSFilter(), springSecurityFilterChain) + .addFilters(filter, springSecurityFilterChain) .build(); accessToken = null; } diff --git a/engine/src/test/java/org/entando/entando/web/category/CategoryControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/category/CategoryControllerIntegrationTest.java index e603a3d9e..d42563d2a 100644 --- a/engine/src/test/java/org/entando/entando/web/category/CategoryControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/category/CategoryControllerIntegrationTest.java @@ -70,8 +70,9 @@ public void testGetCategories() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/dataobject/DataTypeControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/dataobject/DataTypeControllerIntegrationTest.java index 8ccbed4c6..20eeae3f5 100644 --- a/engine/src/test/java/org/entando/entando/web/dataobject/DataTypeControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/dataobject/DataTypeControllerIntegrationTest.java @@ -30,6 +30,7 @@ import org.junit.Test; import org.mockito.InjectMocks; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultMatcher; @@ -64,8 +65,9 @@ public void testGetDataTypes() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } @@ -250,8 +252,9 @@ public void testGetDataTypeAttributeTypes_1() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/filebrowser/FileBrowserControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/filebrowser/FileBrowserControllerIntegrationTest.java index 8c80b5d55..5c710bcbc 100644 --- a/engine/src/test/java/org/entando/entando/web/filebrowser/FileBrowserControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/filebrowser/FileBrowserControllerIntegrationTest.java @@ -52,8 +52,9 @@ public void testCheckRequest() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/guifragment/GuiFragmentControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/guifragment/GuiFragmentControllerIntegrationTest.java index 14ce5cbfe..d4f1b929e 100644 --- a/engine/src/test/java/org/entando/entando/web/guifragment/GuiFragmentControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/guifragment/GuiFragmentControllerIntegrationTest.java @@ -41,8 +41,9 @@ public void testGetFragments_1() throws Exception { result.andDo(print()); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); result.andExpect(jsonPath("$.payload", Matchers.hasSize(1))); result.andExpect(jsonPath("$.errors", Matchers.hasSize(0))); diff --git a/engine/src/test/java/org/entando/entando/web/language/LanguageControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/language/LanguageControllerIntegrationTest.java index 62ddc5378..3fa8869f5 100644 --- a/engine/src/test/java/org/entando/entando/web/language/LanguageControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/language/LanguageControllerIntegrationTest.java @@ -65,8 +65,9 @@ public void testGetLangs() throws Exception { * org.entando.entando.aps.servlet.CORSFilter class */ result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/system/ReloadConfigurationControllerTest.java b/engine/src/test/java/org/entando/entando/web/system/ReloadConfigurationControllerTest.java index 7a66e21f9..37ac1971b 100644 --- a/engine/src/test/java/org/entando/entando/web/system/ReloadConfigurationControllerTest.java +++ b/engine/src/test/java/org/entando/entando/web/system/ReloadConfigurationControllerTest.java @@ -46,8 +46,9 @@ public void should_execute_reload_and_have_headers() throws Exception { * org.entando.entando.aps.servlet.CORSFilter class */ result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/user/UserControllerDeleteAuthoritiesIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/user/UserControllerDeleteAuthoritiesIntegrationTest.java index 92bc1cf91..edb19000c 100644 --- a/engine/src/test/java/org/entando/entando/web/user/UserControllerDeleteAuthoritiesIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/user/UserControllerDeleteAuthoritiesIntegrationTest.java @@ -13,6 +13,13 @@ */ package org.entando.entando.web.user; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.authorization.IAuthorizationManager; import com.agiletec.aps.system.services.user.IAuthenticationProviderManager; @@ -43,13 +50,6 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.context.WebApplicationContext; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath*:spring/testpropertyPlaceholder.xml", @@ -90,8 +90,17 @@ public static void setup() throws Exception { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + + CORSFilter filter = new CORSFilter(); + filter.setEnabled(true); + filter.setAllowedOrigins("*"); + filter.setAllowedMethods("GET, POST, PUT, DELETE, OPTIONS, PATCH"); + filter.setAllowedHeaders("Content-Type, Authorization"); + filter.setAllowedCredentials("false"); + filter.setMaxAge("3600"); + mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext) - .addFilters(new CORSFilter()) + .addFilters(filter) .build(); //workaround for dirty context diff --git a/engine/src/test/java/org/entando/entando/web/userprofile/ProfileTypeControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/userprofile/ProfileTypeControllerIntegrationTest.java index 6a98522c0..4e167badf 100644 --- a/engine/src/test/java/org/entando/entando/web/userprofile/ProfileTypeControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/userprofile/ProfileTypeControllerIntegrationTest.java @@ -64,8 +64,9 @@ public void testGetUserProfileTypes() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } @@ -253,8 +254,9 @@ public void testGetUserProfileAttributeTypes_1() throws Exception { .header("Authorization", "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/userprofile/UserProfileControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/userprofile/UserProfileControllerIntegrationTest.java index 6f34cc433..c942f6eaf 100644 --- a/engine/src/test/java/org/entando/entando/web/userprofile/UserProfileControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/userprofile/UserProfileControllerIntegrationTest.java @@ -69,8 +69,9 @@ public void testGetUserProfileType() throws Exception { System.out.println(result.andReturn().getResponse().getContentAsString()); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); } diff --git a/engine/src/test/java/org/entando/entando/web/widget/WidgetControllerIntegrationTest.java b/engine/src/test/java/org/entando/entando/web/widget/WidgetControllerIntegrationTest.java index b0d4df66b..e27ef0fb0 100644 --- a/engine/src/test/java/org/entando/entando/web/widget/WidgetControllerIntegrationTest.java +++ b/engine/src/test/java/org/entando/entando/web/widget/WidgetControllerIntegrationTest.java @@ -67,8 +67,9 @@ public void testGetCategories() throws Exception { .header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)); result.andExpect(status().isOk()); result.andExpect(header().string("Access-Control-Allow-Origin", "*")); - result.andExpect(header().string("Access-Control-Allow-Methods", CORSFilter.ALLOWED_METHODS)); + result.andExpect(header().string("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")); result.andExpect(header().string("Access-Control-Allow-Headers", "Content-Type, Authorization")); + result.andExpect(header().string("Access-Control-Allow-Credentials", "false")); result.andExpect(header().string("Access-Control-Max-Age", "3600")); }