В моем веб-приложении 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?
Да, именно так, и он не соответствует ни одному добавленному мной пользователю (я не искал весь каталог по этому SID).
Последний блок символов должен быть разным для разных пользователей. Если нет, сравните поток байтов sid двух пользователей и посмотрите, совпадает ли он. Сид будет уникальным.
ctx.getDn() - это DN учетной записи пользователя, для которой требуется SID?
@GabrielLuci да :)




Думаю, ответ здесь: 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?
Если вы обновляете файл конфигурации bean-компонента, в этом нет необходимости. Если это не вариант, то я не совсем уверен. Я знаю AD, но я не Java-разработчик, поэтому сам немного в этом заблудился. Этот блок кода на самом деле не говорит, откуда взялась переменная ldapTemplate. Думаю, это недостающий элемент.
Я заставил это работать, добавив свойства среды в метод конфигурации:
@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"));
}
Надеюсь, это поможет!
Это одинаково для всех пользователей?