I'm my application I'm using OKTA.
My application sends request to OKTA to URL: http://localhost:8080/oauth2/authorization/okta (Call #1)
OKTA then calls its URL: https://dev-1234567.okta.com/oauth2/v1/authorize (Call #2)
I want to disable CORS check for both my application & for dev-1234567.okta.com as well.
With below configs I'm able to disable CORS check for my application urls but not any other.
I tried had coding dev-1234567.okta.com in addAllowedOrigin as well but same issue.
What am I missing?
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource()).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers("/app/**")
.hasAnyAuthority("ROLE_ADMIN").anyRequest()
.authenticated()
//........
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("GET");
configuration.addAllowedMethod("PUT");
configuration.addAllowedMethod("POST");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Okta is not calling your application with CORS, but your app calls Okta with CORS. So usually you'd need to enable CORS/Redirect in both of your Okta tenants for your http://localhost:8080 under Security->API->Trusted Origin
Related
This question already has answers here:
How to configure CORS in a Spring Boot + Spring Security application?
(22 answers)
Closed last month.
I have a CORS problem. I am using spring boot and vue to make a fullstack web. But I get the CORS error when I make the request from the front with axios to the Spring Security form. I'm sure I have to do something in my Authorization class to make the request, but I don't know.
Here is my code:
#EnableWebSecurity
#Configuration
public class WebAuthorization {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.formLogin()
.usernameParameter("email")
.passwordParameter("password")
.loginPage("/api/login");
http.logout().logoutUrl("/api/logout").deleteCookies("JSESSIONID");
return http.build();
}
I hope you can make the request from the front with Vue to the form that I have with spring security.
You can configure CORS using CorsConfigurationSource Bean. For example:
#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;
}
In case you want to allow cross origin requests:
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.applyPermitDefaultValues();
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
See Spring Security documentation for more information.
I have a backend server made in Java with Spring Boot, Security and Web and a client made with Angular.
Currently I am trying to make a simple request under localhost:8080/resource.
The controller for this address is shown bellow:
#RestController
public class IndexController {
#CrossOrigin
#RequestMapping("/resource")
public Map<String, Object> home() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
}
And the Angular client (the part that performs the request) is this:
import { Component } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
public title = "Security Client";
public greeting = {};
constructor(private http: HttpClient) {
http.get("http://localhost:8080/resource").subscribe(data => this.greeting = data);
}
}
The problem by using just what was shown is that I get a CORS error.
Whether removing Spring Security from my pom.xml or adding this configuration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/resource").permitAll();
}
}
Solves the problem.
What I wanna know is why I am getting an CORS error instead of a 401 Unauthorized when accessing an address that demands user authentication.
According to the spring boot documentation:
For security reasons, browsers prohibit AJAX calls to resources
outside the current origin. For example, you could have your bank
account in one tab and evil.com in another. Scripts from evil.com
should not be able to make AJAX requests to your bank API with your
credentials — for example withdrawing money from your account!
Cross-Origin Resource Sharing (CORS) is a W3C specification
implemented by most browsers that lets you specify what kind of
cross-domain requests are authorized, rather than using less secure
and less powerful workarounds based on IFRAME or JSONP.
You're getting this error because you need to add a filter in your security configuration. In your configure, add:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.authorizeRequests().antMatchers("/resource").permitAll();
}
In the same file, you should add:
#Bean
public CorsConfigurationSource corsConfigurationSource() {
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;
}
This works fine for me.
What I wanna know is why I am getting an CORS error instead of a 401
Unauthorized when accessing an address that demands user
authentication.
You get this error because before your actual request (POST, GET...), the browser performs a pre-flight request (OPTIONS) to validate if in fact the called server is able to handle CORS requests.
During this request, the Access-Control-Request-Method and Access-Control-Request-Header are validated and some other info are added to the header.
You receive the CORS error then because your actual request is not even done if CORS validation failed on the OPTIONS request.
You can check a flowchart of how CORS validation works in here
An interesting point is that you will only get a HTTP error status like 401 during the pre-flight request when the server is not authorized to answer the OPTIONS request.
I've been on a witch hunt of trying to figure out why cross-origin requests fail only in Firefox. Turns out Firefox does not send SSL/TLS credentials on cross-origin XHRs, which apparently is defined by the W3 CORS Spec. I was able to mostly resolve this by adding a withCredentials: true to my XHR instances in my client code (it works for GET, PUT, POST, DELETE, etc.).
However, Firefox still refuses to add credentials to pre-flight OPTIONS requests despite me explicitly telling it to in the XHR. Unless there is somehow a way to do this in client code, I am left with configuring my server to allow un-authenticated OPTIONS requests (which in a 2-way SSL configuration seems insane to me). Are there security risks here?
Our server is a Spring Boot project that uses Spring Security, and is configured for 2-way SSL using X509 security certificates. I will provide all relative code to give you an idea of how the application is configured.
Main class:
#EnableAutoConfiguration
#SpringBootApplication
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class OurApp extends WebSecurityConfigurerAdapter {
#Autowired
OurUserDetailsService ourUserDetailsService;
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext ctx = SpringApplication.run(OurApp.class, args);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// X509Configurer<HttpSecurity> x509Configurer = http.authorizeRequests().anyRequest().authenticated().and().x509();
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().
.anyRequest().authenticated()
.and()
.x509().subjectPrincipalRegex("(.*)").authenticationUserDetailsService(ourUserDetailsService)
.and()
.cors()
.and()
.csrf().disable();
}
}
Configuration class that has CORS setup:
#Configuration
public class OurConfig {
#Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://client-origin"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Access-Control-Allow-Origin",
"Access-Control-Allow-Headers", "X-Requested-With", "requestId", "Correlation-Id"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
return configurer -> {
List<RequestMatcher> matchers = new ArrayList<>();
matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
configurer.requestMatchers(new OrRequestMatcher(matchers));
};
}
}
This WORKS on all GET requests, and when I manually perform the requests in browser for the other verbs -- except for OPTIONS. The preflight request continues to fail during the TLS handshake and is aborted by Firefox. I'm confused, is it even possible to send an un-authenticated (credential-less) request over (two-way SSL) HTTPS?
How do I configure spring security or spring boot to allow unauthenticated OPTIONS requests with a two-way SSL (over HTTPS) enabled configuration?
The preflight request should exclude credentials, see CORS specification:
7.1.5 Cross-Origin Request with Preflight
To protect resources against cross-origin requests that could not originate from certain user agents before this specification existed a preflight request is made to ensure that the resource is aware of this specification. The result of this request is stored in a preflight result cache.
The steps below describe what user agents must do for a cross-origin request with preflight. This is a request to a non same-origin URL that first needs to be authorized using either a preflight result cache entry or a preflight request.
[...]
Exclude user credentials.
To handle a preflight request without credentials (SSL client certificate), you have to change the SSL configuration of your server.
For example, see Spring Boot Reference Guide:
server.ssl.client-auth= # Whether client authentication is wanted ("want") or needed ("need"). Requires a trust store.
I am using keycloak to secure my rest service. I am refering to the tutorial given here. I created the rest and front end. Now when I add keycloak on the backend I get CORS error when my front end makes api call.
Application.java file in spring boot looks like
#SpringBootApplication
public class Application
{
public static void main( String[] args )
{
SpringApplication.run(Application.class, args);
}
#Bean
public WebMvcConfigurer corsConfiguration() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/*")
.allowedMethods(HttpMethod.GET.toString(), HttpMethod.POST.toString(),
HttpMethod.PUT.toString(), HttpMethod.DELETE.toString(), HttpMethod.OPTIONS.toString())
.allowedOrigins("*");
}
};
}
}
The keycloak properties in the application.properties file look like
keycloak.realm = demo
keycloak.auth-server-url = http://localhost:8080/auth
keycloak.ssl-required = external
keycloak.resource = tutorial-backend
keycloak.bearer-only = true
keycloak.credentials.secret = 123123-1231231-123123-1231
keycloak.cors = true
keycloak.securityConstraints[0].securityCollections[0].name = spring secured api
keycloak.securityConstraints[0].securityCollections[0].authRoles[0] = admin
keycloak.securityConstraints[0].securityCollections[0].authRoles[1] = user
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /api/*
The sample REST API that I am calling
#RestController
public class SampleController {
#RequestMapping(value ="/api/getSample",method=RequestMethod.GET)
public string home() {
return new string("demo");
}
}
the front end keycloak.json properties include
{
"realm": "demo",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "tutorial-frontend",
"public-client": true
}
The CORS error that I get
XMLHttpRequest cannot load http://localhost:8090/api/getSample. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 401.
I know.. the Problem is quite Old.
But if you've Problems with the local development with Spring Boot + Keycloak you can use the Config
keycloak.cors=true
in your application.properties.
Cheers :)
Try creating your CORS bean like my example. I recently went through the same thing (getting CORS to work) and it was a nightmare because the SpringBoot CORS support is currently not as robust or straightforward as the MVC CORS.
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
This is how I set it up to accept any origin application-wide, but if you change a few of the parameters you should be able to replicate what you want. ie. if you wanted to add only the methods you mentioned, chain some addAllowedMethod(). Allowed origins would be the same, and then your addMapping("/api/*") would become source.registerCorsConfiguration("/api/*", config);.
Edit:
Spring Data Rest and Cors
Take a look at this. Sebastian is on the Spring engineering team so this is about as good as you're going to get for an official answer.
I came here with the same problem and fix it ommiting authentication for OPTIONS method only, like this:
keycloak.securityConstraints[0].security-collections[0].omitted-methods[0]=OPTIONS
It worked for me because the OPTIONS request Keycloack does, does not include Authentication header.
UPDATE
There was something with my browser's cache so I could not see the real impact of a change in my backend code. It looks like what really worked for me was enabling all CORS origins at #RestController level, like this:
#CrossOrigin(origins = "*")
#RestController
public class UsersApi {...}
I don't have access to code examples, but based on the code configurations you have included, it looks like a missing configuration is causing spring to exclude CORS headers.
J. West's response is similar to recent issues I encountered with Spring and CORS, I would however caution you to look into which implementation a spring example references, because there are two. Spring Security and Spring MVC Annotations. Both of these implementations work independent of each other, and can not be combined.
When using the filter based approach as you are (even boiled down), the key was to set allow credentials to true, in order for the authentication headers to be sent by the browser across domains. I would also advise using the full code method proposed above, as this will allow you to create a far more configurable web application for deployment across multiple domains or environments by property injection or a service registry.
Access-Control-Allow-Origin header is supposed to be set by the server application basis the Origin request header provided in the request to the server application. Usually browsers set the Origin header in request whenever they sense a cross origin request being made. And they expect a Access-Control-Allow-Origin header in response to allow it.
Now, for keycloak, I struggled with the same issue. Looking at this, it seems like keycloak does not add Access-Control-Allow-Origin header in case of error response. However, for me it was not adding this header in the response even in case of success response.
Looking into the code and adding breakpoints, I noticed that the webOrigin for client object was not getting populated from the Origin header even if passed and hence CORS was not adding the access control response header.
I was able to get it working by adding the following line of code just before the CORS build call:
client.addWebOrigin(headers.getRequestHeader("Origin").get(0));
before:
Cors.add(request, Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
Once I built the code with this change and started the server, I started getting the three access control response headers:
Access-Control-Expose-Headers: Access-Control-Allow-Methods
Access-Control-Allow-Origin: http://localhost:9000
Access-Control-Allow-Credentials: true
I am using client credentials grant type; hence i added it only in the buildClientCredentialsGrant at TokenEndpoint.java#L473.
I still need to do some more code diving in order to say for sure that it is a bug for success responses at well and to find a better place to set this on the client object in keycloak code (like where client object is being constructed)
You are welcome to give it a try.
UPDATE:
I take this back. I re-registered my client in keycloak with Root URL as http://localhost:9000 (which is my front-end's application port) and i started getting the proper access control response headers. Hope this helps you.
I know the problem is too old but, I found better solution.
Read more at official documentation
Inside your application.yml file
keycloak:
auth-server-url: http://localhost:8180/auth
realm: CollageERP
resource: collage-erp-web
public-client: true
use-resource-role-mappings: true
cors: true
cors-max-age: 0
principal-attribute: preferred_username
cors-allowed-methods: POST, PUT, DELETE, GET
cors-allowed-headers: X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers
or you can config using application.properties file
keycloak.auth-server-url= http://localhost:8180/auth
keycloak.realm= CollageERP
keycloak.resource= collage-erp-web
keycloak.public-client= true
keycloak.use-resource-role-mappings= true
keycloak.cors= true
keycloak.cors-max-age= 0
keycloak.principal-attribute= preferred_username
keycloak.cors-allowed-methods= POST, PUT, DELETE, GET
keycloak.cors-allowed-headers= X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers
and my java adaper class
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import javax.ws.rs.HttpMethod;
#KeycloakConfiguration
#EnableGlobalMethodSecurity(jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.cors().and().authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/api/**")
.authenticated()
.anyRequest().permitAll();
http.csrf().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Bean
public KeycloakConfigResolver KeycloakConfigResolver() {
return new KeycloakSpringBootConfigResolver();
}
}
I want to share with you the solution that worked for me hoping to help whoever is facing the same issue. I am going to give you two solutions actually.
Spring reactive:
#Configuration
#EnableWebFluxSecurity
public class SecurityConfig {
#Autowired
private ReactiveClientRegistrationRepository clientRegistrationRepository;
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
CorsConfiguration cors_config = new CorsConfiguration();
cors_config.setAllowCredentials(true);
cors_config.applyPermitDefaultValues();
cors_config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "null"));
cors_config.setAllowedMethods(List.of("GET","POST","OPTIONS","DELETE"));
cors_config.setAllowedHeaders(List.of("*"));
http.cors().configurationSource(source -> cors_config)
.and()
.csrf().disable()
.authorizeExchange(exchanges -> exchanges.anyExchange().authenticated())
.oauth2Login()//Setting Oauth2Login
.authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("")).and()
.logout(logout -> logout //Setting Oauth2Logout
.logoutHandler(logoutHandler())
.logoutSuccessHandler(oidcLogoutSuccessHandler()));
return http.build();
}
private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {
OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
new OidcClientInitiatedServerLogoutSuccessHandler(this.clientRegistrationRepository);
// Sets the location that the End-User's User Agent will be redirected to
// after the logout has been performed at the Provider
oidcLogoutSuccessHandler.setPostLogoutRedirectUri("");
return oidcLogoutSuccessHandler;
}
private DelegatingServerLogoutHandler logoutHandler() {
//Invalidate session on logout
return new DelegatingServerLogoutHandler(
new SecurityContextServerLogoutHandler(), new WebSessionServerLogoutHandler());
}
}
Spring MVC:
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
CorsConfiguration cors_config = new CorsConfiguration();
cors_config.setAllowCredentials(true);
cors_config.applyPermitDefaultValues();
cors_config.setAllowedOrigins(Arrays.asList("http://localhost:3000", "null"));
cors_config.setAllowedMethods(List.of("GET","POST","OPTIONS","DELETE"));
cors_config.setAllowedHeaders(List.of("*"));
http.cors().configurationSource(source -> cors_config).and()...
return http.build();
}
}
Be sure to have cors enabled on Keycloak too, navigate to
realm->clients->settings->weborigins
and submit your permitted origins.
If you are sending credentials or cookies in your requests, be sure to configure it, for example, if you are using ReactJS:
const httpConfig = { withCredentials: true };
axios.get('YourUrl', httpConfig)
.then(response => {})
.catch(error => {})
.finally(() => {});
When your client is sending an Authentication header, you cannot use
allowedOrigins("*"). You must configure a specific origin URL.
Since you have set the property keycloak.cors = true in your application.properties file, you have to mention the CORS enabled origins in the Keycloak server. To do that follow the below steps.
Go to Clients -> Select the client (Token owner) -> Settings -> Web Origins
Add origins one by one or add * to allow all.
After doing this you have to get a new token. (If you decode the token you will see your origins as allowed-origins": ["*"])
Setting the property keycloak.cors = false is another option. But this completely disables CORS.
Startup Appplication:
#SpringBootApplication
#EnableZuulProxy
public class ZuulServer {
public static void main(String[] args) {
new SpringApplicationBuilder(ZuulServer.class).web(true).run(args);
}
}
My YAML file is like this:
server:
port:8080
spring:
application:
name: zuul
eureka:
client:
enabled: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
zuul:
proxy:
route:
springapp: /springapp
I have a microservice application (on port 8081) called springapp and has some rest services. Below is my client UI app:
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="text/javascript" src="js/libs/jquery/jquery.min.js" ></script>
</head>
<body>
<script type="text/javascript">
$.ajax({
url: 'http://localhost:8080/zuul/springapp/departments',
type: 'GET'
}).done(function (data) {
consoe.log(data);
document.write(data);
});
</script>
</body>
</html>
But I get a
XMLHttpRequest cannot load http://localhost:8080/zuul/springapp/departments. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8383' is therefore not allowed access.
This UI HTML5 app is on http://localhost:8383/SimpleAPp/index.html. CORS, CORS, CORS... Please help. BTW the http://localhost:8080/zuul/springapp/departments returns a json list as supposed to when on the browser address bar. The spring.io blog here says that there is no need for a filter because the zuulproxy takes care of that but I don't know why it is not working for me.
Adding this piece of code to your class annotated with #EnableZuulProxy should do the trick.
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
I had a similar problem, with Angular Web app consuming RESTful services implemented by Spring Boot with Zuul and Spring Security.
None of the above solutions worked. I realized that the problem was NOT in Zuul, but in Spring Security.
As the official documentation (CORS with Spring Security) states, when using Spring Security, CORS must be configured prior to Spring Security.
Finally, I was able to integrate Grinish Nepal's (see prior answers) solution into a solution that works.
Without further ado, here is the code that enables CORS with Spring Security and Zuul:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//irrelevant for this problem
#Autowired
private MyBasicAuthenticationEntryPoint authenticationEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
//configure CORS -- uses a Bean by the name of corsConfigurationSource (see method below)
//CORS must be configured prior to Spring Security
.cors().and()
//configuring security - irrelevant for this problem
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
//irrelevant for this problem
http.addFilterAfter(new CustomFilter(),
BasicAuthenticationFilter.class);
}
//The CORS filter bean - Configures allowed CORS any (source) to any
//(api route and method) endpoint
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin(CorsConfiguration.ALL);
config.addAllowedHeaders(Collections.singletonList(CorsConfiguration.ALL));
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return source;
}
//configuring BA usernames and passwords - irrelevant for this problem
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
...
}
}
When your application runs on http://localhost:8383 then you can only make AJAX-calls to http://localhost:8383. Zuul doesn't and cannot change that.
What Zuul can do is mapping requests for e.g. http://localhost:8383/zuul/ to http://localhost:8080/zuul/. But your browser would have to call http://localhost:8383/zuul/springapp/departments and you have to configure that mapping.
Just adding the following to the configuration worked for me
zuul:
ignoredHeaders: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
I had the same issue, and i have fixed by adding CorsFilter bean
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
And adding zuul's properties this code
zuul:
sensitiveHeaders:
ignored-headers: Access-Control-Allow-Credentials, Access-Control-Allow-Origin
You can find more detail about the issue here
That's just the browser telling you that you breached its common origin policy (see Wikipedia entry and a huge amount of material on the internet, none of which is really relevant to the tags you added). You can either teach the browser that it is OK to load resources from a different address by servicing the CORS pre-flight checks (e.g. in a Filter) or load the HTML through the proxy (hint: the latter is much easier and less error prone).
For those still having issue even when #Bean CorsFilter is added, check if the controller is also annotated with #CrossOrigin, this duplication of CORS, at controller level and at Zuul proxy is probably causing the issue.