Spring-security-oauth: Combining ResourceServer with @EnableOAuth2Sso

Created on 27 Jan 2016  路  28Comments  路  Source: spring-projects/spring-security-oauth

What i want to achieve:

  1. Browse to protected resource and get redirected to authorization-server. After login the resource should be available.
  2. Access the same protected resource for example via CURL with an Authorization header:
    Authorization: bearer someTokenValue. If the token is correct the resource should be returned.

If i use the @EnableOauth2Sso-Annotation on a WebSecurityConfigurerAdapter the first goal is achieved.
For the second goal i had to do this:

@Override
public void configure(HttpSecurity http) throws Exception {
    http
        ...
        .addFilterAfter(oAuth2AuthenticationProcessingFilter(), AbstractPreAuthenticatedProcessingFilter.class);
}


private OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter() {

    OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter =
        new OAuth2AuthenticationProcessingFilter();
    oAuth2AuthenticationProcessingFilter.setAuthenticationManager(oauthAuthenticationManager());
    oAuth2AuthenticationProcessingFilter.setStateless(false);

    return oAuth2AuthenticationProcessingFilter;
}


private AuthenticationManager oauthAuthenticationManager() {

    OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();

    oauthAuthenticationManager.setResourceId(resourceId);
    oauthAuthenticationManager.setTokenServices(tokenServices);
    oauthAuthenticationManager.setClientDetailsService(null);

    return oauthAuthenticationManager;
}

Is this the way to go to achieve both goals? Or is there something much simpler which i just didn't see?

stackoverflow

Most helpful comment

I developed this configuration which is working perfectly fine with me supporting

  • Form based login / Authorization Code flow
  • Password grant type (For REST Endpoints involving user)
  • Client Credentials (For REST Endpoints)

`

@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
protected static class ResourceConfiguration extends WebSecurityConfigurerAdapter {

    @Value("${sso.url}")
    private String ssoUrl;

    @Autowired
    private  RedisConnectionFactory redisConnectionFactory;

    @Bean
    protected TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Bean
    @Primary
    protected ResourceServerTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);

        return defaultTokenServices;
    }


    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
        authenticationManager.setTokenServices(tokenServices());
        return authenticationManager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {      
        http.requestMatchers()
        .and().authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers(HttpMethod.GET, "/static/**").permitAll()
            .antMatchers(HttpMethod.GET, "/profile/**").permitAll()
            .antMatchers(HttpMethod.GET, "/services/**").permitAll()
            .anyRequest().authenticated()
        .and().logout()
                .invalidateHttpSession(true)
                .logoutSuccessUrl(ssoUrl+"/logout")
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .deleteCookies("JSESSIONID").invalidateHttpSession(true)
                .permitAll();
                }

}

@Configuration
@EnableResourceServer
@Order(1)
protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter {



    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("my-resource");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatcher(new OAuthRequestedMatcher())
            .authorizeRequests().anyRequest().fullyAuthenticated();

    }
}

private static class OAuthRequestedMatcher implements RequestMatcher {
    public boolean matches(HttpServletRequest request) {
        String auth = request.getHeader("Authorization");
        boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");
        boolean haveAccessToken = request.getParameter("access_token")!=null;
        return haveOauth2Token || haveAccessToken;
    }
}

`

All 28 comments

Same needs! Any news about possible simplest solution?

I'm interested or in need of this as well. What's the proper way, or is @Yannic92's approach the proper way to configure this?

I have exactly the same needs!

I have the same needs.

Another upvote for this issue

Another one

I have the same needs too

+1

+1

+1

+1

+1

+1

The above solution works perfectly, but when you add auto-wire OAuth2RestTemplate to support the refresh token, it no longer works, anyone with any suggestion?

+1

I have exactly the same needs too!

+1

+1. Does someone know a solution on how to add multiple filters, if you have separate tokenServices e.g. a Facebook and Google Login?

I developed this configuration which is working perfectly fine with me supporting

  • Form based login / Authorization Code flow
  • Password grant type (For REST Endpoints involving user)
  • Client Credentials (For REST Endpoints)

`

@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
protected static class ResourceConfiguration extends WebSecurityConfigurerAdapter {

    @Value("${sso.url}")
    private String ssoUrl;

    @Autowired
    private  RedisConnectionFactory redisConnectionFactory;

    @Bean
    protected TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }

    @Bean
    @Primary
    protected ResourceServerTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);

        return defaultTokenServices;
    }


    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
        authenticationManager.setTokenServices(tokenServices());
        return authenticationManager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {      
        http.requestMatchers()
        .and().authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers(HttpMethod.GET, "/static/**").permitAll()
            .antMatchers(HttpMethod.GET, "/profile/**").permitAll()
            .antMatchers(HttpMethod.GET, "/services/**").permitAll()
            .anyRequest().authenticated()
        .and().logout()
                .invalidateHttpSession(true)
                .logoutSuccessUrl(ssoUrl+"/logout")
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                .deleteCookies("JSESSIONID").invalidateHttpSession(true)
                .permitAll();
                }

}

@Configuration
@EnableResourceServer
@Order(1)
protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter {



    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("my-resource");
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.requestMatcher(new OAuthRequestedMatcher())
            .authorizeRequests().anyRequest().fullyAuthenticated();

    }
}

private static class OAuthRequestedMatcher implements RequestMatcher {
    public boolean matches(HttpServletRequest request) {
        String auth = request.getHeader("Authorization");
        boolean haveOauth2Token = (auth != null) && auth.startsWith("Bearer");
        boolean haveAccessToken = request.getParameter("access_token")!=null;
        return haveOauth2Token || haveAccessToken;
    }
}

`

+1

I've same need too.

+1

+1

@ejazazim Your variant is the only one that worked for me, thanks!

FYI, this is now supported on Spring Security 5
https://docs.spring.io/spring-security/site/docs/5.2.0.BUILD-SNAPSHOT/reference/htmlsingle/#spring-security-oauth2-core
by using a combination of .formLogin() and .oauth2ResourceServer() in your web security config.

+1锛孖 appreciate @ejazazim help.

Many thanks

+1

+1 to @ejazazim too. Very helpful

Closing this as questions are better suited on Stack Overflow. We prefer to use GitHub issues for bugs and enhancements.

Was this page helpful?
0 / 5 - 0 ratings