Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring secure endpoint with only client credentials (Basic)

I have oauth2 authorization server with one custom endpoint (log out specific user manually as admin) I want this endpoint to be secured with rest client credentials (client id and secret as Basic encoded header value), similar to /oauth/check_token.

This endpoint can be called only from my resource server with specific scope.

  1. I need to check if the client is authenticated.
  2. I would like to be able to add @PreAuthorize("#oauth2.hasScope('TEST_SCOPE')")on the controller`s method.

I could not find any docs or way to use the Spring`s mechanism for client authentication check.

EDIT 1

I use java config not an xml one

like image 970
Daniel Donev Avatar asked Sep 25 '18 09:09

Daniel Donev


People also ask

How are credentials encoded in Spring Boot basic authentication?

The credentials will be encoded, and use the Authorization HTTP Header, in accordance with the specs of the Basic Authentication scheme. An example would look like this: Learn about using interceptors in your Spring application with the RestTemplate.

What is basicauthenticationentrypoint in Spring Security?

Configure authentication entry point with BasicAuthenticationEntryPoint : In case the Authentication fails [invalid/missing credentials], this entry point will get triggered. It is very important, because we don’t want [Spring Security default behavior] of redirecting to a login page on authentication failure [ We don’t have a login page].

How does spring authentication check for authentication authority?

We see that our class is a Spring service with a boolean method (as required by the access () chain call) that checks for two things: first if the user is authenticated (so if the user entered the correct credentials of username and password that the Authentication class expects) and if its authorities do NOT contain the "ROLE_ANONYMOUS" authority.

Do you have to write API endpoints for Spring Boot applications?

However, there is more to that. If you are working as a backend developer, a lot of times you have to write API endpoints that are ready to be consumed. Today, we will talk how to create a spring boot application that users have to authenticate against in order to access these API endpoints.


Video Answer


1 Answers

So I ended up with the following solution

Authentication Manager

public class ClientAuthenticationManager implements AuthenticationManager {

private ClientDetailsService clientDetailsService;
private PasswordEncoder passwordEncoder;

public HGClientAuthenticationManager(ClientDetailsService clientDetailsService, PasswordEncoder passwordEncoder) {
    Assert.notNull(clientDetailsService, "Given clientDetailsService must not be null!");
    Assert.notNull(passwordEncoder, "Given passwordEncoder must not be null!");
    this.clientDetailsService = clientDetailsService;
    this.passwordEncoder = passwordEncoder;
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    ClientDetails clientDetails = null;
    try {
        clientDetails = this.clientDetailsService.loadClientByClientId(authentication.getPrincipal().toString());
    } catch (ClientRegistrationException e) {
        throw new BadCredentialsException("Invalid client id or password");
    }
    if (!passwordEncoder.matches(authentication.getCredentials().toString(), clientDetails.getClientSecret())) {
        throw new BadCredentialsException("Invalid client id or password");
    }
    return new OAuth2Authentication(
            new OAuth2Request(null, clientDetails.getClientId(), clientDetails.getAuthorities(), true,
                    clientDetails.getScope(), clientDetails.getResourceIds(), null, null, null),
            null);
}
}

Filter declaration

    private BasicAuthenticationFilter basicAuthenticationFilter() {
    ClientDetailsUserDetailsService clientDetailsUserDetailsService = new ClientDetailsUserDetailsService(
            this.clientDetailsService);
    clientDetailsUserDetailsService.setPasswordEncoder(this.passwordEncoder);
    return new BasicAuthenticationFilter(
            new ClientAuthenticationManager(this.clientDetailsService, this.passwordEncoder));
}

Filter registration

httpSecurity.addFilterBefore(this.basicAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)

WARNING!!! This will prevent any other types of authentication (oauth2, etc.). ONLY Basic authentication is accepted and ONLY for registered clients.

like image 108
Daniel Donev Avatar answered Nov 15 '22 05:11

Daniel Donev