Spring Security OAuth - Full authentication is required to access this resource

51,172

Solution 1

I think I figured out what the problem was.

I went through the following example available on github where form based authentication mechanism was used (which is what I was looking for).

https://github.com/spring-guides/tut-spring-security-and-angular-js/

The exact code is working fine if I use a non HTML page as my login page. For example, JSP or FTL. The example uses Freemarker. Everything is working fine with my settings if I use ftl pages. But the same are not working in case of .html pages.

Solution 2

You need to make the /login endpoints publicly available (not authorized), users need to be able to login without being already logged in.

The /oauth endpoints must be secured.

Try the following

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/login.html", "/logout.do").permitAll()
            .antMatchers("/**").authenticated()
        .and()
        .formLogin()
            .loginProcessingUrl("/login")
            .loginPage("/login.html");
 }

I have a spring-security-oauth example project on github, you can check it out here https://github.com/FrontierPsychiatrist/spring-oauth-example/.

Share:
51,172
Pavan Andhukuri
Author by

Pavan Andhukuri

Architect. BPM & ESB delivery professional at Dark Horse Digital Solutions Pvt Ltd from 2009.

Updated on February 11, 2020

Comments

  • Pavan Andhukuri
    Pavan Andhukuri about 4 years

    Following is my Authorization server configuration:

    import org.springframework.context.annotation.Configuration;
    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.configurers.AuthorizationServerSecurityConfigurer;
    
    @Configuration
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory().withClient("acme").secret("acmesecret")
                    .authorizedGrantTypes("authorization_code", "refresh_token", "password").scopes("openid")
                    .autoApprove(true);
        }
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
        }
    
    }
    

    And the Web security configuration:

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.annotation.Order;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Configuration
    @Order(-20) // Very important
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private 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.html").permitAll().and().requestMatchers()
                    .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access").and().authorizeRequests()
                    .anyRequest().authenticated();
    
        }
    }
    

    Now, from the client application, when I try to access a secure resource, it redirects to the authorization server but I get the following error:

    <oauth>
    <error_description>
    Full authentication is required to access this resource
    </error_description>
    <error>unauthorized</error>
    </oauth>
    

    The same setup is working well in case of basic authentication. I am facing problems when I switch to form login.

    Update

    The following web security setting worked.

    http.formLogin().loginPage("/login.html").loginProcessingUrl("/login").permitAll().and().authorizeRequests()
                    .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access","/oauth/token").permitAll().anyRequest()
                    .authenticated().and().csrf().disable();
    

    Now, I am able to see the login page and I am able to login as well, but post login, the client is not able to get an oauth token.

    This application has no explicit mapping for /error, so you are seeing this as a fallback.
    
    Mon Jul 11 17:39:46 IST 2016
    There was an unexpected error (type=Unauthorized, status=401).
    Authentication Failed: Could not obtain access token
    

    I am able to see the following server log

    2016-07-11 17:39:46.119 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/css/**'
    2016-07-11 17:39:46.119 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/js/**'
    2016-07-11 17:39:46.119 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/images/**'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/**/favicon.ico'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/error'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] w.c.HttpSessionSecurityContextRepository : No HttpSession currently exists
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] 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@13bb1f26
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/logout'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/login'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS'
    2016-07-11 17:39:46.120 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/login'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/oauth/authorize'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/oauth/confirm_access'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/oauth/token'
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [permitAll]
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@6780c4c7, returned: 1
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
    2016-07-11 17:39:46.121 DEBUG 12502 --- [nio-9999-exec-2] o.s.security.web.FilterChainProxy        : /oauth/token reached end of additional filter chain; proceeding with original chain
    2016-07-11 17:39:46.122 DEBUG 12502 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/token
    2016-07-11 17:39:46.122 DEBUG 12502 --- [nio-9999-exec-2] .s.o.p.e.FrameworkEndpointHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException]
    2016-07-11 17:39:46.123  INFO 12502 --- [nio-9999-exec-2] o.s.s.o.provider.endpoint.TokenEndpoint  : Handling error: InsufficientAuthenticationException, There is no client authentication. Try adding an appropriate authentication filter.
    2016-07-11 17:39:46.125 DEBUG 12502 --- [nio-9999-exec-2] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
    2016-07-11 17:39:46.126 DEBUG 12502 --- [nio-9999-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
    2016-07-11 17:39:46.126 DEBUG 12502 --- [nio-9999-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
    

    Update 2

    Following is my client configuration.

    security:
      oauth2:
        client:
          accessTokenUri: http://localhost:9999/uaa/oauth/token
          userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
          clientId: acme
          clientSecret: acmesecret
        resource:
          userInfoUri: http://localhost:9999/uaa/user
    logging:
      level:
        org.springframework.security: DEBUG
    

    Update 3

    The code is available in the following repo

    https://github.com/pavan496/insol-test

  • Pavan Andhukuri
    Pavan Andhukuri almost 8 years
    I tried this. I am receiving an error stating "An OAuth 2 access token must be obtained or an exception thrown." I think the client application is trying to fire "/oauth/token" request after the /authorize request. And that is not accessible. I looked at your repo. This is not the case in it. Your approach seems to be a little different. I have shared my code in the repo mentioned in the question. Can you please take a look at it. It shouldn't be very hard to setup. Thank you.
  • funder7
    funder7 about 3 years
    Maybe the FTL template adds the CSRF token automatically, while in the html page, you have to add it manually. Just guessing!