複数の認証手形発行所をWeb起動中にスイッチする部品

SpringSecurityでは、複数の認証手形発行所(AuthenticationProvider)を持ち、順番に認証して最初にOKになった認証手形発行所から

認証手形をもらうということができます。

しかし、1つの認証手形発行所内で複数の認証手形発行所を持ち、条件に応じて使用する認証手形発行所を変えるといったことができません。

例えば認証は他サーバにOK/NGを確認し、他サーバが通信不可などで利用できない場合は、自サーバのDBにOK/NGを確認する、といった

仕様の場合などがこれに当たると思います。

このような仕様を実現したい場合、soracaneの部品であるDelegatingAuthenticationProviderを使用すると解決できます。

以下では、このクラスの使い方の具体例を見ていきます。

目標

まず、以下のサンプルの目標(ゴール)を示します。

ここでは、カード認証を例題にしたサンプルを見ていきます。

通常のカード認証は、カード用の認証サーバを自サーバと別に構築し、認証サーバに通信してOK/NGを聞きます。

とうぜん認証サーバが落ちた場合はログインできなくなります。

しかし、土日も使わなければならないようなシステムの場合、ログインできなくなると運用自体が止まってしまいます。

そこで認証サーバが止まった場合は、別の認証方式(例えばID/PW)を使用するようにします。

使用サンプル

<Spring設定ファイルのサンプル>

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:util="http://www.springframework.org/schema/util"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:sec="http://www.springframework.org/schema/security"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/util

http://www.springframework.org/schema/util/spring-util-2.5.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/security

http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">

<!-- メインのセキュリティ設定 -->

<sec:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint" access-denied-page="/403.jsp" path-type="ant" >

<sec:intercept-url pattern="/css/*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

<sec:intercept-url pattern="/error.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

<sec:intercept-url pattern="/login.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>

<!-- 独自フィルタを入れる場合はコメントアウト -->

<!--sec:form-login login-page="/login.jsp" default-target-url="/top.html" authentication-failure-url="/login.jsp?error=true"/>

-->

<sec:logout logout-url="/logout" logout-success-url="/login.jsp" invalidate-session="true"/>

<sec:anonymous granted-authority="ROLE_ANONYMOUS"/>

</sec:http>

<!-- AuthenticationProviderオブジェクト -->

<bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">

<property name="providers" >

<list>

<ref local="delegatingAuthenticationProvider"/>

</list>

</property>

</bean>

<!-- 条件によってスイッチする認証プロバイダー -->

<bean id="delegatingAuthenticationProvider" class="jp.co.soracane.security.webapp.DelegatingAuthenticationProvider" >

<property name="delegationDecision">

<bean class="my.CardAuthDecision"/>

</property>

<property name="map">

<map>

<entry key="0" value-ref="cardAuthenticationProvider"/>

<entry key="1" value-ref="daoAuthenticationProvider" />

</map>

</property>

<property name="otherProvider" ref="daoAuthenticationProvider"/>

</bean>

<!-- カード用 認証発行所(何か自作する) -->

<bean id="cardAuthenticationProvider" class="my.CardAuthenticationProvider">

</bean>

<!-- ID/PW 認証発行所 -->

<bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">

<property name="userDetailsService" ref="userService1" />

</bean>

<!-- ログインユーザの設定。 -->

<sec:user-service id="userService">

<sec:user name="user1" password="pass1" authorities="ADMIN"/>

<sec:user name="user2" password="pass2" authorities="READ"/>

</sec:user-service>

<!-- エントリポイントの設定 -->

<bean id="authenticationProcessingFilterEntryPoint"

class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">

<property name="loginFormUrl" value="/login.jsp"/>

</bean>

</beans>

DelegatingAuthenticationProviderは、mapプロパティに切り替えの条件と、使用する認証手形発行所を設定します。

上記の場合は、0のときにカード認証、1のときにID/PW認証という設定になっています。

0か1かをきめるのはDecisionクラスで、これは自作します。

もし、既に用意しているDecision派生クラスを使用できる場合にはそれをうまく利用してください。

【DelegatingAuthenticationProviderの主なプロパティ】

delegationDecision

map

otherProvider

条件分岐に必要になる決定情報を作成するクラスを設定します。

delegationDecisionで決定した情報で条件分岐します。

決定情報をキーにして、認証手形発行所を決めます。

決定情報がmap上に存在しない場合に、ここで設定した認証手形発行所が使用されます。

<Decisionクラスのサンプル:my.CardAuthDecision.java>

public class CardAuthDecision implements DelegationDecision {

public String decide(String seed) {

//カード認証サーバ落ちていれば1を、落ちていなければ0を返すように実装します

}

}

DelegationDecision をimplementsして作成するだけです。

最後に

この部品は、単純に条件に従って認証手形発行所を決めるだけの部品です。

考え方はシンプルですので使用しやすいかと思います。

Decisionは既にいくつか用意されていますので、javadocで派生クラスを見ていただければと思います。

システム日付によって変更をしたい場合でしたら、おそらく既存の部品だけで実現できるかと思います。