Java Spring从Active Directory UserDetails获取属性

时间:2017-11-21 16:17:46

标签: java spring spring-boot active-directory spring-security-ldap

我有一个用户已通过AD登录,现在我想获取他们的一些信息。这是我正在玩的示例测试终点:

@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);
    }
}

我可以获得身份验证,然后是UserDetails,但我认为实现的是LdapUserDetailsImpl

https://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/ldap/userdetails/LdapUserDetailsImpl.html

这似乎没有任何方法可以像&#34; getAttribute&#34;管他呢。如果我想获得其中一个AD属性,例如&#34; mail&#34;或者&#34; telephoneNumber&#34;,我怎么才能得到它?

编辑:

所以,只是为了尝试提取&#34;标题&#34;属性我扩展了LdapUserDetailsImpl:

public class CustomUserDetails extends LdapUserDetailsImpl {

    private String title;

    public void setTitle(String title) {
        this.title = title;
    }
    public String getTitle() {
        return this.title;
    }
}

我扩展了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;
    }
}

在我的控制器中,我尝试获取此对象:

CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();

但是这给了我一个投射错误......我错过了什么?

WebSecurityConfigurerAdapter中包含以下内容:

@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;
}

2 个答案:

答案 0 :(得分:2)

您可以通过扩展spring 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;        
    }
}

如果在该方法中设置断点,则应该能够在调试器中探索可用的所有不同属性。

这与我给出的另一个答案类似:Update users informations during login against LDAP AD using Spring

答案 1 :(得分:0)

首先通过在SecurityConfiguration中添加以下内容来设置您的提供程序。如果未设置,则默认为不具有所有属性的简单LdapUserDetailsMapper。

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();
}

然后创建一个自定义映射器,扩展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;
    }

}