2

I have tried to replicate https://spring.io/guides/tutorials/spring-boot-oauth2/#_social_login_manual but for only GitHub.

The issue is that I get redirected to GitHub, gets authenticated but then nothing happens, it does not actually retrieve the token with the response code etc. I have searched on numerous threads. I have the same issue as: Unable to expose endpoint in Spring Boot to receive authorization code from Google

I could try https://dzone.com/articles/spring-boot-oauth2-getting-the-authorization-code but would like Spring to handle as much security stuff as possible not manually make the rest call.

This goes into some detail about modifying filter chain: Spring oauth2 dont redirect to original url

Spring provides OAuth2LoginAuthenticationFilter and OAuth2AuthorizationRequestRedirectFilter but do I have to use implement that?

2019-08-01 04:36:09.473 DEBUG 13884 --- [nio-8080-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request '/login/github' matched by universal pattern '/**'
2019-08-01 04:36:09.474 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2019-08-01 04:36:09.476 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2019-08-01 04:36:09.477 DEBUG 13884 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
2019-08-01 04:36:09.477 DEBUG 13884 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
2019-08-01 04:36:09.479 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2019-08-01 04:36:09.480 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2019-08-01 04:36:09.488 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2019-08-01 04:36:09.489 DEBUG 13884 --- [nio-8080-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/github' doesn't match 'POST /logout
2019-08-01 04:36:09.490 DEBUG 13884 --- [nio-8080-exec-9] o.s.security.web.FilterChainProxy        : /login/github at position 6 of 12 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
2019-08-01 04:36:09.491 DEBUG 13884 --- [nio-8080-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/github'; against '/login/github'
2019-08-01 04:36:09.491 DEBUG 13884 --- [nio-8080-exec-9] uth2ClientAuthenticationProcessingFilter : Request is to process authentication
2019-08-01 04:36:14.533 DEBUG 13884 --- [nio-8080-exec-9] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@422e37e6
2019-08-01 04:36:14.534 DEBUG 13884 --- [nio-8080-exec-9] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2019-08-01 04:36:14.534 DEBUG 13884 --- [nio-8080-exec-9] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-08-01 04:36:15.238 DEBUG 13884 --- [nio-8080-exec-9] o.s.s.web.DefaultRedirectStrategy        : Redirecting to 'https://github.com/login/oauth/authorize?client_id=SOMETHING&redirect_uri=http://localhost:8080/login/oauth2/code/github&response_type=code&state=bT8lSK'
2019-08-01 04:36:15.542 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request '/login/oauth2/code/github' matched by universal pattern '/**'
2019-08-01 04:36:15.542 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2019-08-01 04:36:15.542 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2019-08-01 04:36:15.542 DEBUG 13884 --- [io-8080-exec-10] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2019-08-01 04:36:15.543 DEBUG 13884 --- [io-8080-exec-10] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@250f33e4. A new one will be created.
2019-08-01 04:36:15.543 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2019-08-01 04:36:15.543 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
2019-08-01 04:36:15.545 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
2019-08-01 04:36:15.546 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/oauth2/code/github' doesn't match 'POST /logout
2019-08-01 04:36:15.546 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 6 of 12 in additional filter chain; firing Filter: 'OAuth2ClientAuthenticationProcessingFilter'
2019-08-01 04:36:15.546 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/github'; against '/login/github'
2019-08-01 04:36:15.546 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2019-08-01 04:36:15.547 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2019-08-01 04:36:15.550 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2019-08-01 04:36:15.554 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@bc4979c4: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 9ABF40E66AE6EDF4FA955A1EC1E728AA; Granted Authorities: ROLE_ANONYMOUS'
2019-08-01 04:36:15.555 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2019-08-01 04:36:15.555 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2019-08-01 04:36:15.555 DEBUG 13884 --- [io-8080-exec-10] o.s.security.web.FilterChainProxy        : /login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2019-08-01 04:36:15.557 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/oauth2/code/github' doesn't match 'POST /logout
2019-08-01 04:36:15.557 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/github'; against '/'
2019-08-01 04:36:15.557 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/github'; against '/login**'
2019-08-01 04:36:15.558 DEBUG 13884 --- [io-8080-exec-10] o.s.s.w.u.matcher.AntPathR

I tried to replicate the tutorial exactly and did some digging around but have not been able to solve the problem.

@EnableOAuth2Client
public class SocialApplication extends WebSecurityConfigurerAdapter {
    @Bean
    public FilterRegistrationBean<OAuth2ClientContextFilter> oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
        FilterRegistrationBean<OAuth2ClientContextFilter> registration = new FilterRegistrationBean<OAuth2ClientContextFilter>();
        registration.setFilter(filter);
        registration.setOrder(-100);
        return registration;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**", "/error**").permitAll().anyRequest()
                .authenticated().and().exceptionHandling()
                .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout()
                .logoutSuccessUrl("/").permitAll().and().csrf()
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
                .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
        // @formatter:on
    }

    private Filter ssoFilter() {
        OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter(
                "/login/github");
        OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(facebook(), oauth2ClientContext);
        facebookFilter.setRestTemplate(facebookTemplate);
        UserInfoTokenServices tokenServices = new UserInfoTokenServices(facebookResource().getUserInfoUri(),
                facebook().getClientId());
        facebook().setUseCurrentUri(false);
        facebook().setPreEstablishedRedirectUri("http://localhost:8080/login/oauth2/code/github");
        tokenServices.setRestTemplate(facebookTemplate);
        facebookFilter.setTokenServices(tokenServices);
        return facebookFilter;
    }

The problem is

org.springframework.security.access.AccessDeniedException: Access is denied

Pool
  • 11,999
  • 14
  • 68
  • 78
akohli96
  • 21
  • 2
  • ![browser image](https://imgur.com/a/2lldrWS) – akohli96 Aug 01 '19 at 09:49
  • I found this useful https://www.tutorialspoint.com/spring_boot/spring_boot_google_oauth2_sign_in.htm but used GitHub rather than google. Like you, I took the spring guide but used GitHub rather than Facebook. What is the callback url in your GitHub oauth app? I also just took the spring guide to logout and no further, did not go for the manual sections. I still get some strange behaviour but hopefully someone will answer my own questions on stackoverflow! – John Aug 02 '19 at 06:04

1 Answers1

2

Based on debug logs it seems that OAuth2LoginAuthenticationFilter is missing in security filter chain, client receives code from gihub authorization server which should be exchanged for token.

This is the request received by client app from authorization server:

/login/oauth2/code/github?code=d899209d67e0105486d8&state=bT8lSK

Which should be intercepted by OAuth2LoginAuthenticationFilter with default filter processing uri: "/login/oauth2/code/*"- this is what you are missing.

Your question:

Spring provides OAuth2LoginAuthenticationFilter and OAuth2AuthorizationRequestRedirectFilter but do I have to use implement that?

Spring security filter chain is not configured to include above mentioned filters by default, so we can provide HttpSecurity.oauth2Login(). For Example:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.
        .
        .oauth2Login()
        .
        .
        .clientRegistrationRepository(clientRegistrationRepository())
        .authorizedClientService(oAuth2AuthorizedClientService());
 }
  @Bean
  public ClientRegistrationRepository clientRegistrationRepository() {
    ClientRegistration github = 
     CommonOAuth2Provider.GITHUB.getBuilder("github")
            .clientId("ClientId")
            .clientSecret("ClientSecret")
            .redirectUriTemplate("http://localhost:PORT/contextpath/login/oauth2/code/")
            .scope("email","profile")
            .build();

    //inmemory is temporary
    List<ClientRegistration> clientRegistrationList = new ArrayList<>();
    clientRegistrationList.add(github);
    return new InMemoryClientRegistrationRepository(clientRegistrationList);
}
@Bean
public OAuth2AuthorizedClientService oAuth2AuthorizedClientService() {
    return new 
   InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository());
}

which will configure OAuth2LoginAuthenticationFilter and OAuth2AuthorizationRequestRedirectFilter for more information see https://docs.spring.io/spring-security/site/docs/5.0.7.RELEASE/reference/html/oauth2login-advanced.html

Alternative to http.oauth2Login() for adding those 2 filters is to manually configure and add them, which is a little bit not elegant. For example:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    auth.authenticationProvider(oAuth2LoginAuthenticationProvider());
}

@Bean
public DefaultAuthorizationCodeTokenResponseClient defaultAuthorizationCodeTokenResponseClient(){
    return new DefaultAuthorizationCodeTokenResponseClient();
}

@Bean
public DefaultOAuth2UserService defaultOAuth2UserService(){
    return new DefaultOAuth2UserService();
}

@Bean
public OAuth2LoginAuthenticationProvider oAuth2LoginAuthenticationProvider(){
    return new OAuth2LoginAuthenticationProvider(defaultAuthorizationCodeTokenResponseClient(),defaultOAuth2UserService());
}

@Bean
public OAuth2LoginAuthenticationFilter oAuth2LoginAuthenticationFilter() throws Exception {
    OAuth2LoginAuthenticationFilter oAuth2LoginAuthenticationFilter =
     new OAuth2LoginAuthenticationFilter(clientRegistrationRepository(),oAuth2AuthorizedClientService());
    oAuth2LoginAuthenticationFilter.setAuthenticationManager(super.authenticationManagerBean());

    return oAuth2LoginAuthenticationFilter;
}
@Override
public void configure(HttpSecurity http) throws Exception {
    http
            .
            .
            .addFilterBefore(oAuth2LoginAuthenticationFilter(), RequestCacheAwareFilter.class)
           .addFilterBefore(oAuth2AuthorizationRequestRedirectFilter(),OAuth2LoginAuthenticationFilter.class)
             .
             .

}
S.Step
  • 441
  • 3
  • 8
  • Hello, I configured the redirect uri to be the same as the original uri that triggers the oauthprocessing ie /login/oauth2/code/github and it worked. Is there anything wrong with the approach? – akohli96 Aug 14 '19 at 03:46