Мое веб-приложение использует Spring Security для аутентификации и авторизации.
Аутентификация предварительно аутентифицируется через корпоративный единый вход. Однако в качестве альтернативы приложение использует авторизацию на основе формы для аутентификации в противном случае. Это также достигается с помощью Spring Security благодаря наличию списка провайдеров аутентификации, настроенных в дескрипторе развертывания. Рассмотрим типичный сценарий, описанный в следующей последовательности.
- В случае сбоя предварительной аутентификации корпоративного единого входа пользователю предоставляется страница входа в систему.
- Введенные учетные данные отправляются, и, поскольку провайдер SSOPreAuthentication не может найти принципала (при условии сбоя единого входа), запрос перенаправляется следующему провайдеру аутентификации, который является LdapAuthenticationProvider.
Здесь я случайно натолкнулся на то, что LdapAuthenticationProvider, использующий BindAuthenticator, привязывает имя пользователя к LDAP, даже если пароль частично правильный (совпадают только первые 8 символов пароля. Остальные игнорируются).
Ниже приведена конфигурация в моем дескрипторе развертывания, относящаяся к обсуждению
<?xml version="1.0" encoding="UTF-8"?>
<!-- DO NOT EDIT FILE GENERATED BY BUILD SCRIPT (edit the config template version) -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd"><security:http auto-config="false" access-denied-page="/accessDenied.htm" access-decision-manager-ref="accessDecisionManager">
<security:form-login login-page="/login.htm" authentication-failure-url="/login.htm?error=true" />
<security:logout logout-success-url="/login.htm" />
<security:intercept-url pattern="/**/*" access="ROLE_DENIED" />
</security:http>
<bean id="preauthSSOFilter" class="MySSOProcessingFilter">
<security:custom-filter position="PRE_AUTH_FILTER" />
<property name="principalRequestHeader" value="XX1" />
<property name="credentialsRequestHeader" value="XX2" />
<property name="ldapUserIdRequestHeader" value="XX3" />
<property name="ldapDNRequestHeader" value="XX4" />
<property name="ldapAuthenticator" ref="ldapBindAuthenticator" />
<property name="anonymousUserIfPrincipalRequestHeaderMissing" value="[none]" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="ldapContextValidator" class="org.springframework.ldap.pool.validation.DefaultDirContextValidator" />
<bean id="ldapContextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://myLDAP.com:983/o=something.com"/>
</bean>
<bean id="ldapAuthenticationProvider" class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
<security:custom-authentication-provider />
<constructor-arg ref="ldapBindAuthenticator" />
<constructor-arg ref="ldapAuthoritiesPopulator" />
</bean>
<bean id="ldapBindAuthenticator" class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg ref="ldapContextSource"/>
<property name="userSearch" ref="ldapUserSearch" />
</bean>
<bean id="ldapUserSearch" class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value="(uid={0})"/>
<constructor-arg index="2" ref="ldapContextSource" />
</bean>
<bean id="ldapAuthoritiesPopulator" class="org.springframework.security.ldap.populator.UserDetailsServiceLdapAuthoritiesPopulator">
<constructor-arg ref="userDetailsService" />
</bean>
А вот следы журналов для двух сценариев:
- Когда пароль совершенно неверный (все символы неверны)
18: 34: 13 599 DEBUG [FilterChainProxy] / j_spring_security_check at
положение 4 из 8 в цепи дополнительного фильтра; Фильтр обжига:
«Org.springframework.security.ui.webapp.AuthenticationProcessingFilter [
порядок = 700; ] '18: 34: 13 599 ОТЛАДКА [AuthenticationProcessingFilter]
Запрос на обработку аутентификации 18: 34: 13,599 DEBUG
[ProviderManager] Попытка аутентификации с использованием
org.springframework.security.providers.ldap.LdapAuthenticationProvider
18: 34: 13,599 DEBUG [FilterBasedLdapUserSearch] Поиск пользователя
'@ username @', с поиском пользователя [searchFilter: '(uid = {0})',
searchBase: '', scope: subtree, searchTimeLimit: 0, derefLinkFlag:
false] 18: 34: 13 599 DEBUG [AbstractContextSource] Принципал: ''
18: 34: 13,943 DEBUG [AbstractContextSource] Получил контекст Ldap на сервере
'ldap: //myLDAP.com: 983 / o =thing.com' 18: 34: 14,130 ОТЛАДКА
[DefaultSpringSecurityContextSource] Создание контекста с принципалом:
'uid = @ username @, ou = people, l = AP, o = somthing.com' 18: 34: 14,458 ОТЛАДКА
[BindAuthenticator] Не удалось выполнить привязку как uid = @ username @, ou = people, l = AP:
org.springframework.ldap.AuthenticationException: [LDAP: код ошибки 49
- неверные учетные данные]; Вложенное исключение - javax.naming.AuthenticationException: [LDAP: код ошибки 49 - Неверный
Полномочия]
- Когда пароль правильный или частично (только первые 8 символов совпадают), правильный
18: 30: 11 849 DEBUG [FilterChainProxy] / j_spring_security_check at
положение 4 из 8 в цепи дополнительного фильтра; Фильтр обжига:
«Org.springframework.security.ui.webapp.AuthenticationProcessingFilter [
порядок = 700; ] '18: 30: 11,849 DEBUG [AuthenticationProcessingFilter]
Запрос на обработку аутентификации 18: 30: 11,849 DEBUG
[ProviderManager] Попытка аутентификации с использованием
org.springframework.security.providers.ldap.LdapAuthenticationProvider
18: 30: 11,849 DEBUG [FilterBasedLdapUserSearch] Поиск пользователя
'@ username @', с поиском пользователя [searchFilter: '(uid = {0})',
searchBase: '', scope: subtree, searchTimeLimit: 0, derefLinkFlag:
false] 18: 30: 11,849 DEBUG [AbstractContextSource] Принципал: ''
18: 30: 12,193 DEBUG [AbstractContextSource] Получил контекст Ldap на сервере
'ldap: //myLDAP.com: 983 / o =thing.com' 18: 30: 12,365 ОТЛАДКА
[DefaultSpringSecurityContextSource] Создание контекста с принципалом:
'uid = @ username @, ou = people, l = AP, o =thing.com' 18: 30: 12,708 ОТЛАДКА
[AbstractContextSource] Получил Ldap контекст на сервере
'LDAP: //myLDAP.com: 983 / о = something.com'
Может кто-нибудь объяснить это таинственное поведение?