I have the following config, based on the example here https://docs.spring.io/spring-security/site/docs/current/reference/html/cors.html
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.csrf().disable()
.cors();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
But when I test this out I am still able to access it from my localhost no problem. It's like the cors isn't being activated at all.
edit: I should add that I am using Spring OAuth2 and this config is located in my ResourceServerConfigurerAdapter
Have you annotated your class with #component? That is the class where you are initializing the CORS filter?
Related
Situation
This is my Spring security config and it works when I create request from localhost and application runs at localhost too.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/client/**")
.hasRole(HttpClientType.CLIENT.name())
.antMatchers("/**")
.hasRole(HttpClientType.USER.name())
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.accessDeniedHandler(restAuthorizationEntryPoint)
.and()
.addFilterBefore(jwtTokenFilter, BasicAuthenticationFilter.class)
.csrf().disable().cors().disable();
}
Problem
When I deploy my application to production server, and create request from remote host, every time I get HTTP 403.
P.S. I thought the problem will be in CORS and CSRF but it doesn't work even I disable it.
The cors().disable() does not disable cors security filter at all, but only applies the default cors configurations.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.cors().configurationSource(corsConfigurationSource())
...
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of(CorsConfiguration.ALL));
configuration.setAllowedMethods(List.of(CorsConfiguration.ALL));
configuration.setAllowedHeaders(List.of(CorsConfiguration.ALL));
configuration.setAllowCredentials(true);
// ideally CorsConfiguration.ALL should not be used in production
configuration.addExposedHeader(HttpHeaders.AUTHORIZATION); // The headers you expose in response
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
Are you using #EnableWebSecurity in the class to enable mvc security settings?. Test with .sessionRegistry(sessionRegistry())
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
I am working in a Spring Boot 2.2.5 application with an Angular 9 frontend.
I have been trying to configure a CORS filter on the Spring Boot backend to allow any origin with any headers for any request.
Based on my research, what I currently have implemented in my main Application.java file should work:
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("GET");
config.addAllowedMethod("POST");
config.addAllowedMethod("PUT");
config.addAllowedMethod("DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
However, what I am experiencing is that this is only allowing me to execute GET call from the frontend to my controller on the backend. Any other call to POST or PUT fails with the following error:
Access to XMLHttpRequest at 'http://localhost:8080/spring-boot-starter-seed/default-theme/save/cyan' from origin 'http://localhost:8083' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I know im somewhat on the right track because if I remove the #Bean I implemented, then all calls from frontend to backend fail due to that error. But when implementing that Bean, for some reason its only working for GET requests.
Is there something I have missed?
***** Update *****
I dont know if this will be helpful, but, I am using Azure AD for authentication with this application. I have a WebSecurityConfig that looks like this:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/actuator/**", "/heartbeat/**", "/register", "/unregister").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(this.jwtAuthenticationConverter());
}
}
Earlier in my post I said that GET requests are working, but that seems to be somewhat false.
GET /heartbeat works. However...
GET /default-theme does not work and fails with the same No Access-Control-Allow-Origin error.
The only difference between these two Controller paths is that the /default-theme is not included in the excluded antMatchers, and it is protected by #PreAuthorize(value = "hasRole('ROLE_access')")
I think the problem here is due to the filter of the dispatcher servlet :
try this class to implement a filter as well :
public class CORSFilter extends GenericFilterBean implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chaine)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods", "*");
httpResponse.setHeader("Access-Control-Allow-Headers", "*");
httpResponse.setHeader("Access-Control-Allow-Credentials", "false");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
System.out.println("****************** CORS Configuration Completed *******************");
chaine.doFilter(request, response);
}
}
Then inject the bean in your main application class or every where :
#Bean
public FilterRegistrationBean crosFilterRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new CORSFilter());
registrationBean.setName("CORS Filter");
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
Hope this would be helpfull
Inside your WebSecurityConfig class you need to configure cors as given below
#Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.and()
.cors().configurationSource(corsConfigurationSource())
.and()
...
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList(
"list of domains here"
)
);
configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT", "OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(
Arrays.asList(
"Access-Control-Allow-Headers",
"Access-Control-Allow-Origin",
"Access-Control-Request-Method",
"Access-Control-Request-Headers",
"Origin", "Cache-Control",
"Content-Type",
"Authorization"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
So, as it turns out, my update on my original post was on the right track to assume that Spring Security and my WebSecurityConfig was part of the cause.
I found the real solution on an answer here.
I needed to update my HttpSecurity config to include the .cors() first:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.authorizeRequests()
.antMatchers("/actuator/**", "/heartbeat", "/register", "/unregister").permitAll()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(this.jwtAuthenticationConverter());
}
After doing this, all other CORS configurations were unnecessary and could be removed from my app. Just add the #CrossOrigin annotation to any relevant controllers.
With this in place, calling my GET /default-theme controller, protected by the #PreAuthorize(value = "hasRole('ROLE_access')"), got rid of the No Access-Control-Allow-Origin error, and resulted in the error I expected which was a 401 response.
The underlying reason for all of this was because I was tasked with migrating this application from LDAP auth to Azure AD auth.
Hopefully this will help someone in the future.
I'm trying to make my frontend only place from request to backend can be made. Problem is that it doesn't work and every request is being invoked. Below is code which configures Spring Security and cors.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, SIGN_UP_URL).permitAll()
.antMatchers(HttpMethod.GET, "/groups").permitAll()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://192.168.0.16:8080"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
You might want to add OPTIONS http method to the CORS allowed methods. Most of the front end languages sent an OPTIONS request before sending the real one. Something like
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS"));
I'm trying to configure Spring for CORS in order to use Angular web UI:
I tried this:
#Configuration
#ComponentScan("org.datalis.admin.config")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
PropertySourcesPlaceholderConfigurer conf = new PropertySourcesPlaceholderConfigurer();
conf.setLocation(new ClassPathResource("application.properties"));
return conf;
}
#Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("127.0.0.1");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
Apache server with Angular FE is running with Wildly server on the same server so I configured 127.0.0.1 for source.
But still I get:
Access to XMLHttpRequest at 'http://123.123.123.123:8080/api/oauth/token' from origin 'http://123.123.123.123' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
auth:1 Failed to load resource: the server responded with a status of 404 (Not Found)
Do you know how I can fix this issue?
Second way that I tried:
#Configuration
#EnableResourceServer
public class ResourceSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource_id").stateless(true);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users/**").permitAll()
.anyRequest().authenticated()
.and()
.cors().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest()
.fullyAuthenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Bean
public CorsConfigurationSource corsConfigurationSources() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
With the second configuration I get has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
auth:1 Failed to load resource: the server responded with a status of 404 (Not Found)
What is the best way to achieve this result?
Your allowed origin is 127.0.0.1 but your client side has the ip 123.123.123.123. Try to change this:
config.addAllowedOrigin("127.0.0.1");
To this:
config.addAllowedOrigin("123.123.123.123");
You need to tell Spring Security to use the CORS Configuration you created.
In my project I configured Spring Security in this way:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.antMatchers("/rest/protected/**")
.authenticated()
//Other spring sec configruation and then:
.and()
.cors()
.configurationSource(corsConfigurationSource())
}
Where corsConfigurationSource() is:
#Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
boolean abilitaCors = new Boolean(env.getProperty("templating.oauth.enable.cors"));
if( abilitaCors )
{
if( logger.isWarnEnabled() )
{
logger.warn("CORS ABILITATI! Si assume ambiente di sviluppo");
}
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200","http://localhost:8080", "http://localhost:8180"));
configuration.setAllowedMethods(Arrays.asList( RequestMethod.GET.name(),
RequestMethod.POST.name(),
RequestMethod.OPTIONS.name(),
RequestMethod.DELETE.name(),
RequestMethod.PUT.name()));
configuration.setExposedHeaders(Arrays.asList("x-auth-token", "x-requested-with", "x-xsrf-token"));
configuration.setAllowedHeaders(Arrays.asList("X-Auth-Token","x-auth-token", "x-requested-with", "x-xsrf-token"));
source.registerCorsConfiguration("/**", configuration);
}
return source;
}
I hope it's useful
Angelo
This is my working #Configuration class to handle CORS requests used only in dev environment.
#Configuration
//#Profile(PROFILE_DEV)
public class CorsConfiguration {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
};
}
}
You have also to configure Spring Security to ignore HttpMethod.OPTIONS used by preflight request (as the exception you mentioned)
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
//...
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
//others if you need
.antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.exceptionHandling()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated();
}
}
Because when you use cors you have Simple Request and Preflighted Request that triggers an HttpMethod.OPTIONS
I recommend you to use a WebMvcConfigurer, and in the addCorsMappings method set the CORS configuration.
Somethingo like this
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:9798")
.allowedMethods("POST", "GET")
//.allowedHeaders("header1", "header2", "header3")
//.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
}
}
Here there is a link with a fully functional Spring with CORS project, just download and run it.
https://github.com/reos79/spring-cors
It has a html page (person.html) this page does nothing but call the service on the port (9797). So you need to load this project twice, once on port 9797 to load the service and the other on port (9798). Then on you browser you call the page person on the server localhost:9798 and it will call the service on localhost:9797, in the file application.properties I configured the port.
You need to add #CrossOrigin class level in your controller class like below
#CrossOrigin
public class SampleController {
// Your code goes here
}
annotation to your rest controller class
Try changing your bean name to corsConfigurationSource removing the "s"
Documentation https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors
// by default uses a Bean by the name of corsConfigurationSource
i have a spring-rest application with oauth2 authentication. Everything works fine and i can receive a token and use it to authenticate and all that stuff. Now i am developing a frontend for the application with Angular2.
The main Problem here is: How can i allow CORS in my Oauth2 security configuration?
I have managed to allow it in my Controller classes with the #CrossOrigin annotation, but how does it work in the security configuration?
i have tried this:
#Configuration
#EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
But i still got the error:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
According to the Spring doc the CorsConfigurationSource is not used as a bean but in a CorsFilter, see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html#_filter_based_cors_support
public class MyCorsFilter extends CorsFilter {
public MyCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
Another way would be to provide a cors mapping in the WebMvcConfigurerAdapter, see https://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html#_javaconfig
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}