私の Web アプリケーションは、認証と認可に Spring Security を使用しています。認証は、企業 SSO を介して事前認証されます。ただし、フォールバックとして、それ以外の場合、アプリケーションは認証にフォーム ベースのログインを使用します。これも、デプロイメント記述子で認証プロバイダーのリストを構成することにより、Spring Security を使用して実現されます。次のシーケンスで説明する典型的なシナリオを考えてみましょう。
- 企業 SSO の事前認証に失敗すると、ログイン ページがユーザーに表示されます。
- 入力された資格情報が送信され、SSOPreAuthentication プロバイダーがプリンシパルを見つけることができないため (SSO の失敗を想定)、要求は次の認証プロバイダーである LdapAuthenticationProvider に転送されます。
ここで偶然に遭遇したのは、BindAuthenticator を使用する LdapAuthenticationProvider が、パスワードが部分的に正しい場合でもユーザー名を 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>
次に、2 つのシナリオのログのトレースを示します。
- パスワードが完全に間違っている場合(すべての文字が間違っている)
18:34:13,599 DEBUG [FilterChainProxy] /j_spring_security_check 追加フィルター チェーンの 8 の位置 4; 発射フィルター: 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' 18:34:13,599 DEBUG [AuthenticationProcessingFilter] リクエストは認証処理です 18:34:13,599 DEBUG [ProviderManager] org.springframework.security.providers.ldap.LdapAuthenticationProvider を使用した認証試行 18:34:13,599 DEBUG [FilterBasedLdapUserSearch] 検索中ユーザー '@username@'、ユーザー検索 [searchFilter: '(uid={0})'、searchBase: ''、スコープ: サブツリー、searchTimeLimit: 0、derefLinkFlag: false] 18:34:13,599 DEBUG [AbstractContextSource] プリンシパル: '' 18:34:13,943 DEBUG [AbstractContextSource] サーバー 'ldap://myLDAP.com で LDAP コンテキストを取得しました: 983/o=something.com' 18:34:14,130 DEBUG [DefaultSpringSecurityContextSource] プリンシパルでコンテキストを作成しています: 'uid=@username@, ou=people, l=AP, o=somthing.com' 18:34:14,458 DEBUG [ 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 追加フィルター チェーンの 8 の位置 4; 発射フィルター: 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=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: ''、スコープ: サブツリー、searchTimeLimit: 0、derefLinkFlag: false] 18:30:11,849 DEBUG [AbstractContextSource] プリンシパル: '' 18:30:12,193 DEBUG [AbstractContextSource] サーバー 'ldap://myLDAP.com で LDAP コンテキストを取得しました:
誰かがこの不思議な振る舞いを説明できますか?