Конечная точка информации о пользователе сервера авторизации Spring Oauth2 с несколькими grant_type не работает

#spring-security #spring-cloud #spring-security-oauth2 #spring-oauth2

#spring-безопасность #spring-cloud #spring-безопасность-oauth2 #spring-oauth2

Вопрос:

У меня есть сервер авторизации, который имеет встроенный менеджер аутентификации DB. Вот конфигурации.

AuthConfig.java

 @Configuration
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private DataSource dataSource;
    

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource).passwordEncoder(passwordEncoder).jdbc();
    }

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

    @Bean
    public TokenStore tokenStore() {
        return new InMemoryTokenStore();
    }
}
  

ResourceConfig.java

 @Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").permitAll().and().authorizeRequests().antMatchers("/userinfo").authenticated();
    }
}
  

SecurityConfig.java

 @Configuration
@EnableWebSecurity
//@Order(SecurityProperties.IGNORED_ORDER) // If added grant_type password does not work
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

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

    // @formatter:off
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/userinfo").authenticated().and().authorizeRequests()
                .antMatchers("/login", "/oauth/token", "/oauth/**").permitAll().and().formLogin().and().csrf().disable()
                .cors().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
                .usersByUsernameQuery("select username,password,enabled from TBL_USERS where username = ?")
                .authoritiesByUsernameQuery(
                        "select username, role as authority from TBL_USER_ROLES where username = ?");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(4);
    }
}
  

UserInfo.java

 @RestController
public class UserInfo {

    @GetMapping(value="/userinfo")
    public Map<String, Object> user(@AuthenticationPrincipal Principal principal) {
        if (principal != null) {
           return Map.of("name", principal.getName(), "authorities", SecurityContextHolder.getContext().getAuthentication().getAuthorities());
        }
        return null;
    }
}
  

Хотя приведенный выше фрагмент кода работает для grant_type=»password» и другого сервера ресурсов, способного извлекать userinfo для проверки клиента. Однако, когда я использую grant_type="implicit" сервер авторизации, который не может перенаправить на страницу входа, возникает ошибка аутентификации, трассировка стека добавлена ниже.

 2019-03-11 23:30:16.442 DEBUG 16401 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@a265b6db: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@380f4: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 588FF6DC19A9313BFD6DA9E05BE589DC; Granted Authorities: ROLE_ANONYMOUS
2019-03-11 23:30:16.443 DEBUG 16401 --- [nio-8080-exec-4] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@7f86e65e, returned: 1
2019-03-11 23:30:16.443 DEBUG 16401 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
2019-03-11 23:30:16.443 DEBUG 16401 --- [nio-8080-exec-4] o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
2019-03-11 23:30:16.443 DEBUG 16401 --- [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : /oauth/authorize?response_type=tokenamp;state=amp;client_id=client_2amp;scope=amp;redirect_uri=http:%2F/localhost:8182/resource2 reached end of additional filter chain; proceeding with original chain
2019-03-11 23:30:16.444 DEBUG 16401 --- [nio-8080-exec-4] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped to public org.springframework.web.servlet.ModelAndView org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(java.util.Map<java.lang.String, java.lang.Object>,java.util.Map<java.lang.String, java.lang.String>,org.springframework.web.bind.support.SessionStatus,java.security.Principal)
2019-03-11 23:30:16.449 DEBUG 16401 --- [nio-8080-exec-4] o.s.s.w.a.ExceptionTranslationFilter     : Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.InsufficientAuthenticationException: User must be authenticated with Spring Security before authorization can be completed.
    at org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint.authorize(AuthorizationEndpoint.java:143) ~[spring-security-oauth2-2.3.4.RELEASE.jar:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.16.jar:9.0.16]
  

Некоторые из альтернатив, которые я пробовал, это удалить класс ResourceConfig, в этом случае основной объект остается нулевым (вероятно, потому, что не зарегистрирован фильтр для извлечения токена), и другой подход, который я использовал, заключается в том, что в SecurityConfig добавляется наивысший порядок, в этом случае, хотя неявная авторизация работает, авторизация паролем не работает

Как включить конечную точку userInfo со всеми grant_types?

Ответ №1:

Наконец-то исправлено после долгих усилий, это больше связано с конфигурацией безопасности в SecurityConfig.java файле.

 protected void configure(HttpSecurity http) throws Exception {
        http.requestMatchers().antMatchers("/login", "/oauth/authorize").and().authorizeRequests().anyRequest()
                .authenticated().and().formLogin().permitAll().and().csrf().disable().cors().disable();
    }
  

Здесь приведен полный пример

Комментарии:

1. Я могу представить, как трудно справиться с этой цепочкой. Это безумие : (