3

I have two microservices, one is configured as OAuth2 server - A and another one which is configured as OAuth2 client - B. I would like to share my custom user between these two microservices. When the user authenticates himself with the A I create a custom implementation of UserDetails, I would like to protect some resources in B. So that I configured Resource server which is the same as A. I expected that I can share my custom implementation of UserDetails between A and B using Principal. I am able to get the custom user from the principal in A but in B the principal is only represented by String(username). How can I make the resource server to return custom implementation of the UserDetails and not just username?

source of A - server

Server configuration:

@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
@EnableWebSecurity
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Implementation of UserDetailsService which returns my CustomUser which implements UserDetails(just a dummy one for simplicity)

@Service
@Primary
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        GrantedAuthority authority = new Authority("USER");
        return new CustomUser(5L, "username", "{noop}password", Arrays.asList(authority));
    }
}

Configuration of OAuth2 server:

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

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

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
               .withClient("user")
               .secret("{noop}password")
               .authorizedGrantTypes("password", "refresh_token")
               .scopes("webapp");
    }
}

WebSecurityConfigurerAdapter:

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

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

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

This is how principal "should" be accessible to other services, through rest endpoint which return just Principal, here in service A it contains instance of CustomUser:

@RestController
@RequestMapping("/user")
public class UserRestController {

    @GetMapping("/auth")
    public Principal getPrincipal(Principal principal) {
        return principal;
    }
}

Client source of B - client

Application.properties - url of endpoint from A

server.port=8081
security.oauth2.resource.user-info-uri=http://localhost:8080/user/auth

Starter of B

@SpringBootApplication
@EnableResourceServer
@EnableWebSecurity
@EnableOAuth2Client
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

And finally the rest controller which I use to test whether the principal is string(username) or CustomUser. Unfortunatelly Principal always contains just a username and map of fields with values from custom user.

@RestController
@RequestMapping("/client")
public class ClientRestController {

    @GetMapping("/print")
    public void printId(Principal principal) {
        System.out.println(principal);
    }
}

Could you please help me to solve it? How can I pass Principal with my CustomUser?

Thanks for help:)

Community
  • 1
  • 1
pecrom
  • 31
  • 2
  • If your Authorization and Resource server are different from one another then this answer might help you https://stackoverflow.com/questions/51240197/spring-oauth-with-jwt-custom-userdetails-set-principal-inside-jwtaccesstokenco – silentsudo Nov 09 '19 at 13:52

1 Answers1

0

Well, it is not a good idea to return the Principal object (most probably it will be its implementation class UsernamePasswordAuthenticationToken). If you only want an endpoint to share custom user details, then preferable way would be to create a data transfer object that contains only the information that you'd like to expose.

Recommended way to get principal (authenticated user who's making a request) is from security context. More information on this is available here.

Vijay Nandwana
  • 2,476
  • 4
  • 25
  • 42