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?
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:)