Skip to content

Commit

Permalink
Fix cors config (#777)
Browse files Browse the repository at this point in the history
* fix(bauhaus cors config)

* test (cors : tests skeletons)

* test (cors : tests ok)

---------

Co-authored-by: Bibonne Fabrice <[email protected]>
  • Loading branch information
FBibonne and Bibonne Fabrice authored Oct 8, 2024
1 parent 01c5a1a commit 1ac5d7c
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;
import java.util.Optional;

import static fr.insee.rmes.config.PropertiesKeys.CORS_ALLOWED_ORIGIN;

@Configuration
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class CommonSecurityConfiguration {
Expand All @@ -27,25 +25,32 @@ public class CommonSecurityConfiguration {

public static final String DEFAULT_ROLE_PREFIX = "" ;
private final Optional<String> allowedOrigin ;
private final String appHost;

public CommonSecurityConfiguration(@Value("${"+CORS_ALLOWED_ORIGIN+"}") Optional<String> allowedOrigin){
public CommonSecurityConfiguration(@Value("${"+CORS_ALLOWED_ORIGIN+"}") Optional<String> allowedOrigin, @Value("${fr.insee.rmes.bauhaus.appHost}") String appHost) {
this.allowedOrigin=allowedOrigin;
this.appHost = appHost;
}


@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
logger.info("Allowed origins : {}", allowedOrigin);
configuration.setAllowedOrigins(List.of(allowedOrigin.orElse("*")));
configuration.setAllowedMethods(List.of("*"));
configuration.setAllowedHeaders(List.of("*"));
UrlBasedCorsConfigurationSource source = new
UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {

@Override
public void addCorsMappings(CorsRegistry registry) {
logger.info("Allowed origins : {}", allowedOrigin);
registry.addMapping("/**")
.allowedOrigins(allowedOrigin.orElse(appHost))
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600);
}

};
}


@Bean
public StampFromPrincipal stampFromPrincipal(UserDecoder userDecoder){
return principal -> {
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/bauhaus-local-dev.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Default value for cors filter : empty means no CORS allowed :
fr.insee.rmes.bauhaus.cors.allowedOrigin=*
fr.insee.rmes.bauhaus.cors.allowedOrigin=http://localhost:3000/,http://localhost:8080/

# Properties Front
fr.insee.rmes.bauhaus.appHost = https://localhost:3000/#/
fr.insee.rmes.bauhaus.appHost = http://localhost:3000/#/

# Env (local --> NoAuth | qf, pre-prod, prod --> PROD)
fr.insee.rmes.bauhaus.env = NoAuth
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package fr.insee.rmes.integration;

import fr.insee.rmes.config.BaseConfigForMvcTests;
import fr.insee.rmes.config.auth.security.CommonSecurityConfiguration;
import fr.insee.rmes.external.services.authentication.stamps.StampsService;
import fr.insee.rmes.webservice.PublicResources;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;

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.status;

@WebMvcTest(controllers = PublicResources.class, properties = {
"fr.insee.rmes.bauhaus.cors.allowedOrigin=",
"fr.insee.rmes.bauhaus.appHost=http://localhost:80",
"logging.level.org.springframework.web=debug"})
@Import({BaseConfigForMvcTests.class, CommonSecurityConfiguration.class})
class CorsConfigDefaultToAppHostPropertyForOriginTest {

@Autowired
// Perform mock request on http://localhost:80
private MockMvc mockMvc;

@MockBean
private StampsService stampsService;

@ValueSource(strings = {
"http://bauhaus",
"https://localhost:80",
"http://localhost:8080"
})
@ParameterizedTest
void whenPerformCorsRequest_shouldBeDenied(String origin) throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
.header("Origin", origin)
).andExpect(status().isForbidden())
.andExpect(content().string("Invalid CORS request"));

}

@Test
void whenPerformNoCorsRequest_shouldBeOK() throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
).andExpect(status().isOk());
}

@Test
void whenHeaderOriginIsOK_shouldBeOK() throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
.header("Origin", "http://localhost:80")
).andExpect(status().isOk());
}

}
63 changes: 63 additions & 0 deletions src/test/java/fr/insee/rmes/integration/CorsConfigTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package fr.insee.rmes.integration;

import fr.insee.rmes.config.BaseConfigForMvcTests;
import fr.insee.rmes.config.auth.security.CommonSecurityConfiguration;
import fr.insee.rmes.external.services.authentication.stamps.StampsService;
import fr.insee.rmes.webservice.PublicResources;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;

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.status;

@WebMvcTest(controllers = PublicResources.class, properties = {
"fr.insee.rmes.bauhaus.cors.allowedOrigin=http://localhost:80",
"fr.insee.rmes.bauhaus.appHost=http://myfront:80",
"logging.level.org.springframework.web=debug"})
@Import({BaseConfigForMvcTests.class, CommonSecurityConfiguration.class})
class CorsConfigTest {

@Autowired
// Perform mock request on http://localhost:80
private MockMvc mockMvc;

@MockBean
private StampsService stampsService;

@ValueSource(strings = {
"http://bauhaus",
"https://localhost:80",
"http://localhost:8080"
})
@ParameterizedTest
void whenPerformCorsRequest_shouldBeDenied(String origin) throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
.header("Origin", origin)
).andExpect(status().isForbidden())
.andExpect(content().string("Invalid CORS request"));
}

@Test
void whenPerformNoCorsRequest_shouldBeOK() throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
).andExpect(status().isOk());
}

@Test
void whenHeaderOriginIsOK_shouldBeOK() throws Exception {
mockMvc.perform(get("/stamps")
.header("Accept", "application/json")
.header("Origin", "http://localhost:80")
).andExpect(status().isOk());
}

}

0 comments on commit 1ac5d7c

Please sign in to comment.