问题
I have a user that has logged in through AD and now I want to get some of their information. Here's a sample test endpoint I am playing with:
@RequestMapping(value={"/secure/test"}, method=RequestMethod.GET)
public ResponseEntity<?> getSecureTest(HttpServletRequest request) {
String str = "Test Response";
request.getSession().setAttribute("testVar", "SessionVariable");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
if (!(authentication instanceof AnonymousAuthenticationToken)) {
String currentUserName = authentication.getName();
str = str + "\n -- " + currentUserName + "\n\n";
str = str + userDetails.getUsername(); // matches authentication.getName()
return new ResponseEntity<>(str, HttpStatus.OK);
} else {
str = str + "failed auth";
return new ResponseEntity<>(str, HttpStatus.UNAUTHORIZED);
}
}
I can get the authentication and from that, a UserDetails, but the implementation that comes out I believe is a LdapUserDetailsImpl
https://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/ldap/userdetails/LdapUserDetailsImpl.html
This doesn't appear to have any methods to like "getAttribute" or whatever. If I wanted to get one of the AD attributes such as "mail" or "telephoneNumber", how can I get it?
Edit:
So, just to try to extract the "title" attribute I extended the LdapUserDetailsImpl:
public class CustomUserDetails extends LdapUserDetailsImpl {
private String title;
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return this.title;
}
}
And I extended the LdapUserDetailsMapper:
public class CustomDetailsContextMapper extends LdapUserDetailsMapper {
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
LdapUserDetailsImpl ldapUserDetailsImpl = (LdapUserDetailsImpl) super.mapUserFromContext(ctx, username, authorities);
CustomUserDetails customUserDetails = new CustomUserDetails();
customUserDetails.setTitle(ctx.getStringAttribute("title"));
return customUserDetails;
}
}
In my controller, I try to get this object:
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
but this gives me a casting error... What am I missing?
WebSecurityConfigurerAdapter has this stuff in it:
@Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider());
authManagerBuilder.userDetailsService(userDetailsService());
}
@Bean
public AuthenticationManager authenticationManager() {
return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProviderES()));
}
@Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(ldapdomain, ldapurl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
return provider;
}
回答1:
You can implement your own user details mapper by extending springs ldap one.
package example.active.directory.authentication;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collection;
public class CustomUserMapper extends LdapUserDetailsMapper{
@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities){
UserDetails details = super.mapUserFromContext(ctx, username, authorities);
String[] changedValues = ctx.getStringAttributes("whenchanged");
/// Do something here, like map to your custom UserDetails object.
return details;
}
}
If you set a breakpoint in that method, you should be able to explore all the different attributes available to you in your debugger.
This is similar to another answer I gave: Update users informations during login against LDAP AD using Spring
回答2:
First set your provider by adding below in your SecurityConfiguration. If not set, defaults to a simple LdapUserDetailsMapper which doesn't have all attributes.
provider.setUserDetailsContextMapper(userDetailsContextMapper());
@Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(ldapdomain, ldapurl);
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setUserDetailsContextMapper(userDetailsContextMapper());
return provider;
}
@Bean
public UserDetailsContextMapper userDetailsContextMapper() {
return new CustomUserMapper();
}
Then create a custom mapper extending LdapUserDetailsMapper
public class CustomUserMapper extends LdapUserDetailsMapper{
@Override
public CustomUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities){
// set from userDetails
UserDetails details = super.mapUserFromContext(ctx, username, authorities);
// set directly from ctx
CustomUserDetails customUserDetails = new CustomUserDetails();
customUserDetails.setFirstName(ctx.getStringAttribute("givenName"));
customUserDetails.setLastName(ctx.getStringAttribute("sn"));
return customUserDetails;
}
}
来源:https://stackoverflow.com/questions/47417778/java-spring-get-attributes-from-active-directory-userdetails