I am a backend developer and i am providing a spring boot rest API with JWT security to consume for a front end developer who calls the api from local host.So when he calls a POST request he says he gets an CORS error.So I added the part
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(request, response);
}
But still he gets the error.What may be the cause.Any help is appreciated
OPTIONS https:my.domain/url 401 (Unauthorized)
when it is a POST request.
Controller code:
#RestController
public class RegistrationController {
#Autowired
#Qualifier("restTemplateUserRegitration")
private RestTemplate restTemplateUserRegitration;
#RequestMapping(value="${user.endpoint}",produces={MediaType.APPLICATION_JSON_VALUE},method=RequestMethod.POST)
public ResponseEntity<?> registerUser(#RequestBody Model ModelRequest){
Map<String, Object> Status=new HashMap<String, Object>();
FeedBackStatus = restTemplateUserRegitration.postForObject("http:serviceurl",registration/single",Model.class,Map.class );
return ResponseEntity.ok(Status);
}
}
I also had a similar experience. We have solved the problem as follows.
This code added in securityConfiguration.
The browser will send the OPTIONS request first before sending the POST request. Therefore, when the request is sent, the authorization header value is not included in the request header, so the JWT filter judges that the user is unauthenticated.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS);
}
Try this first, this should allow all origins, but it is security risk.
response.setHeader("Access-Control-Allow-Origin", "*");
This is one option. Not sure if its an elegant one
#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;
}
Put this in any spring bean.
You can create your own CorsConfiguration
#EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
CorsConfigurationSource corsConfigurationSource = new CorsConfigurationSource() {
#Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("http://localhost:63342");
corsConfiguration.addAllowedHeader("Authorization");
corsConfiguration.setAllowedMethods(Arrays.asList("POST", "GET"));
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}
};
And add it to configuration.
.and().cors().configurationSource(corsConfigurationSource);
And try using this annotation
#CrossOrigin
You should implement a filter like this:
public class CORSFilter extends OncePerRequestFilter {
private final Logger LOG = LoggerFactory.getLogger(CORSFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
LOG.info("Adding CORS Headers ........................");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
Found this from the post Cross Origin Request Blocked Spring MVC Restful Angularjs
Hope this help!
Related
After deploy I got problem with CORS. I can access data directly from my API but when trying fetch it from React app I got problem as in an image:
I tried to add filters to add to every header Access-Control-Allow-Origin and it now return data from API and I can see it in browsers console but react cant get it
WebSecurity.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and();
http.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and();
http.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public FilterRegistrationBean crosFilterRegistration(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean(new MyCorsFilter());
registrationBean.setName("CORS Filter");
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("https://*************"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"));
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"));
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
MyCorseFiltre.java
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class MyCorsFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "https://**************");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, HEAD, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig config) throws ServletException {
}
}
Application.java
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("https://*************");
}
};
}
This row
response.setHeader("Access-Control-Allow-Origin", "https://**************");
adds the duplicated header. So does this row:
configuration.setAllowedOrigins(Collections.singletonList("https://*************"));
One of them is enough. Preferably the latter. The same goes for most of the CORS config you have.
I have implemented Filter for CORS in spring boot.The code is as follow:-
#SpringBootApplication
#Component
public class Application implements Filter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
To get the access_token from oauth2 I have created following object from angularjs:-
{"url":"http://localhost:8080/oauth/token?grant_type=client_credentials&client_id=clientId&client_secret=clientSecret","headers":{"Authorization":"Basic token_value"},"withCredentials":true,"method":"POST"}
I am getting following error when I hit the server:-
OPTIONS url... 401() Response for preflight has invalid HTTP status code 401
I have looked for the solutions for similar problems in stack overflow but none of them fixed my problem.Could someone please help on this?
Following piece of code solved my problem
#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(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
The code sample is taken from https://github.com/spring-projects/spring-security-oauth/issues/938
Please read more about Preflight requests.
They simply suggest the browser if the server supports a cross-origin request. The response to such OPTIONS requests should good (i.e. < 400).
I think the statement filterChain.doFilter(servletRequest, servletResponse); is passing the request further, instead of returning a response.
You can read more about enabling CORS using Spring in Java here Enable CORS for OPTIONS request using Spring Framework
I'm using spring security with OAuth2 (version: 4.0.4.RELEASE) and spring (verison: 4.3.1.RELEASE).
I'm developing frontend in Angular and I'm using grunt connect:dev (http://127.0.0.1:9000). When I trying to login by localhost address everything working fine but from other I'm getting error:
"XMLHttpRequest cannot load http://localhost:8084/oauth/token?client_id=MY_CLIENT_ID. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:9000' is therefore not allowed access. The response had HTTP status code 401."
I have configured mapping (Overrided public void addCorsMappings(CorsRegistry registry)) in WebMvcConfigurerAdapter (like below) but it still not working for http://127.0.0.1:9000.
registry.addMapping("/**")
.allowedOrigins("http://127.0.0.1:9000")
.allowedMethods("POST", "OPTIONS", "GET", "DELETE", "PUT")
.allowedHeaders("X-Requested-With,Origin,Content-Type,Accept,Authorization")
.allowCredentials(true).maxAge(3600);
Configuration based on: https://spring.io/guides/gs/rest-service-cors/
Please, point me the right directon to resolve this issue.
Hopefully, you found an answer long ago, but if not (and if anyone else finds this question searching as I was):
The issue is that Spring Security operates using filters and those filters generally have precedence over user defined filters, #CrossOrigin and similar annotations, etc.
What worked for me was to define the CORS filter as a bean with highest precedence, as suggested here.
#Configuration
public class MyConfiguration {
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://127.0.0.1:9000");
config.setAllowedMethods(Arrays.asList("POST", "OPTIONS", "GET", "DELETE", "PUT"));
config.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization"));
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
Sorry for long time response. I resolved the issue by configuring my CORS filter like below:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
private static final Logger LOGGER = LogManager.getLogger(CORSFilter.class.getName());
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
final String origin = ((HttpServletRequest) req).getHeader("Origin");
if (ofNullable(origin).isPresent() && origin.equals("http://127.0.0.1:9000")) {
LOGGER.info("CORSFilter run");
response.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:9000");
response.addHeader("Access-Control-Allow-Credentials", "true");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.addHeader("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept,Authorization");
response.setStatus(200);
}
}
chain.doFilter(addNessesaryHeaders(request), response);
}
private MutableHttpServletRequest addNessesaryHeaders(final HttpServletRequest request) {
final MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);
mutableRequest.putHeader("Accept", "application/json");
mutableRequest.putHeader("Authorization", "Basic" + " bXVzaWNzY2hvb2w6");
return mutableRequest;
}
#Override
public void destroy() {
}
}
You can try something like that
#Configuration
public class CorsConfig {
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods(HttpMethod.OPTIONS.name(),
HttpMethod.PATCH.name(),
HttpMethod.PUT.name(),
HttpMethod.DELETE.name(),
HttpMethod.GET.name(),
HttpMethod.POST.name())
.maxAge(360);
}
};
}
}
Note: Spring version should be 4.2 or later
below worked for me.
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#Configuration
#EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
}
I use <spring.version>4.2.0.RELEASE</spring.version>, <spring.security.version>4.0.2.RELEASE</spring.security.version>, and <spring.security.oauth2.version>2.0.9.RELEASE</spring.security.oauth2.version>.
I use #CrossOrigin to dela with CORS. For now, I want to allow all the headers and all the methods. I can use any of the other headers than Authorization without any CORS issue. But with Authorization(header to send Bearer token), I get CORS issue. I use #CrossOrigin annotatiion at Class level and allow all the headers as below -
#CrossOrigin(allowedHeaders = {"*"})
No 'Access-Control-Allow-Origin' header is present on the requested
resource
How can I allow Authorization header as well as I did all other headers and avoid CORS issues?
You can add the following to any configuration file:
#Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
EDIT
For XML configuration, you could create a custom filter and add it to your filter chain:
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
XML config
<security:filter-chain-map>
<sec:filter-chain pattern="/**"
filters="
ConcurrentSessionFilterAdmin,
securityContextPersistenceFilter,
logoutFilterAdmin,
usernamePasswordAuthenticationFilterAdmin,
basicAuthenticationFilterAdmin,
requestCacheAwareFilter,
securityContextHolderAwareRequestFilter,
anonymousAuthenticationFilter,
sessionManagementFilterAdmin,
exceptionTranslationFilter,
filterSecurityInterceptorAdmin,
CorsFilter"/>
</security:filter-chain-map>
I serve my front- and backend from two different servers. Now I am trying to get CORS working on the Spring-Boot-Jersey backend. I tried everything I could find on the internet but nothing seem to work or I am missing something.
My current setup uses a ContainerResponseFilter. I tried registering it automatically with #Provider and manually in the Jersey configuration.
ContainerResponseFilter
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request,
ContainerResponseContext response) throws IOException {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Headers",
"origin, content-type, accept, authorization");
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
}
}
Maybe it is important but I also used Spring-Security-oauth2 by adding the #EnableOAuth2Sso annotation. Please tell me if you need more of my setup.
I fixed it this way,
First create a class
public class CORSResponseFilter implements ContainerResponseFilter {
public void filter(ContainerRequestContext requestContext,ContainerResponseContext responseContext)
throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
//headers.add("Access-Control-Allow-Origin", "http://abcd.org"); //allows CORS requests only coming from abcd.org
headers.add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
headers.add("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, X-Codingpedia");
}
}
The filter must inherit from the ContainerResponseFilter interface and must be registered as a provider:
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(CORSResponseFilter.class);
//other registrations
}
}
Fixed it by using the CORSFilter displayed in https://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {
void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Max-Age", "3600");
if (request.getMethod()!='OPTIONS') {
chain.doFilter(req, res);
} else {
}
}
void init(FilterConfig filterConfig) {}
void destroy() {}
}
Not sure if the #Provider annotation is supported by Spring. Try replacing the #Provider annotation with Springs #Component and the CORSFilter should extend org.springframework.web.filter.OncePerRequestFilter. This is the Spring way of configuring Filters and this will work for any application server.
You can also configure CORS via the WebMvcConfigurerAdapter, which might be more compact:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("...") // add headers
.allowedMethods(".."); // add methods
}
};
}
Check out this guide!