Spring LDAP возвращает тот же и неправильный objectSid

В моем веб-приложении Spring я не могу получить правильный objectId от текущего пользователя, вошедшего в систему с учетной записью Active Directory. Кажется, что все атрибуты имеют правильное значение, но значение objectId всегда установлено на S-1-5-21-1723711471-3183472479-4012130053-3220159935, и я не знаю, откуда оно взялось.

WebSecurityConfig

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(activeDirectoryLdapAuthenticationProvider());
    }

    private ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        ActiveDirectoryLdapAuthenticationProvider provider =
                new ActiveDirectoryLdapAuthenticationProvider(LdapConfig.AD_DOMAIN, LdapConfig.AD_SERVER);
        provider.setUserDetailsContextMapper(new LdapUserDetailsContextMapper());
        return provider;
    }
}

LdapUserDetailsContextMapper

@Slf4j
public class LdapUserDetailsContextMapper implements UserDetailsContextMapper {
    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> collection) {
        log.info("username: " + username); //username is correct
        log.info("DN from ctx: " + ctx.getDn()); // returns correct DN
        byte[] byteSid = ctx.getStringAttribute("objectSid").getBytes();
        String sid = LdapUtils.convertBinarySidToString(byteSid);
        log.info("SID: " + sid); // S-1-5-21-1723711471-3183472479-4012130053-3220159935 everytime

        return new User(username, "notUsed", true, true, true, true,
                AuthorityUtils.createAuthorityList("ROLE_USER"));
    }

    @Override
    public void mapUserToContext(UserDetails userDetails, DirContextAdapter dirContextAdapter) {

    }
}

Как получить правильный SID из Active Directory?

Это одинаково для всех пользователей?

raiyan 28.05.2018 14:01

Да, именно так, и он не соответствует ни одному добавленному мной пользователю (я не искал весь каталог по этому SID).

kojot 28.05.2018 14:05

Последний блок символов должен быть разным для разных пользователей. Если нет, сравните поток байтов sid двух пользователей и посмотрите, совпадает ли он. Сид будет уникальным.

raiyan 28.05.2018 14:12
ctx.getDn() - это DN учетной записи пользователя, для которой требуется SID?
Gabriel Luci 28.05.2018 14:20

@GabrielLuci да :)

kojot 28.05.2018 14:23
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
5
1 345
2

Ответы 2

Думаю, ответ здесь: http://forum.spring.io/forum/spring-projects/data/ldap/66894-objectsid-and-ldaptemplate

Во втором последнем посте он описывает ту же проблему, что и у вас. В последнем посте он описывает исправление, которое должно добавить это в файл конфигурации Bean:

<bean id = "contextSource" class = "org.springframework.ldap.core.support.LdapContextSource">
    <property name = "url" value = "ldap://ldapserver.domain.com:389" />
    <property name = "base" value = "dc=domain,dc=com" />
    <property name = "userDn" value = "cn=binduser,cn=Users,dc=domain,dc=com" />
    <property name = "password" value = "bindpwd"/>
    <property name = "baseEnvironmentProperties">
        <map>
        <entry key = "java.naming.ldap.attributes.binary">
            <value>objectSid</value>
        </entry>
        </map>
    </property>
</bean>

Вам придется изменить значения для вашего домена, но я думаю, что важная часть - это baseEnvironmentProperties.

Эта ветка также описывает программный способ установки этого (хотя для objectGuid вы можете просто поменять местами атрибут).

AbstractContextSource contextSource = (AbstractContextSource) ldapTemplate.getContextSource();
Map<String,String> baseEnvironmentProperties = new HashMap<String, String>();
baseEnvironmentProperties.put("java.naming.ldap.attributes.binary", "objectSid");
contextSource.setBaseEnvironmentProperties(baseEnvironmentProperties);
contextSource.afterPropertiesSet();

Не могли бы вы мне помочь, как добавить это к моему ActiveDirectoryLdapAuthenticationProvider?

kojot 29.05.2018 08:50

Если вы обновляете файл конфигурации bean-компонента, в этом нет необходимости. Если это не вариант, то я не совсем уверен. Я знаю AD, но я не Java-разработчик, поэтому сам немного в этом заблудился. Этот блок кода на самом деле не говорит, откуда взялась переменная ldapTemplate. Думаю, это недостающий элемент.

Gabriel Luci 29.05.2018 14:10

Я заставил это работать, добавив свойства среды в метод конфигурации:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/", "/home").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/login")
            .permitAll()
            .and()
            .logout()
            .permitAll();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .authenticationProvider(activeDirectoryLdapAuthenticationProvider());
}

private ActiveDirectoryLdapAuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
    ActiveDirectoryLdapAuthenticationProvider provider =
            new ActiveDirectoryLdapAuthenticationProvider(LdapConfig.AD_DOMAIN, LdapConfig.AD_SERVER);

// ************** NEW ENVIRONMENT PROPERTIES **********************************
    Map<String, Object> environmentProperties = new HashMap<>();
    environmentProperties.put("java.naming.ldap.attributes.binary", "objectsid");
    provider.setContextEnvironmentProperties(environmentProperties);
// ************** END OF NEW ENVIRONMENT PROPERTIES ***************************

    provider.setUserDetailsContextMapper(new LdapUserDetailsContextMapper());
    return provider;
    }
}

А затем читаем это так в UserDetailContextMapper:

public class CustomUserDetailsContextMapper implements UserDetailsContextMapper {

private final static Logger logger = LoggerFactory.getLogger(CustomUserDetailsContextMapper.class);

@Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {
    logger.info(ctx.getDn().toString());
    byte[] byteSid = null;
    try {
        byteSid = (byte[]) ctx.getAttributes().get("objectsid").get();
    } catch (NamingException e) {
        e.printStackTrace();
    }
    String sid = LdapUtils.convertBinarySidToString(byteSid);
    logger.info("SID: {}", sid);

    return new User(username, "notUsed", true, true, true, true,
            AuthorityUtils.createAuthorityList("ROLE_USER"));    
}

Надеюсь, это поможет!

Другие вопросы по теме