Как получить дополнительные атрибуты пользователя из LDAP в Spring Security?

В настоящее время я пытаюсь разработать приложение Spring Boot, целью которого будет управление записями пользователей в нашем каталоге LDAP.

Логин LDAP уже работает; так же как и поиск групп, членом которых является пользователь.

Кроме того, я хотел бы заполнить объект Spring Security Principal еще некоторыми атрибутами LDAP этого пользователя. Я прочитал несколько сообщений о SO, а также официальную документацию Spring, но просто не могу заставить это работать.

Вот мой текущий код: Класс AuthenticationConfiguration

@Configuration
class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {

    private String ldapUrl = "ldap://127.0.0.1:10389/dc=corp,dc=org";
    private String bindUser = "cn=spring,ou=users,dc=corp,dc=org";
    private String bindPW = "<password>";
    private String groupSearchBase = "ou=groups";
    private String groupSearchFilter = "(member={0})";
    private String userDnPattern = "uid={0},ou=users";
    private Log log = LogFactory.getLog(this.getClass());

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {

        DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapUrl);

        contextSource.setUserDn(bindUser);
        contextSource.setPassword(bindPW);
        contextSource.afterPropertiesSet();
        log.info(contextSource.getReadOnlyContext().getAttributes("uid=testuser,ou=users")); // returns all LDAP attributes from that user

        DefaultLdapAuthoritiesPopulator populator = new DefaultLdapAuthoritiesPopulator(contextSource, groupSearchBase);
        populator.setGroupSearchFilter(groupSearchFilter);
        populator.setSearchSubtree(true);
        populator.setIgnorePartialResultException(true);

        auth
        .ldapAuthentication()
        .ldapAuthoritiesPopulator(populator)
        .contextSource(contextSource)
        .userDetailsContextMapper(userDetailsContextMapper())
        .userDnPatterns(userDnPattern)
        ;
    }

    @Bean
    public UserDetailsContextMapper userDetailsContextMapper() {
        return new CustomUserDetailsContextMapper();
    }

}

Как видите, я использую метод userDetailsContextMapper() для возврата экземпляра моего CustomUserDetailsContextMapper:

@Configuration
public class CustomUserDetailsContextMapper extends LdapUserDetailsMapper implements UserDetailsContextMapper {

    private Log log = LogFactory.getLog(this.getClass());

    @Override
    public LdapUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {

        LdapUserDetailsImpl details = (LdapUserDetailsImpl) super.mapUserFromContext(ctx, username, authorities);
        log.info("DN from ctx: " + ctx.getDn()); // return correct DN
        log.info("Attributes size: " + ctx.getAttributes().size()); // always returns 0

        return new CustomUserDetails(details);
    }

    @Override
    public void mapUserToContext(UserDetails user, DirContextAdapter ctx) {
        // default
    }
}

Теперь, когда вы посмотрите на этот первый оператор журнала в AuthenticationConfiguration, Spring фактически выведет весь пользовательский объект на стандартный вывод, правильно показывая все атрибуты LDAP от пользователя: {displayname=displayName: Test User, givenname=givenName: Test, objectclass=objectClass: posixAccount, top [...]}

Однако операторы журнала в моем классе CustomUserDetailsContextMapper этого не делают. Хотя первый правильно отображает DN вошедшего в систему пользователя, второй просто отображает 0, т.е. ctx не содержит никаких атрибутов текущего пользователя.

Я также пытался запросить атрибуты напрямую через ctx.getAttribute("attribute"), ctx.getStringAttribute("attribute") или ctx.getObjectAttribute("attribute"), но безрезультатно.

Как получить доступ к атрибутам LDAP из метода mapUserFromContext?

У меня действительно нет идей, поэтому любая помощь будет принята с благодарностью :-)


person Alex    schedule 09.06.2016    source источник


Ответы (2)


Решил это. Проблема была не в коде приложения, а в конфигурации LDAP.

Поскольку я использовал BindAuthenticator по умолчанию, Spring Security попытался выполнить привязку к LDAP с пользователем, указанным в форме входа. К сожалению, все пользователи под ou=users имели только разрешение search в конфигурации LDAP. Изменение search на read (см. пункт 8.2.3 http://www.openldap.org/doc/admin24/access-control.html) решил эту проблему для меня.

Обратите внимание, что сам вход/связывание по-прежнему были успешными (поскольку разрешение auth является подмножеством search), но любое извлечение атрибутов не удалось, так как для этого требовалось разрешение read.

person Alex    schedule 10.06.2016

Заранее для примера @mpm:

Надеюсь, это будет полезно для кого-то. Вот мой декоратор для UserDetails

public class CustomUserDetails implements LdapUserDetails {
    private String iin;
    private String colvirId;
    private LdapUserDetails details;

    public CustomUserDetails(LdapUserDetails details) {
        this.details = details;
    }

    public String getIin() {
        return iin;
    }

    public void setIin(String iin) {
        this.iin = iin;
    }

    public String getColvirId() {
        return colvirId;
    }

    public void setColvirId(String colvirId) {
        this.colvirId = colvirId;
    }

    @Override
    public String getDn() {
        return details.getDn();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return details.getAuthorities();
    }

    @Override
    public String getPassword() {
        return details.getPassword();
    }

    @Override
    public String getUsername() {
        return details.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return details.isAccountNonExpired();
    }

    @Override
    public boolean isAccountNonLocked() {
        return details.isAccountNonLocked();
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return details.isCredentialsNonExpired();
    }

    @Override
    public boolean isEnabled() {
        return details.isEnabled();
    }
}
person qwert_ukg    schedule 19.07.2018