spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.74k stars 40.58k forks source link

Broken CORS Support with Spring Security #5834

Closed rudolfschmidt closed 8 years ago

rudolfschmidt commented 8 years ago

Using Spring Boot in combination with Spring Security and enabling Cors Support with Annotation @CrossOrigin leads to a broken cors response if the authentication with spring security fails.

Considering java script code for cors request:

url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
    if xmlhttp.readyState is 4
        console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send

The output needs to be 200. If the credentials are valid, the request will be 200.

Considering the usecase the credentials are wrong, you would expect output 401 (the standard code for failed authentication). but with spring boot and spring security the output will be 0 with the browser notification:

XMLHttpRequest cannot load http://localhost:5000/api/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://rudolfschmidt:3000' is therefore not allowed access. The response had HTTP status code 401.

The OPTION request goes through

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:3000
Pragma:no-cache
Referer:http://localhost:3000/

and the reserver response

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:authorization
Access-Control-Allow-Methods:GET
Access-Control-Allow-Origin:http://localhost:3000
Access-Control-Max-Age:1800
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:0
Date:Mon, 02 May 2016 06:52:03 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

and the result is

Request URL:http://localhost:5000/api/token
Request Method:OPTIONS
Status Code:200 OK
Remote Address:[::1]:5000

everthing is fine.

but now the real request starts:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Authorization:Basic YTphYQ==
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:5000
Origin:http://localhost:3000
Pragma:no-cache
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.75 Safari/537.36

and the response is

Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json;charset=UTF-8
Date:Mon, 02 May 2016 06:52:03 GMT
Expires:0
Pragma:no-cache
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
WWW-Authenticate:Basic realm="Realm"
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

the result is

Request URL:http://localhost:5000/api/token
Request Method:GET
Status Code:401 Unauthorized
Remote Address:[::1]:5000

its also fine, but because the failing header Access-Control-Allow-Origin the ajax request is broken.

I assume that spring security doesnt notice that corsSupport is enabled, because the CrossOrigin Annotiation is at the RestController. Spring Security handles like a gateway before the request has a chance to reach the Annotation that enables the Cors Headers.

The solution is adding a CorsFilter in the Spring Security Chan.

My Spring Code

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
@RestController
@RequestMapping("api")
public class Controller {
    @RequestMapping("token")
    @CrossOrigin
    Map<String, String> token(HttpSession session) {
        return Collections.singletonMap("token", session.getId());
    }
}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsService userDetailsService;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .requestMatchers(CorsUtils::isCorsRequest).permitAll()
                .anyRequest().authenticated()
                .and().httpBasic()
                .and().addFilterBefore(new WebSecurityCorsFilter(), ChannelProcessingFilter.class);
    }
}
public class WebSecurityCorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse res = (HttpServletResponse) response;
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");
        chain.doFilter(request, res);
    }
    @Override
    public void destroy() {
    }
}

The solution works but the external filter is ugly and should be work out of the box.

I hope spring boot is the right repository for that issue cause it refers to spring security as well.

wilkinsona commented 8 years ago

This feels to me like it should be handled in Spring Security as it would be generally useful to everyone using Spring Security, not just using Spring Boot and Spring Security.

What you you think, @rwinch?

spring-projects-issues commented 8 years ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

wilkinsona commented 8 years ago

Ping @rwinch

rudolfschmidt commented 8 years ago

Which feedback do you need from me? @wilkinsona the reason why i have opened here is that spring boot autoconfigure spring security and the annotation doesnt work with the spring security authentication system

wilkinsona commented 8 years ago

@rudolfschmidt Sorry for the confusion. It's @rwinch that we need some feedback from

rwinch commented 8 years ago

@rudolfschmidt Thanks for the report.

I don't know that there is a lot that can be done with the current CORS APIs. Spring Security has no insight as to what the CORS configuration Spring MVC is providing, so it cannot leverage that information to inject the headers.

At the only way I see this working is using the Filter as you have already described.

Perhaps @rstoyanchev or @sdeleuze have some ideas though.

rudolfschmidt commented 8 years ago

If there is no way around, I would suggest to remove these Annotations if Spring Technologies dont support it sufficient. In every web app you need a kind of authentication. What is the benefit of those annotations if you cant use them with spring security and you need to develop your own filter system. Even if you dont need spring security you still need your own implementation of an authentication system that will not work with those annotations I guess.

sdeleuze commented 8 years ago

If you want to define CORS configuration in a single place and get it used by both Spring MVC and Spring Security, the filter based solution is indeed a good one. In that case, don't use @CrossOrigin at @Controller or @RequestMappinglevel and just configure a global filter that will handle both Spring Security and Spring MVC requests. Be aware that you don't have to create your own filter, we provide one with Spring Framework, based on the same logic than the @CrossOrigin support.

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("http://domain1.com);
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    Filter corsFilter = new CorsFilter(source);

In order to get this filter taken in account, you can use it with Spring Security addFilterBefore() method like you did, or register it as a @Bean. There may be an order issue if your register a CorsFilter bean so currently you need to register a FilterRegistrationBean bean to be able to specify the order:

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("http://domain1.com");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(0);
    return bean;
}

That said, for your use case there is maybe an improvement we discussed with @dsyer: supporting @CrossOrigin annotation with a global scope if used at @Configuration level. That could result is creating a filter with order = 0 like explained previously, but in a much more concise way for the user. This improvement + more guideline in the documentation in order to advise to use global CORS configuration for secured websites would resolve this kind of issue I think. This kind of feature may also be useful for enabling CORS on Spring Data REST. Any thoughts?

rstoyanchev commented 8 years ago

We are also looking for ways to expose the knowledge that we have with @CrossOrigin at the HandlerMapping level to Spring Security and I'll provide an update once we know more

In the meantime however as Sebastien pointed out, we do provide a CorsFilter so you can re-use the same infrastructure code that underlies the @CrossOrigin support. In other words you don't have to write such a Filter yourself.

wilkinsona commented 8 years ago

I'm going to close this one. It sounds like some improvements in Spring Framework will be available in due course and there's nothing to be done in Spring Boot to address this.

sdeleuze commented 8 years ago

I have updated my Spring + CORS blog post to add more details about the filter based solution: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#filter-based-cors-support and also answered on Stackoverflow.

I will update it again if we achieve better integration between Spring MVC and Spring Security as suggested by @rstoyanchev.

rwinch commented 8 years ago

@rudolfschmidt I wanted to let you know that Spring Security 4.1.1 was released with what should be a fix for the CORS issues you were having. Take a look at the second example which leverages the CORS configuration from Spring MVC http://docs.spring.io/spring-security/site/docs/4.1.x/reference/htmlsingle/#cors

NOTE: You must use Spring Framework 4.3.1 to take advantage of this feature because it is the first release to provide the necessary hooks.

vramku5 commented 7 years ago

http://stackoverflow.com/questions/40658655/spring-security-angular-js-cors-issue-error-xmlhttprequest-cannot-load-htt

I have tried the suggestion in the blog post, but I am getting a redirect in the OPTIONS request and hence the GET fails. Can you please take a look?

vramku5 commented 7 years ago

I had to set spring.filter-order: 50 (some high number), so that corsFilter appears before springSecurityFilterChain and OAuth2ClientContextFilter. Then it works.

Is this the right fix ? Is bean.setOrder(0) not taking effect or getting overridden by some other springSecurity code?

nebrass commented 7 years ago

Hello @vramku5 I think it will be better if you mark your method with : @Order(Ordered.HIGHEST_PRECEDENCE) So you let the container make sure that your component will be handled before any other component.

vramku5 commented 7 years ago

Hi @nebrass, I tried it, and it doesn't seem to take precedence. Maybe the explicit set by spring code overrides annotations.

@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DCorsConfiguration {

    @Bean
    public FilterRegistrationBean dgCorsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        org.springframework.web.cors.CorsConfiguration config = new org.springframework.web.cors.CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:5000");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));

        //bean.setOrder(-110);

    }
}

The output from spring-boot:run. You can see that the cors filter is after spring security filter chain. If I uncomment the line which has bean.setOrder, then corsfilter gets mapped before.

2016-11-23 13:35:44.883  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2016-11-23 13:35:44.884  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2016-11-23 13:35:44.884  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2016-11-23 13:35:44.884  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'OAuth2ClientContextFilter' to: [/*]
2016-11-23 13:35:44.884  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2016-11-23 13:35:44.886 DEBUG 17404 --- [ost-startStop-1] o.s.w.c.s.StandardServletEnvironment     : Adding [servletConfigInitParams] PropertySource with lowest search precedence
2016-11-23 13:35:44.886 DEBUG 17404 --- [ost-startStop-1] o.s.w.c.s.StandardServletEnvironment     : Adding [servletContextInitParams] PropertySource with lowest search precedence
2016-11-23 13:35:44.886 DEBUG 17404 --- [ost-startStop-1] o.s.w.c.s.StandardServletEnvironment     : Adding [systemProperties] PropertySource with lowest search precedence
2016-11-23 13:35:44.886 DEBUG 17404 --- [ost-startStop-1] o.s.w.c.s.StandardServletEnvironment     : Adding [systemEnvironment] PropertySource with lowest search precedence
2016-11-23 13:35:44.887 DEBUG 17404 --- [ost-startStop-1] o.s.w.c.s.StandardServletEnvironment     : Initialized StandardServletEnvironment with PropertySources [servletConfigInitParams,servletContextInitParams,systemProperties,systemEnvironment]
2016-11-23 13:35:44.887  INFO 17404 --- [ost-startStop-1] .s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
2016-11-23 13:35:44.887  INFO 17404 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'corsFilter' to: [/*]
ceefour commented 7 years ago

Since Spring Security 4.1, this is the proper way to make Spring Security support CORS (also needed in Spring Boot 1.4/1.5):

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    }
}

and:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.csrf().disable();
        http.cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Do not do any of below, which are the wrong way to attempt solving the problem:

Reference: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html

ghost commented 7 years ago

@ceefour Thanks man, your solutions works for me. But now if I can't use http.authorizeRequests().antMatchers(HttpMethod.POST, "/some_api").hasRole(UserRole.USER);, how do I specified what routes are for the user and witch are for the admin role ?

ceefour commented 7 years ago

@bretoiurazvan there's no problem with that. the "do not do" is only for HttpMethod.OPTIONS

bvulaj commented 7 years ago

@ceefour - That configuration above is still not working for OPTIONS preflight requests, as I'm still seeing the referenced error; No 'Access-Control-Allow-Origin' header is present on the requested resource. I've provided configuration below, but let me know if there is other info I could provide.

@Configuration
@EnableWebSecurity
@EnableJdbcHttpSession
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            ...
            .and().cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(/**origins**/);
        configuration.setAllowedMethods(ImmutableList.of("*"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(ImmutableList.of("*"));
        configuration.setExposedHeaders(ImmutableList.of("Access-Control-Allow-Origin", "Access-Control-Allow-Methods", "Access-Control-Allow-Headers", "Access-Control-Max-Age",
                "Access-Control-Request-Headers", "Access-Control-Request-Method"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

and:

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry
            .addMapping("/**")
                .allowedOrigins(/**origins**/)
                .allowedMethods("*")
                .allowedHeaders("*")
                .exposedHeaders("Access-Control-Allow-Origin", 
                        "Access-Control-Allow-Methods", 
                        "Access-Control-Allow-Headers", 
                        "Access-Control-Max-Age", 
                        "Access-Control-Request-Headers", 
                        "Access-Control-Request-Method");
    }
}
qubittraining commented 6 years ago

I am getting

The method cors() is undefined for the type HttpSecurity

This is my code

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors();

        http
        .headers()
        .frameOptions()
        .disable();

I am using spring 4.2.6-RELEASE

snicoll commented 6 years ago

@qubittraining this issue is closed and we don't use the tracker for questions, please ask on StackOverflow.

erycoking commented 6 years ago

Hi, am trying to consume my rest api built with spring boot using angular 6 and I keep getting the following error

Response for preflight does not have HTTP ok status

On postman the code works fine but when I try to consume it with my application it gives me an the error in my browser console. I have tried all the solution posted on this page but nothing seem to work. Am using spring boot: 2.0.5 and spring cloud version: Finchley.SR1 Below is my configurations

Authorization Server

package com.erycoking.Hunch.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("Hunch")
                .secret(passwordEncoder.encode("my_hunch_secret"))
                .scopes("read", "write", "trusted")
                .authorizedGrantTypes("password")
                .authorities("ROLE_USER", "ROLE_ADMIN", "ROLE_GUEST")
                .resourceIds("oauth2_resource")
                .accessTokenValiditySeconds(3600)
                .refreshTokenValiditySeconds(86400);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }
}

Resource Server

package com.erycoking.Hunch.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .cors().and()
                .antMatcher("/**").authorizeRequests()
                .antMatchers(  "/", "/students", "/login", "/register", "/oauth/token").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}

Web Config

package com.erycoking.Hunch.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private CustomUserDetailsService userDetailsService;
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public WebSecurityConfig(CustomUserDetailsService userDetailsService, BCryptPasswordEncoder passwordEncoder) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

Any assistance would be greatly appreciated

philwebb commented 6 years ago

@erycoking Sorry, but we prefer to not use the issue tracker for questions. Please ask on stackoverflow.com using the spring-boot tag.

erycoking commented 6 years ago

just for the sake of those having the same problem as mine, the solution that worked for me is below. declare a global webFilter as follows

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsConfig implements Filter {

    public CorsConfig() {
    }

    @Override
    public void init(FilterConfig fc) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        System.out.println("doFilter");
        HttpServletResponse response = (HttpServletResponse) resp;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "PUT, POST, DELETE, OPTIONS, GET");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, resp);
        }
    }

    @Override
    public void destroy() {
    }
}

Here is my resource server

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**").authorizeRequests()
                .antMatchers(  "/", "/students", "/student", "/oauth/token", "/transaction/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new OAuth2AccessDeniedHandler());
    }
}

Happy coding. Hey @philwebb sorry for violating the rules. sometimes you have to help out your brothers

dryleaf commented 5 years ago

What's the up to date solution for this issue in 2019?

snicoll commented 5 years ago

@dryleaf as mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements. Please ask questions on StackOverflow.