Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security Ouath2 : Extended UserDetails not returned by the Principal object

Last week I started on extending the UserDetails class to be able to support a custom field. The special thing about this field is that it gets filled with a value that depends an a request parameter. I managed to implement this correctly (so the question does not focus on that).

Now the thing is that after a successfull login the UserDetails object gets filled correctly (I was able to see this using a AuthenticationSuccessHandler) and client recieves a JWT token from the OAuth2 provider. The client then tries to fetch more details on the user by visiting the "/uaa/user" endpoint. This is set to return the Principal object. But after checking the contents of the Principal object I was supprised that the UserDetails object was missing. The method getPrincipal() only returned the username instead of the UserDetails object.

According to this question this is the result of a failed login. The AuthenticationToken (in this case a UsernamePasswordAuthenticationToken) gets rejected by the AuthenticationManager. I have no idea why it should do such a thing. The authentication with the default UserDetails object seems to work just fine. Can someone help me solve this problem?

Some details on the implemented classes (as mentioned above). Some code has been left out here for reasons.

CustomUserDetails

public class CustomUserDetails extends User {

  private final Integer custom;

  public CustomUserDetails (...default params..., Integer custom) {
    super(...default params...);
    this.custom = custom;
  }
}

CustomUserDetailsService

@Service
public class CustomUserDetailsService implements UserDetailsService {
  @Override
  public CustomUserDetails loadUserByUsername(String username) throw UsernameNotFoundException {
    return new CustomUserDetails(...default params..., 12345);
  }
}

Configuration

@Autowired
private CustomUserDetails userDetails;

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

User Endpoint

@RequestMapping(value = "/user", method = RequestMethod.GET)
@ResponseBody
public Principal getDetails(Principal user) {
  return user;
}

The Principal object returned here should have the UserDetails object inside of it and should return this to the client. But instead of that it only returns a String with the username when you call getPrincipal();

In the end I want the JSON returned by the User endpoint (which returns the Principle object) to contain the custom field I added to the UserDetails.

Thanks in advance.

like image 302
Robin Hermans Avatar asked Oct 12 '15 10:10

Robin Hermans


1 Answers

Generally, you need the annotation @AuthenticationPrincipal, but I will suggest you to build your own annotation, something like this:

/**
 * Our own {@link AuthenticationPrincipal} annotation as suggested by
 * http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#mvc-authentication-principal
 *
 */
@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {}

Then you can have this Principal in this way:

@RequestMapping(..)
public Principal test(@CurrentUser Principal principal){..}

BUT, IMHO you should have your own Impl of Principal, or rather extends the existing impl. something like this:

public MyPrincipal extends org.springframework.security.core.userdetails.User {..}

In this case you can return values whatever you want to.

like image 165
Jaiwo99 Avatar answered Oct 20 '22 17:10

Jaiwo99