web-dev-qa-db-fra.com

Spring Boot: Oauth2: l'accès est refusé (l'utilisateur est anonyme); redirection au point d'entrée d'authentification

J'essaie d'utiliser Spring Boot oauth2 pour effectuer l'authentification et l'autorisation sans état. Cependant, j'ai du mal à le faire fonctionner.

Voici mon code:

@EnableAutoConfiguration
@ComponentScan
//@EnableEurekaClient
//@EnableZuulProxy
@Configuration
public class AuthServiceApp {

  public static void main(String[] args) {
    SpringApplication.run(AuthServiceApp.class, args);
  }
}

Config. D'autorisation:

@Configuration
@EnableAuthorizationServer
public class Oauth2ServerConfig extends AuthorizationServerConfigurerAdapter {

  @Autowired
  @Qualifier("authenticationManagerBean")
  private AuthenticationManager auth;

  @Autowired
  private DataSource dataSource;

  @Autowired
  private CustomUserDetailsService userDetailService;

  @Autowired
  private ClientDetailsService clientDetailsService;


  @Bean
  public JdbcTokenStore tokenStore() {
    return new JdbcTokenStore(dataSource);
  }

  @Bean
  protected AuthorizationCodeServices authorizationCodeServices() {
    return new JdbcAuthorizationCodeServices(dataSource);
  }

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

  @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    // @OFF
    endpoints
          .authorizationCodeServices(authorizationCodeServices())
          .authenticationManager(auth)
          .userDetailsService(userDetailService)
          .tokenStore(tokenStore());
    // @ON
  }


  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

    // @OFF
    clients.jdbc(dataSource)
           .withClient("client")
           .secret("secret")
           .authorizedGrantTypes("password","refresh_token", "client_credentials")
           .authorities("USER")
           .scopes("read", "write")
           .autoApprove(true)
           .accessTokenValiditySeconds(60)
           .refreshTokenValiditySeconds(300);
    // @ON
  }
}

Configuration du serveur de ressources:

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
class ResourceServerConfig extends ResourceServerConfigurerAdapter {


  @Autowired
  private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

  @Autowired
  private CustomLogoutSuccessHandler customLogoutSuccessHandler;


  @Override
  public void configure(HttpSecurity http) throws Exception {
    // @OFF
          http
              .sessionManagement()
              .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
              .and()
              .exceptionHandling()
              .authenticationEntryPoint(customAuthenticationEntryPoint)
              .and()
              .logout()
              .logoutUrl("/oauth/logout")
              .logoutSuccessHandler(customLogoutSuccessHandler)
              .and()
              .csrf()
//            .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
              .disable()
              .headers()
              .frameOptions().disable()
              .and()
              .authorizeRequests()
              .antMatchers("/identity/**").authenticated();
   // @ON
  }
}


@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Autowired
  private CustomUserDetailsService userDetailsService;

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

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

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // @OFF
    http
        .csrf()
        .disable()
        .authorizeRequests()
        .antMatchers("/login").permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin().permitAll();
   // @ON
  }
}

Manette:

@RestController
@RequestMapping("/")
public class AuthController {

  @PreAuthorize("#oauth2.hasScope('read')")
  @GetMapping("/user")
  public Principal getUser(Principal user) {
     return user;
  }
}

Je peux obtenir le jeton d'accès à l'aide de POSTMAN. J'utilise le même jeton d'accès dans l'en-tête pour obtenir les détails de l'utilisateur sous la forme http://localhost:8082/identity/user avant son expiration. Cependant, je reçois une réponse HTML de la page de connexion avec la log suivante sur la console:

2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 301C6EDD36372CF9C553FCFCD4AA47E3; Granted Authorities: ROLE_ANONYMOUS'
2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.security.web.FilterChainProxy        : /user at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.security.web.FilterChainProxy        : /user at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.security.web.FilterChainProxy        : /user at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/user'; against '/login'
2017-05-24 22:55:16.070 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /user; Attributes: [authenticated]
2017-05-24 22:55:16.071 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055c2bc: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 301C6EDD36372CF9C553FCFCD4AA47E3; Granted Authorities: ROLE_ANONYMOUS
2017-05-24 22:55:16.071 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@55b4f25d, returned: -1
2017-05-24 22:55:16.071 DEBUG 16899 --- [nio-8082-exec-9] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.Java:84) ~[spring-security-core-4.2.2.RELEASE.jar:4.2.2.RELEASE]

Mais il semble que j'ai été authentifié lors du premier appel pour obtenir le jeton d'accès à oauth/token:

2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@50c8f5e8: Principal: org.springframework.security.core.userdetails.User@af12f3cb: Username: client; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@21a2c: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 2F070B741A55BD1E47933621D9127780; Granted Authorities: USER
2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@61f8721f, returned: 1
2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2017-05-24 22:54:35.966 DEBUG 16899 --- [nio-8082-exec-6] o.s.security.web.FilterChainProxy        : /oauth/token reached end of additional filter chain; proceeding with original chain
2017-05-24 22:54:35.967 DEBUG 16899 --- [nio-8082-exec-6] .s.o.p.e.FrameworkEndpointHandlerMapping : Looking up handler method for path /oauth/token
2017-05-24 22:54:35.968 DEBUG 16899 --- [nio-8082-exec-6] .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]
2017-05-24 22:54:35.975 DEBUG 16899 --- [nio-8082-exec-6] .o.p.p.ResourceOwnerPasswordTokenGranter : Getting access token for: client
2017-05-24 22:54:35.975 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
Hibernate: select user0_.id as id1_1_, user0_.enabled as enabled2_1_, user0_.name as name3_1_, user0_.password as password4_1_, user0_.username as username5_1_ from user user0_ where user0_.username=?
Hibernate: select roles0_.user_id as user_id1_2_0_, roles0_.role_id as role_id2_2_0_, role1_.id as id1_0_1_, role1_.role as role2_0_1_ from user_role roles0_ inner join role role1_ on roles0_.role_id=role1_.id where roles0_.user_id=?
2017-05-24 22:54:36.125  INFO 16899 --- [nio-8082-exec-6] o.s.s.o.p.token.store.JdbcTokenStore     : Failed to find access token for token 180c2528-b712-4088-9cce-71e9cc7ccb94
2017-05-24 22:54:36.232 DEBUG 16899 --- [nio-8082-exec-6] o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
2017-05-24 22:54:36.232 DEBUG 16899 --- [nio-8082-exec-6] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

Peut-être que je configure quelque chose de mal. Qu'est-ce que j'oublie ici?

6
cosmos

J'ai eu un problème similaire et j'ai constaté que le OAuth2AuthenticationProcessingFilter n'était pas appelé par la chaîne de filtres et que, de ce fait, l'utilisateur n'était pas authentifié et donc traité comme anonyme.

J'utilise la version 1.5.3 de Spring-Boot et j'ai ajouté la ligne ci-dessous dans application.yml pour corriger la commande.

security.oauth2.resource.filter-order=3

Il doit y avoir une déclaration de journal présente qui montre que son invocation

DEBUG 34386 --- [nio-8082-exec-1] o.s.security.web.FilterChainProxy        : /foo at position 5 of 11 in additional filter chain; firing Filter: 'OAuth2AuthenticationProcessingFilter'

Référence - https://github.com/spring-projects/spring-security-oauth/issues/993

12
Rites

Je faisais face au même problème et j'ai réussi à le résoudre en désactivant explicitement une configuration automatique par ressort:

@EnableAutoConfiguration(exclude = [OAuth2AutoConfiguration::class,
   SecurityAutoConfiguration::class, SecurityFilterAutoConfiguration::class])
0
Michael Gloegl

Utiliser

.authorizedGrantTypes("password","refresh_token", "client_credentials")

vous devez ouvrir l'accès à

/auth/token

en configuration de sécurité de votre serveur d'autorisation

@Override
protected void configure(HttpSecurity http) throws Exception {
    code...
    http
        .antMatcher("/**")
        .authorizeRequests()
            .antMatchers("/oauth/token").permitAll()
        .anyRequest().authenticated()
    code...     
} 
0
ejazazeem