42

I've been trying to implement a OAuth2 authentication server using the guides by Dave Syer with some inspiration from JHipster. But I can't figure out how it all works together.

It looks like the security setup using the WebSecurityConfigurerAdapter is overwritten when I use ResourceServerConfigurerAdapter.

@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter {

    private TokenExtractor tokenExtractor = new BearerTokenExtractor();

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .addFilterAfter(contextClearer(), AbstractPreAuthenticatedProcessingFilter.class)
                .authorizeRequests()
                .anyRequest().authenticated().and().httpBasic();
    }

    private OncePerRequestFilter contextClearer() {
        return new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                if (tokenExtractor.extract(request) == null) {
                    SecurityContextHolder.clearContext();
                }
                filterChain.doFilter(request, response);
            }
        };
    }

@Component
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    private final AuthenticationManager authenticationManager;

    @Autowired
    public CustomWebSecurityConfigurerAdapter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .parentAuthenticationManager(authenticationManager);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .formLogin()
                    .loginPage("/login").permitAll()
                .and()
                    .authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .and()
                    .requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
                .and()
                    .authorizeRequests().anyRequest().authenticated();
    }
}

This is code taken from a few different examples, so they might not mix that well. But I can't find a good documentation/example list for OAuth2 (unlike Spring Boot which has a awesome documentation), so I'm having problems understanding how thye all fit together. If I don't add the loginForm to the ResourceServerConfigurerAdapter, it will just give me unauthorized. But I defined it in the WebSecurityConfigurererAdapter as permitAll().

This is the AuthorizationServerConfigurerAdapter:

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("acme")
                .secret("acmesecret")
                .authorizedGrantTypes("authorization_code", "refresh_token",
                        "password").scopes("openid");
    }

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

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

Anything I'm doing wrong? Do I have to setup all the security within the ResourceServerConfigurerAdapter? Do I even need the WebSecurityConfigurerAdapter anymore?

If anyone know any guides, tutorials, blogs or anything alike that might help me wrap my head around how this works, that would be greatly appreciated.

Kind regards, Kenneth.

LG87
  • 695
  • 1
  • 10
  • 20
  • Your `OAuth2ResourceConfig` is redundant as far as I can see. Just saying. – Dave Syer Feb 19 '15 at 10:39
  • What are the symptoms (what paths are you hitting and what do you see)? Using curl (-v to see the headers) and DEBUG logging for Spring Security should tell you everything you need to know. – Dave Syer Feb 19 '15 at 10:44
  • The symptomes was that it basically ignored the WebSecurityConfigurerAdapter. But after reading you explanation below, I get a bit more how it works. – LG87 Feb 22 '15 at 12:52
  • I do not get your CustomWebSecurityConfigurerAdapter configure to get me to a login form, I have 404. How did you test it? – Dimitri Kopriwa Sep 21 '16 at 06:19

1 Answers1

48

You need a WebSecurityConfigurerAdapter to secure the /authorize endpoint and to provide a way for users to authenticate. A Spring Boot application would do that for you (by adding its own WebSecurityConfigurerAdapter with HTTP basic auth). It creates a filter chain with order=0 by default, and protects all resources unless you provide a request matcher. The @EnableResourceServer does something similar, but the filter chain it adds is at order=3 by default. WebSecurityConfigurerAdapter has an @Order(100) annotation. So first the ResourceServer will be checked (authentication) and then your checks in your enxtension of WebSecurityConfigureAdapter will be checked.

Your configuration looks sane (the login chain takes precedence, but only matches a small set of requests).

Robert
  • 1,579
  • 1
  • 21
  • 36
Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • 4
    I had to make my WebSecurityConfigurerAdapter order=2 to get it to work. – Robin Elvin Jul 16 '15 at 11:50
  • 1
    Do you specify the order with the Order annotation or where do you specify this? I have the same issue and annotating the configuration with Order doesn't have any effect, ResourceServerConfigurerAdapter is the only class being used and WebSecurityConfigurerAdapter is getting ignored completely. – Cenobyte321 Dec 05 '15 at 01:24
  • 2
    @Cenobyte321 `implements Ordered` or `@Order(1)` or `@Order(2)` – robinhowlett Feb 05 '16 at 02:27
  • 1
    @DaveSyer, is it possible to use two layer of security (basic+bearer) on top of each over ? – Dimitri Kopriwa Mar 20 '17 at 15:27
  • Yes. Maybe read this: https://spring.io/guides/topicals/spring-security-architecture/. – Dave Syer Mar 21 '17 at 15:38
  • @Lg87 Can you have your credentials in properties file rather than the java source code itself? – JayC Mar 28 '17 at 15:07
  • Is WebSecurityConfigurerAdapter default annotated by @Order(100) ? – meobeo173 Sep 19 '17 at 06:41
  • @DaveSyer how do you know the defaults for those ResourceServerConfigurer `@order` in both `WebSecurityConfigurerAdapter` and `ResourceServerConfigurerAdapter`? I looked into those classes but I only see `@Order(value = 100)` in WebSecurityConfigurerAdapter but nothing in ResourceServerConfigurerAdapter – kavrosis Mar 06 '18 at 00:25
  • For RSCA you need to look at the WSCA that it creates for you. IIRC the default is 3, but Spring Boot modifies it (and has a config property for it). – Dave Syer Mar 06 '18 at 06:53
  • Just a small addition I stumbled upon: `org.springframework.core.annotation.Order`: "Lower values have higher priority". So that means `ResourceServerConfiguration(order = 3)` will be used BEFORE `WebSecurityConfigurarerAdapter @Order(100)` Which makes sense: First check authentication, then check defaults – Robert Oct 24 '18 at 08:11
  • @DaveSyer can you pls look into this issue https://stackoverflow.com/questions/53537133/unable-to-access-resources-with-access-token-spring-boot-oauth2 – vjnan369 Nov 29 '18 at 14:10