Is possible ask for an acces token oauth2 just with refresh token in spring security? without basic authentication?

前端 未结 1 712
后悔当初
后悔当初 2021-01-25 04:14

I would like to know if in spring oauth2 is possible get a new pair tokens (access token and refresh token) just using another refresh token, without the basic authentication (w

相关标签:
1条回答
  • 2021-01-25 05:06

    The short answer is no. The class used to manage the Spring Oauth 2 endpoints is the following one:

    @FrameworkEndpoint
    public class TokenEndpoint extends AbstractEndpoint
    

    Both requests, I mean, get access token and refresh one use the same endpoint with different parameters. And the method to manage those ones is:

    @RequestMapping(
      value = {"/oauth/token"},
      method = {RequestMethod.POST}
    )
    public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, @RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
      if (!(principal instanceof Authentication)) {
        throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
      } else {
        String clientId = this.getClientId(principal);
        ... 
    

    As you can see, a Principal object is required (in this case provided by the Basic Authentication).

    Even, if you configure the security of your project to permit that url without checking authentication, you will achieve to "enter" in above method but you will receive an InsufficientAuthenticationException because no Authentication instance has been provided.


    Why custom authentication will not work

    1. Create a custom AuthenticationProvider will not work because the method postAccessToken is invoked before. So you will receive an InsufficientAuthenticationException.

    2. Create a OncePerRequestFilter and configure it to execute before process the current request:

        @Override
        protected void configure(HttpSecurity http) throws Exception {
          http...
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(myCustomFilter, UsernamePasswordAuthenticationFilter.class);
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
          web.ignoring()
                .antMatchers(POST, "/accounts/oauth/**");
        }
    

    with a code "similar to":

    @Component
    public class CustomAuthenticationFilter extends OncePerRequestFilter {
    
      @Override
      protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        ...
        SecurityContextHolder.getContext().setAuthentication(
                new UsernamePasswordAuthenticationToken("existingUser",
                        "passwordOfExistingUser",
                        Collections.emptyList()));
        ...
        filterChain.doFilter(request, response);
    }
    

    The problem with this approach is the principal in TokenEndpoint comes from the HttpServletRequest not from Spring context, as you can see debugging BasicAuthenticationFilter class.

    In your custom filter you can try, using reflection, set a value in userPrincipal property but, as you can verify, request has several "internal request properties" and that could be a "too tricky option".


    In summary, Oauth standard needs user/pass to access to the resources, if you want to workaround in almost of provided endpoints maybe that project is not what you are looking for.


    Workaround to include your own object in Spring Principal

    I do not recommend that but if you still want to go ahead with this approach, there is a way to include your own value inside the principal parameter received by TokenEndpoint class.

    It is important to take into account BasicAuthorizationFilter will be still executed, however you will be able to override the Spring principal object by your own one.

    For this, we can reuse the previous CustomAuthenticationFilter but now your have to include the filters you need, I mean, allowed urls, parameters, etc You are going to "open the doors", so be careful about what you allow and not.

    The difference in this case is, instead of add the configuration in our class that extends WebSecurityConfigurerAdapter we are going to do it in:

    @Configuration
    @EnableAuthorizationServer
    public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    
      @Autowired
      private CustomAuthenticationFilter customAuthenticationFilter;
      ...
    
      @Override
      public void configure(AuthorizationServerSecurityConfigurer security) {
        security.checkTokenAccess("isAuthenticated()");
        security.addTokenEndpointAuthenticationFilter(customAuthenticationFilter);
      }
      ...
    
    0 讨论(0)
提交回复
热议问题