barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)
Показаны сообщения с ярлыком AD. Показать все сообщения
Показаны сообщения с ярлыком AD. Показать все сообщения

вторник, 27 июня 2017 г.

ktpass: ошибка "Password set failed! 0x00000020"

Проблема

Пытаюсь связать kerberos-принципала с пользователем утилитой ktpass:
ktpass -princ HTTP/MYSERVER@DOMAIN.LOCAL -mapuser MYSERVER$@DOMAIN.LOCAL -crypto ALL -ptype KRB5_NT_SRV_HST +rndpass -out C:\TMP\MYSERVER.keytab
Получаю ошибку:
Reset MYSERVER$'s password [y/n]?  y
Password set failed! 0x00000020Aborted.
Причина

В DN объекта MYSERVER$ есть кириллица.

Решение

Перенести MYSERVER$ таким образом, чтобы в его DN не было кириллицы.

среда, 17 августа 2016 г.

Spring Security и аутентификация по Active Directory: ошибка "Failed to locate directory entry for authenticated user"

Проблема

Настроил в приложении, использующем Spring Security, аутентификацию по Active Directory (провайдер ActiveDirectoryLdapAuthenticationProvider), но при попытке входа ловлю ошибку:
2016-08-17 11:20:45.525 ERROR 22440 --- [http-nio-8080-exec-154] ctiveDirectoryLdapAuthenticationProvider : Failed to locate directory entry for authenticated user: user@domain.local
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-0310020A, problem 2001 (NO_OBJECT), data 0, best match of:
'DC=domain,DC=local'

 ]
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3160) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:3081) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2888) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1846) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1769) ~[na:1.8.0_60]
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1786) ~[na:1.8.0_60]
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:418) ~[na:1.8.0_60]
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:396) ~[na:1.8.0_60]
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:297) ~[na:1.8.0_60]
at org.springframework.security.ldap.SpringSecurityLdapTemplate.searchForSingleEntryInternal(SpringSecurityLdapTemplate.java:333) ~[spring-security-ldap-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.searchForUser(ActiveDirectoryLdapAuthenticationProvider.java:310) ~[spring-security-ldap-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider.doAuthentication(ActiveDirectoryLdapAuthenticationProvider.java:144) ~[spring-security-ldap-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:82) [spring-security-ldap-4.0.3.RELEASE.jar:4.0.3.RELEASE]
Причина

Провайдер ActiveDirectoryLdapAuthenticationProvider работает следующим образом: 
  1. сначала он пытается забиндиться к AD с указанным логином / паролем
  2. после этого ищет объект пользователя по совпадению введенного логина и атрибута userPrincipalName
Попробовал выполнить аналогичный поиск по введенному логину в AD через curl (http://barbitoff.blogspot.ru/2016/08/ldap-ad-ldapsearch.html), поиск не дал результатов. Посмотрел на объект пользователя - он вообще не имеет атрибута userPrincipalName (не большой специалист по AD, поэтому не могу сказать, почему). К счастью, фильтр, используемый для поиска пользователя в ActiveDirectoryLdapAuthenticationProvider кастомизируется путем вызова setSearchFilter().

четверг, 11 августа 2016 г.

Spring Security и "javax.naming.PartialResultException [Root exception is javax.naming.CommunicationException: xxx.yyy:389 [Root exception is java.net.UnknownHostException : xxx.yyy]]"

Проблема

Неожиданно в приложении, использующем для аутентификации и авторизации Spring Security + Misrosoft Active Directory, перестала работать аутентификация из-за ошибки:
javax.naming.PartialResultException [Root exception is javax.naming.CommunicationException: xxx.yyy:389 [Root exception is java.net.UnknownHostException: xxx.yyy]]
При этом хостнэйм xxx.yyy не фигурирует в настройках Spring Security (там указан ip сервера AD), единственная корреляция этого хостнэйма с настройками заключается в том, что DC=xxx,DC=yyy - это корневой DN нашего AD.

Решение

Погуглив, нашел, что ошибка PartialResultException говорит о том, что AD-сервер вернул ссылку на вышестоящий AD-лес, и с обработкой этой ссылки возникла какая-то проблема (в нашем случае, ссылка содержит неизвестный хостнэйм xxx.yyy).  Одно из возможных решений - изменить порт, по которому приложение соединяется с AD, с 389 на 3268, по этому порту AD не возвращает ссылок. Спасибо http://stackoverflow.com/questions/16412236/how-to-resolve-javax-naming-partialresultexception.

среда, 9 апреля 2014 г.

Wavemaker 6.5.3: аутентификация по Active Directory с использованием sAMAccountName

Проблема

Реализовать аутентификацию по Active Directory в приложении, построенном на Wavemaker 6.5.3, c использованием в качестве логина sAMAccountName.

Решение 

Через UI настройек безопасности поиск по sAMAccountName не организовать, т.к. там единственный вариант поиска пользователя - это userDnPattern:


Нам же нужно задать не шаблон для DN, а поиск по атрибуту sAMAccountName. Выход - идем Source -> Resources, в Folder Shortcuts выбираем "Project", там открываем файл WEB-INF/project-security.xml. В нем добавляем бин:
<bean id="userSearch"
       class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
   <constructor-arg index="0">
     <value>OU=Users</value>
   </constructor-arg>
   <constructor-arg index="1">
     <value>(sAMAccountName={0})</value>
   </constructor-arg>
   <constructor-arg index="2">
     <ref local="initialDirContextFactory"/>
   </constructor-arg>
   <property name="searchSubtree">
     <value>true</value>
   </property>
 </bean>
Первый аргумент конструктора нужно поправить в соответствие с базовым узлом для поиска по sAMAccountName. Базовый узел указывается относительно указанного в URL-е LDAP (в моем случае - относительно DC=my,DC=domain).
Далее необходимо исправить первый аргумент конструктора бина ldapAuthProvider с:
<constructor-arg>
<bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg>
<ref local="initialDirContextFactory"/>
</constructor-arg>
<property name="userDnPatterns">
<list>
<value>cn={0},ou=Users</value>
</list>
</property>
</bean>
</constructor-arg>
на 
<constructor-arg>
<bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg>
<ref local="initialDirContextFactory"/>
</constructor-arg>
<property name="userSearch">
<ref bean="userSearch"/>
</property>
</bean>
</constructor-arg>
Все, можно заходить в приложение по  sAMAccountName и паролю из AD.

PS Спасибо http://dev.wavemaker.com/forums/?q=node/7096

пятница, 1 июня 2012 г.

Spring Security: аутентификация и авторизация с помощью Active Directory

Задача:

Реализовать в веб-приложении авторизацию с помощью Active Directory (для начала без применения различных ролей).

Решение:

Не буду описывать весь процесс прикручивания Spring Security к веб-приложению (о нем я уже когда-то писал тут), расскажу лишь о специфичных для LDAP моментах (в моем случае роль LDAP-сервера выполнял AD, но возможно, описанное здесь справедливо и для других серверов).
Во-первых, потребуются jar-ник Spring LDAP (http://www.springsource.org/ldap), а также модуль Spring Security "spring-security-ldap". 
Для осуществления подключения к LDAP и аутентификации / авторизации через него потребутся следующие вещи:
  1. DN и пароль пользователя, от имени которого приложение будет выполнять запросы к LDAP (если AD не позволяет подключаться и искать пользователей анонимно)
  2. Собственно хост / порт LDAP-сервера
  3. BaseDN, т.е. тот контекст, который будет базовым для поиска пользователей
  4. Критерий, по которому мы будем соотносить введенный пользователем логин с объектом, соответствующим этому пользователю в LDAP. Например, роль логина может выполнять электронная почта пользователя или его UID, как в моем случае.
В конфигурации Spring Security необходимо объявить соответствующий провайдер аутентификации и инициализировать необходимые для него бины:
<beans:bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
  <beans:constructor-arg value="ldap://myldap:389/dc=barbitoff,dc=blogspot,dc=com"/>
  <!--beans:property name="userDn" value="uid=barbitoff,ou=People,dc=barbitoff,dc=blogspot,dc=com"/>
  <beans:property name="password" value="barbitoffspass"/-->
</beans:bean>  
<beans:bean id="ldapActiveDirectoryAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
  <beans:constructor-arg>
<beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
 <beans:constructor-arg ref="contextSource"/>
 <beans:property name="userDnPatterns">
<beans:list>
 <beans:value>uid={0},ou=People</beans:value>
</beans:list>
 </beans:property>
</beans:bean>
  </beans:constructor-arg>
  <beans:constructor-arg>
<beans:bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
 <beans:constructor-arg ref="contextSource"/>
 <beans:constructor-arg value="ou=Groups"/>
 <beans:property name="groupRoleAttribute" value="ou"/>
</beans:bean>
  </beans:constructor-arg>
</beans:bean>      
<authentication-manager erase-credentials="true">
<authentication-provider ref="ldapActiveDirectoryAuthProvider"/>
</authentication-manager>   
Сконфигурированный таким образом Spring Security будет пытаться аутентифицировать  в LDAP пользователя, используя DN "uid=<entered-login>,ou=People,dc=barbitoff,dc=blogspot,dc=com", где <entered-login> - введенный пользователем в форму входа логин. При успешной аутентификации список ролей пользователя будет заполняться на основе результата поиска в ou=Groups,dc=barbitoff,dc=blogspot,dc=com с фильтром "member=<userDN>" (имя роли будет браться из атрибута "ou").
Закомментированные строки в бине "contextSource" нужно раскомментировать, если поиск пользователей невозможен при анонимном подключении к LDAP. 
Для отладки конфигурации очень полезно включить логирование на уровень DEBUG (http://barbitoff.blogspot.com/2012/05/spring-security.html).