Я прочитал почти все о Spring/Security/Ldap и ActiveDirectory в stackoverflow. Даже если бы я нашел полезные советы и подсказки, я не смог решить свою проблему.
Вот он: я настроил Spring Безопасность, используя пользовательскую службу и пользовательскую страницу входа, и все работает нормально. Затем я попытался переключиться на конечный поставщик аутентификации, который, как оказалось, является ActiveDirectory.
Вот мой security-applicationContext.xml(напомню, что эта настройка отлично работает с пользовательской услугой в качестве поставщика проверки подлинности, поэтому файл импортируется и т.д.):
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/security/oauth http://www.springframework.org/schema/security/spring-security-oauth.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<!-- Définitions globales de sécurité -->
<global-method-security pre-post-annotations="enabled" />
<!-- Configuration de l'accès et du formulaire -->
<!-- Permettre l'accès libre aux feuilles de style, polices et images -->
<http pattern='/resources/css/**' security="none" />
<http pattern='/resources/fonts/**' security="none" />
<http pattern='/resources/images/**' security="none" />
<http use-expressions="true" access-denied-page="/403" disable-url-rewriting="true">
<!-- Limitation à une seule session utilisateur concurrente -->
<session-management invalid-session-url="/identite?time=1">
<concurrency-control max-sessions="1" expired-url="/identite?time=1" />
</session-management>
<!-- Définitions pour le formulaire de la page JSP d'identification -->
<form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" />
<logout logout-url="/logout" logout-success-url="/identite?out=1" delete-cookies="JSESSIONID" invalidate-session="true" />
<!-- Utiliser un canal chiffré pour les échanges -->
<intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" />
<intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" />
</http>
<!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) -->
<authentication-manager erase-credentials="true">
<ldap-authentication-provider ref="myADProvider" />
<!-- This is the user-service authentication provider that is working fine
<authentication-provider>
<user-service>
<user name="Toto" authorities="ROLE_USER, ROLE_ADMIN" password="totototo" />
</user-service>
</authentication-provider>
-->
</authentication-manager>
<b:bean id="myADProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="fsappsuni" />
<b:constructor-arg value="ldap://fsapps.company.uni:389/" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
<b:property name="useAuthenticationRequestCredentials" value="true" />
</b:bean>
В bean myADProvider, даже если я изменил первый аргумент конструктора на fsapps.company.uni или company.uni или что бы то ни было, он ничего не изменит при следующей ошибке. Проблема возникает из-за того, что после привязки поиск выполняется с неправильным фильтром, ища что-то вроде (& (userPrincipalName = {0}) (objectclass= user)) вместо (& (sAMAccountName = {0}) (объектный = пользователь)). Поскольку я не мог понять, как изменить это, пока вы можете сделать это с поставщиком LDAP, я затем переключился на провайдера LDAP, пытаясь заставить его работать без успеха, не наткнувшись на проблему в том же месте. Я также обновил мою Spring Framework с 3.1.2 до 4.1.6.RELEASE и Spring Безопасность с 3.1.2 до 4.0.0.RELEASE после прочтения возникла проблема с ActiveDirectoryLdapAuthenticationProvider в надежде, что проблема будет в то же время, начальные обсуждения этого вопроса с версией 3.x.
Вот моя конфигурация для настройки LDAP, которая пытается сделать аутентификацию работой с Active Directory:
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/security/oauth
http://www.springframework.org/schema/security/spring-security-oauth.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!-- Définitions globales de sécurité -->
<global-method-security pre-post-annotations="enabled" />
<!-- Configuration de l'accès et du formulaire -->
<!-- Permettre l'accès libre aux feuilles de style, polices et images -->
<http pattern='/resources/css/**' security="none" />
<http pattern='/resources/fonts/**' security="none" />
<http pattern='/resources/images/**' security="none" />
<http use-expressions="true" disable-url-rewriting="true">
<!-- Limitation à une seule session utilisateur concurrente -->
<session-management invalid-session-url="/identite?time=1">
<concurrency-control max-sessions="1" expired-url="/identite?time=1" />
</session-management>
<!-- Définitions pour le formulaire de la page JSP d'identification -->
<form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" />
<csrf disabled="true" />
<logout logout-url="/logout" logout-success-url="/identite?out=1" delete-cookies="JSESSIONID" invalidate-session="true" />
<!-- Utiliser un canal chiffré pour les échanges -->
<intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" />
<intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" />
</http>
<!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) -->
<ldap-server url="ldap://fsapps.company.uni/dc=fsapps,dc=company,dc=uni" port="389" />
<authentication-manager erase-credentials="true">
<ldap-authentication-provider role-prefix="none"
user-search-filter="(&(sAMAccountName={0})(objectClass=user))"
group-search-filter="(&(member={0})(objectClass=group))"
user-search-base="dc=fsapps,dc=company,dc=uni">
</ldap-authentication-provider>
<!-- <authentication-provider ref="myADProvider" ></authentication-provider> -->
</authentication-manager>
<!--
<b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="fsapps.company.uni" />
<b:constructor-arg value="ldap://fsapps.company.uni:389/" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
<!- -
<b:property name="useAuthenticationRequestCredentials" value="true" />
- ->
</b:bean>
<b:bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"></b:bean>
-->
</b:beans>
На этот раз я оставил часть конфигурации bean с поставщиком AD для справки. Это тоже не работает.
Итак, как я могу передать пути поиска пользователей и групп поставщику AD? Или, альтернативно, как настроить LDAP-провайдера для работы с AD и полной аутентификации?
Вот сообщение, которое я получаю в своем журнале с настройкой LDAP, настройка AD объясняется выше (Bad Credentials по существу из-за неправильного пути поиска):
2015-04-15 16:19:13,252 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-1] Authentication attempt using org.springframework.security.ldap.authentication.LdapAuthenticationProvider MDC{}
2015-04-15 16:19:13,252 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-1] Processing authentication request for user: ba5glag MDC{}
2015-04-15 16:19:13,252 DEBUG (o.s.s.l.s.FilterBasedLdapUserSearch.searchForUser) [http-8443-1] Searching for user 'myuser', with user search [ searchFilter: '(&(sAMAccountName={0})(objectClass=user))', searchBase: 'dc=fsapps,dc=company,dc=uni', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ] MDC{}
2015-04-15 16:19:13,299 DEBUG (o.s.s.a.DefaultAuthenticationEventPublisher.publishAuthenticationFailure) [http-8443-1] No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException MDC{}
2015-04-15 16:19:13,299 ERROR (o.s.s.w.a.AbstractAuthenticationProcessingFilter.doFilter) [http-8443-1] An internal error occurred while trying to authenticate the user. MDC{}
org.springframework.security.authentication.InternalAuthenticationServiceException: Uncategorized exception occured during LDAP processing; nested exception is javax.naming.NamingException: [LDAP: error code 1 - 00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece(unprintable character here)]; remaining name 'dc=fsapps,dc=company,dc=uni'
at org.springframework.security.ldap.authentication.LdapAuthenticationProvider.doAuthentication(LdapAuthenticationProvider.java:207) ~[spring-security-ldap-4.0.0.RELEASE.jar:?]
at org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider.authenticate(AbstractLdapAuthenticationProvider.java:82) ~[spring-security-ldap-4.0.0.RELEASE.jar:?]
Надеюсь, я предоставил всю необходимую информацию для кого-то, чтобы дать некоторые подсказки и рекомендации для решения этой проблемы конфигурации.
ОБНОВЛЕНИЕ 2015-04-16 ~ 10: 20
Я выяснил, как добавить фильтр поиска с помощью ActiveDirectoryLdapAuthenticationProvider. Я также наблюдал с Wireshark обмен между моим сервером приложений и сервером AD, чтобы увидеть, что на самом деле было сделано. Вот мои выводы, я считаю, что я не далеко от решения моей проблемы. Мой обновленный security-applicationContext.xml, я выбросил материал ldap-сервера, так как теперь я сосредоточен на том, чтобы работать с ActiveDirectoryLdapAuthenticationProvider. Итак, теперь это более чистая конфигурация для чтения:
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/security/oauth
http://www.springframework.org/schema/security/spring-security-oauth.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">
<!-- Définitions globales de sécurité -->
<global-method-security pre-post-annotations="enabled" />
<!-- Configuration de l'accès et du formulaire -->
<!-- Permettre l'accès libre aux feuilles de style, polices et images -->
<http pattern='/resources/css/**' security="none" />
<http pattern='/resources/fonts/**' security="none" />
<http pattern='/resources/images/**' security="none" />
<http pattern='/resources/js/**' security="none" />
<http use-expressions="true" disable-url-rewriting="true">
<!-- Limitation à une seule session utilisateur concurrente -->
<session-management invalid-session-url="/identite?expiree=1">
<concurrency-control max-sessions="1" expired-url="/identite?expiree=1" />
</session-management>
<!-- Définitions pour le formulaire de la page JSP d'identification -->
<form-login login-page="/identite" login-processing-url="/identite.proc" default-target-url="/" always-use-default-target="true" authentication-failure-url="/identite?err=1" username-parameter="username" password-parameter="password" />
<csrf disabled="true" />
<logout logout-url="/logout" logout-success-url="/identite?termine=1" delete-cookies="JSESSIONID" invalidate-session="true" />
<!-- Utiliser un canal chiffré pour les échanges -->
<intercept-url requires-channel="https" pattern="/identite*" access="permitAll()" />
<intercept-url requires-channel="https" pattern="/**" access="isAuthenticated()" />
<access-denied-handler error-page="/erreur403" />
</http>
<!-- Fournisseurs d'identité pour le formulaire (au final, LDAP) -->
<authentication-manager erase-credentials="true">
<authentication-provider ref="myADProvider" />
</authentication-manager>
<b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="fsapps.company.uni" />
<b:constructor-arg value="ldap://fsapps.company.uni:389/" />
<b:property name="searchFilter" value="(&(sAMAccountName={0})(objectClass=user))" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
<b:property name="useAuthenticationRequestCredentials" value="true" />
</b:bean>
<b:bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />
</b:beans>
Несколько комментариев о конфигурации. В определении myADProvider bean первый аргумент конструктора fsapps.company.uni используется для создания принципала в форме [email protected] и для создания базового объекта для запроса поиска с базовым объектом формы: dc = fsapps, DC = компания, dc = уни.
Второй аргумент конструктора используется для установления связи. Следующий элемент типа свойства с name= "searchFilter" вызовет метод setSearchFilter() класса ActiveDirectoryLdapAuthenticationProvider, чтобы установить фильтр поиска (именно это я искал изначально, чтобы добиться определенного прогресса). Итак, теперь он настроен на поиск (& (sAMAccountName = {0}) (objectclass= пользователь)).
С помощью этой настройки я вижу в WireShark цепочку LDAP, и привязка завершается успешно. Ответ на связывание является успешным. Затем запрос на поиск также успешно завершен, но не возвращает результат. Следовательно, я все еще получаю следующее в своем журнале:
2015-04-16 10:30:28,201 DEBUG (o.s.s.a.ProviderManager.authenticate) [http-8443-2] Authentication attempt using org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider MDC{}
2015-04-16 10:30:28,201 DEBUG (o.s.s.l.a.AbstractLdapAuthenticationProvider.authenticate) [http-8443-2] Processing authentication request for user: myusername MDC{}
2015-04-16 10:30:28,294 DEBUG (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Searching for entry under DN '', base = 'dc=fsapps,dc=company,dc=uni', filter = '(&(sAMAccountName={0})(objectClass=user))' MDC{}
2015-04-16 10:30:28,294 INFO (o.s.s.l.SpringSecurityLdapTemplate.searchForSingleEntryInternal) [http-8443-2] Ignoring PartialResultException MDC{}
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials MDC{}
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Updated SecurityContextHolder to contain null Authentication MDC{}
2015-04-16 10:30:28,310 DEBUG (o.s.s.w.a.AbstractAuthenticationProcessingFilter.unsuccessfulAuthentication) [http-8443-2] Delegating to authentication failure handler org.springframework.se[email protected]2876b359 MDC{}
Я считаю, что я почти там, но все же могу использовать небольшую помощь, если кто-то может предоставить любой. После тщательного изучения появляется первый аргумент конструктора, который используется для построения baseObject. И userPrincipalName - моя проблема. В нашей настройке имя userPrincipalName использует имя домена, которое не является именем домена в URL-адресе LDAP (например, campus.company.com). Пока что так хорошо, я могу изменить аргумент, чтобы соответствовать нашему доменному имени, используемому для построения принципов наших пользователей. Теперь проблема заключается в изменении базового объекта, который должен соответствовать схеме URL-адреса LDAP (то есть fsapps.company.uni).
В документации есть только один способ установки фильтра поиска, однако конструктор может использовать один, два или три аргумента. Третий аргумент предоставляет значение baseObject.
Затем моя проблема решается следующей конфигурацией, где я должен использовать все доступные сеттеры и аргументы конструктора, чтобы заставить ее работать. Определение myADProvider bean выглядит следующим образом:
<b:bean id="myADProvider" class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<b:constructor-arg value="campus.company.com" />
<b:constructor-arg value="ldap://fsapps.company.uni:389/" />
<b:constructor-arg value="dc=fsapps,dc=company,dc=uni" />
<b:property name="searchFilter" value="(&(userPrincipalName={0})(objectClass=user))" />
<b:property name="convertSubErrorCodesToExceptions" value="true" />
</b:bean>
В моем случае свойство searchFilter могло быть опущено сейчас, так как я возвращаюсь к значению по умолчанию. Несмотря на это очень длинное описание моей установки и проблемы. Я надеюсь, что кто-то другой сможет извлечь из этого выгоду.
Вот ссылка на документацию класса ActiveDirectorLdapAuthenticationProvider: http://docs.spring.io/autorepo/docs/spring-security/4.0.0.RELEASE/apidocs/org/springframework/security/ldap/authentication/ad/ActiveDirectoryLdapAuthenticationProvider.html
Я нашел WireShark очень полезным, чтобы узнать, что происходит между сервером приложений и сервером AD для отладки этой проблемы.