セキュリティ名前空間の構成

名前空間構成は、Spring Framework のバージョン 2.0 以降で使用可能になっています。これにより、従来の Spring Bean アプリケーションコンテキスト構文を、追加の XML スキーマの要素で補足できます。詳細については、Spring リファレンスドキュメントを参照してください。名前空間要素を使用して、個々の Bean をより簡潔に構成したり、より強力に、問題のドメインにより厳密に一致し、根本的な複雑さをユーザーから隠す代替構成構文を定義したりできます。単純な要素は、複数の Bean と処理ステップがアプリケーションコンテキストに追加されているという事実を隠すことができます。例: security 名前空間からアプリケーションコンテキストに次の要素を追加すると、アプリケーション内での使用をテストするための組み込み LDAP サーバーが起動します。

<security:ldap-server />

これは、同等の Apache Directory サーバー Bean を接続するよりもはるかに簡単です。最も一般的な代替構成要件は、ldap-server 要素の属性によってサポートされており、ユーザーは、どの Bean を作成する必要があるか、および Bean プロパティ名が何であるかを心配する必要がありません。ldap-server 要素の使用の詳細については、LDAP 認証の章を参照してください。優れた XML エディターは、アプリケーションコンテキストファイルを編集する際に、使用可能な属性と要素に関する情報を提供する必要があります。標準の Spring 名前空間を操作するための特別な機能を備えているため、Pleiades All in One (JDK, STS, Lombok 付属) または Eclipse Spring Tool Suite (英語) を試すことをお勧めします。

アプリケーションコンテキストで security 名前空間の使用を開始するには、spring-security-config jar をクラスパスに追加します。次に、必要なのは、スキーマ宣言をアプリケーションコンテキストファイルに追加することだけです。

<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
		https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/security
		https://www.springframework.org/schema/security/spring-security.xsd">
	...
</beans>

表示される多くの例(およびサンプルアプリケーション)では、デフォルトの名前空間として(beans ではなく) security を使用することがよくあります。つまり、すべてのセキュリティ名前空間要素のプレフィックスを省略して、コンテンツを読みやすくすることができます。アプリケーションコンテキストを別々のファイルに分割し、それらの 1 つにほとんどのセキュリティ構成がある場合にも、これを実行することをお勧めします。セキュリティアプリケーションのコンテキストファイルは、次のように開始されます。

<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/security
		https://www.springframework.org/schema/security/spring-security.xsd">
	...
</beans:beans>

この章では、この構文が今後使用されることを前提としています。

名前空間の設計

名前空間は、フレームワークの最も一般的な使用箇所をキャプチャーし、アプリケーション内で有効にするための単純化された簡潔な構文を提供するように設計されています。この設計は、フレームワーク内の大規模な依存関係に基づいており、次の領域に分割できます。

  • Web/HTTP セキュリティは最も複雑な部分です。フレームワーク認証メカニズムの適用、URL の保護、ログインページとエラーページのレンダリングなどに使用されるフィルターと関連するサービス Bean をセットアップします。

  • ビジネスオブジェクト(メソッド)セキュリティは、サービス層を保護するためのオプションを定義します。

  • AuthenticationManager は、フレームワークの他の部分からの認証リクエストを処理します。

  • AccessDecisionManager は、Web およびメソッドのセキュリティのためのアクセス決定を提供します。デフォルトのものが登録されていますが、通常の Spring Bean 構文で宣言されたカスタムのものを使用することを選択できます。

  • AuthenticationProvider インスタンスは、認証マネージャーがユーザーを認証するためのメカニズムを提供します。名前空間は、いくつかの標準オプションのサポートと、従来の構文で宣言されたカスタム Bean を追加する手段を提供します。

  • UserDetailsService は認証プロバイダーと密接に関連していますが、他の Bean でも必要になることがよくあります。

次のセクションで、これらを構成する方法を説明します。

セキュリティ名前空間の構成の開始

このセクションでは、フレームワークの主な機能のいくつかを使用するために名前空間構成を構築する方法について説明します。最初はできるだけ早く起動して実行し、いくつかのテストログインを使用して、既存の Web アプリケーションに認証サポートとアクセス制御を追加することを想定しています。次に、データベースまたはその他のセキュリティリポジトリに対する認証に切り替える方法を見ていきます。後のセクションでは、より高度な名前空間構成オプションを紹介します。

web.xml の構成

最初に行う必要があるのは、web.xml ファイルに次のフィルター宣言を追加することです。

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

DelegatingFilterProxy は、アプリケーションコンテキストで Spring Bean として定義されているフィルター実装に委譲する Spring Framework クラスです。この場合、Bean の名前は springSecurityFilterChain です。これは、Web セキュリティを処理するために名前空間によって作成された内部インフラストラクチャ Bean です。この場合、Bean の名前は "springSecurityFilterChain" です。これは、Web セキュリティを処理するために名前空間によって作成された内部インフラストラクチャ Bean です。この Bean 名を自分で使用しないように注意してください。この Bean を web.xml に追加すると、アプリケーションコンテキストファイルの編集を開始する準備が整います。Web セキュリティサービスは、<http> 要素によって構成されます。

最小限の <http> 構成

Web セキュリティを有効にするには、次の構成が必要です。

<http>
<intercept-url pattern="/**" access="hasRole('USER')" />
<form-login />
<logout />
</http>

そのリストは、欲しいと言っています:

  • アプリケーション内のすべての URL を保護する必要があり、それらにアクセスするには ROLE_USER のロールが必要です

  • ユーザー名とパスワードを使用したフォームを使用してアプリケーションにログインするには

  • アプリケーションからログアウトできるように登録されたログアウト URL

<http> 要素は、すべての Web 関連の名前空間機能の親です。<intercept-url> 要素は pattern を定義します。これは、Ant パス構文を使用して受信リクエストの URL と照合されます。一致が実際に実行される方法の詳細については、HttpFirewall のセクションを参照してください。代わりに正規表現マッチングを使用することもできます(詳細については、名前空間の付録を参照してください)。access 属性は、指定されたパターンに一致するリクエストのアクセス要件を定義します。デフォルトの構成では、これは通常、コンマで区切られたロールのリストであり、そのうちの 1 つはユーザーがリクエストを行うことを許可されている必要があります。ROLE_ プレフィックスは、ユーザーの権限との単純な比較を行う必要があることを示すマーカーです。つまり、通常のロールベースのチェックを使用する必要があります。Spring Security のアクセス制御は、単純なロールの使用に限定されません(したがって、異なる型のセキュリティ属性を区別するためにプレフィックスを使用します)。解釈がどのように変化するかは後でわかります。access 属性のコンマ区切り値の解釈は、使用されている AccessDecisionManager の実装によって異なります。Spring Security 3.0 以降、属性に EL 式を設定することもできます。

複数の <intercept-url> 要素を使用して、URL のセットごとに異なるアクセス要件を定義できますが、それらはリストされた順序で評価され、最初の一致が使用されます。最も具体的な一致を一番上に配置する必要があります。method 属性を追加して、特定の HTTP メソッド(GETPOSTPUT など)への一致を制限することもできます。

ユーザーを追加するには、名前空間で直接テストデータのセットを定義できます。

<authentication-manager>
<authentication-provider>
	<user-service>
	<!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
	NoOpPasswordEncoder should be used. This is not safe for production, but makes reading
	in samples easier. Normally passwords should be hashed using BCrypt -->
	<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
	<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
	</user-service>
</authentication-provider>
</authentication-manager>

上記のリストは、同じパスワードを安全に保管する方法の例を示しています。パスワードの前に {bcrypt} を付けて、DelegatingPasswordEncoder に、パスワードが BCrypt を使用してハッシュされるように構成された PasswordEncoder をサポートするように指示します。

<authentication-manager>
<authentication-provider>
	<user-service>
	<user name="jimi" password="{bcrypt}$2a$10$ddEWZUl8aU0GdZPPpy7wbu82dvEw/pBpbRvDQRqA41y6mK1CoH00m"
			authorities="ROLE_USER, ROLE_ADMIN" />
	<user name="bob" password="{bcrypt}$2a$10$/elFpMBnAYYig6KRR5bvOOYeZr1ie1hSogJryg9qDlhza4oCw1Qka"
			authorities="ROLE_USER" />
	<user name="jimi" password="{noop}jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
	<user name="bob" password="{noop}bobspassword" authorities="ROLE_USER" />
	</user-service>
</authentication-provider>
</authentication-manager>

<http> エレメントは、FilterChainProxy とそれが使用するフィルター Bean を作成するロールを果たします。フィルターの位置が事前定義されているため、フィルターの順序が正しくないなど、以前は一般的な課題は課題ではなくなりました。

<authentication-provider> 要素は DaoAuthenticationProvider Bean を作成し、<user-service> 要素は InMemoryDaoImpl を作成します。すべての authentication-provider 要素は <authentication-manager> 要素の子である必要があります。これにより、ProviderManager が作成され、認証プロバイダーが登録されます。名前空間の付録で作成された Bean の詳細情報を見つけることができます。フレームワークの重要なクラスとその使用方法を理解し始めたい場合、特に後でカスタマイズしたい場合は、この付録をクロスチェックする必要があります。

上記の構成では、2 人のユーザー、パスワード、アプリケーション内でのロール(アクセス制御に使用される)を定義しています。user-service 要素に properties 属性を設定することにより、標準のプロパティファイルからユーザー情報をロードすることもできます。ファイル形式の詳細については、メモリ内認証のセクションを参照してください。<authentication-provider> 要素を使用するということは、認証マネージャーがユーザー情報を使用して認証リクエストを処理することを意味します。複数の <authentication-provider> 要素を使用して、さまざまな認証ソースを定義できます。それぞれが順番に相談されます。

この時点で、アプリケーションを起動できるようになり、続行するにはログインする必要があります。試してみるか、プロジェクトに付属している「チュートリアル」サンプルアプリケーションを試してみてください。

デフォルトのログイン後の宛先の設定

保護されたリソースにアクセスしようとしてフォームログインのプロンプトが表示されない場合は、default-target-url オプションが有効になります。これは、正常にログインした後にユーザーが取得される URL です。デフォルトは / です。always-use-default-target 属性を true に設定することにより、ユーザーが常にこのページにアクセスするように構成することもできます(ログインが「オンデマンド」であったか、明示的にログインを選択したかに関係なく)。これは、アプリケーションでユーザーが常に「ホームページ」ページから開始する必要がある場合に役立ちます。例:

<http pattern="/login.htm*" security="none"/>
<http use-expressions="false">
<intercept-url pattern='/**' access='ROLE_USER' />
<form-login login-page='/login.htm' default-target-url='/home.htm'
		always-use-default-target='true' />
</http>

宛先をさらに制御するには、authentication-success-handler-ref 属性を default-target-url の代替として使用できます。参照される Bean は AuthenticationSuccessHandler のインスタンスでなければなりません。

高度な Web 機能

このセクションでは、基本を超えたさまざまな機能について説明します。

独自のフィルターを追加する

以前に Spring Security を使用したことがある場合は、フレームワークがサービスの適用に使用するフィルターのチェーンを維持していることをご存知でしょう。スタックの特定の場所に独自のフィルターを追加するか、現在名前空間構成オプションがない Spring Security フィルター(CAS など)を使用することができます。または、UsernamePasswordAuthenticationFilter (<form-login> 要素によって作成される)などの標準の名前空間フィルターのカスタマイズされたバージョンを使用して、Bean を明示的に使用するときに使用できる追加の構成オプションのいくつかを利用することもできます。フィルターチェーンは直接公開されていないため、名前空間構成でこれをどのように行うことができますか?

名前空間を使用する場合、フィルターの順序は常に厳密に適用されます。アプリケーションコンテキストが作成されるとき、フィルター Bean は名前空間処理コードによってソートされ、標準の Spring Security フィルターはそれぞれ、名前空間内のエイリアスと既知の位置を持ちます。

以前のバージョンでは、フィルターインスタンスが作成された後、アプリケーションコンテキストの後処理中に並べ替えが行われました。バージョン 3.0 + では、クラスがインスタンス化される前に、Bean メタデータレベルでソートが行われるようになりました。これは、<http> 要素の解析中にフィルターリスト全体を認識している必要があるため、独自のフィルターをスタックに追加する方法に影響を与えるため、3.0 では構文がわずかに変更されています。

次の表に、フィルター、エイリアス、フィルターを作成する名前空間要素と属性を、フィルターチェーンで発生する順序で示します。

表 1: 標準のフィルターエイリアスと順序
エイリアス フィルタークラス 名前空間要素または属性

DISABLE_ENCODE_URL_FILTER

DisableEncodeUrlFilter

http@disable-url-rewriting

FORCE_EAGER_SESSION_FILTER

ForceEagerSessionCreationFilter

http@create-session="ALWAYS"

CHANNEL_FILTER

ChannelProcessingFilter

http/intercept-url@requires-channel

SECURITY_CONTEXT_FILTER

SecurityContextPersistenceFilter

http

CONCURRENT_SESSION_FILTER

ConcurrentSessionFilter

session-management/concurrency-control

HEADERS_FILTER

HeaderWriterFilter

http/headers

CSRF_FILTER

CsrfFilter

http/csrf

LOGOUT_FILTER

LogoutFilter

http/logout

X509_FILTER

X509AuthenticationFilter

http/x509

PRE_AUTH_FILTER

AbstractPreAuthenticatedProcessingFilter Subclasses

N/A

CAS_FILTER

CasAuthenticationFilter

なし

FORM_LOGIN_FILTER

UsernamePasswordAuthenticationFilter

http/form-login

BASIC_AUTH_FILTER

BasicAuthenticationFilter

http/http-basic

SERVLET_API_SUPPORT_FILTER

SecurityContextHolderAwareRequestFilter

http/@servlet-api-provision

JAAS_API_SUPPORT_FILTER

JaasApiIntegrationFilter

http/@jaas-api-provision

REMEMBER_ME_FILTER

RememberMeAuthenticationFilter

http/remember-me

ANONYMOUS_FILTER

AnonymousAuthenticationFilter

http/anonymous

SESSION_MANAGEMENT_FILTER

SessionManagementFilter

session-management

EXCEPTION_TRANSLATION_FILTER

ExceptionTranslationFilter

http

FILTER_SECURITY_INTERCEPTOR

FilterSecurityInterceptor

http

SWITCH_USER_FILTER

SwitchUserFilter

なし

custom-filter 要素とこれらの名前の 1 つを使用して、フィルターを表示する位置を指定することにより、独自のフィルターをスタックに追加できます。

<http>
<custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />
</http>

<beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>

スタック内の別のフィルターの前または後にフィルターを挿入する場合は、after または before 属性を使用することもできます。FIRST および LAST を position 属性とともに使用して、フィルターをスタック全体の前または後にそれぞれ表示することを示すことができます。

フィルター位置の競合の回避

名前空間によって作成された標準フィルターの 1 つと同じ位置を占める可能性のあるカスタムフィルターを挿入する場合は、名前空間のバージョンを誤って含めないでください。機能を置き換えたいフィルターを作成する要素をすべて削除します。

<http> 要素自体を使用して作成されたフィルター(SecurityContextPersistenceFilterExceptionTranslationFilterFilterSecurityInterceptor)を置き換えることはできないことに注意してください。デフォルトでは、AnonymousAuthenticationFilter が追加され、セッション固定保護が無効になっていない限り、SessionManagementFilter もフィルターチェーンに追加されます。

認証エントリポイントを必要とする名前空間フィルターを置き換える場合(つまり、認証されていないユーザーがセキュリティで保護されたリソースにアクセスしようとすることによって認証プロセスがトリガーされる場合)、カスタムエントリポイント Bean も追加する必要があります。

メソッドのセキュリティ

バージョン 2.0 以降、Spring Security は、サービスレイヤーメソッドにセキュリティを追加するための実質的なサポートを備えています。JSR-250 アノテーションセキュリティとフレームワークの元の @Secured アノテーションのサポートを提供します。バージョン 3.0 以降、式ベースのアノテーションを利用することもできます。単一の Bean にセキュリティを適用するか(intercept-methods 要素を使用して Bean 宣言を装飾することにより)、または AspectJ スタイルのポイントカットを使用してサービスレイヤー全体にわたって複数の Bean を保護することができます。

デフォルトの AccessDecisionManager

このセクションは、Spring Security 内のアクセス制御の基礎となるアーキテクチャーについてある程度の知識があることを前提としています。そうでない場合は、スキップして後で戻ることができます。このセクションは、単純なロールベースのセキュリティ以上のものを使用するためにカスタマイズを行う必要がある人にのみ関連するためです。

名前空間構成を使用すると、AccessDecisionManager のデフォルトインスタンスが自動的に登録され、intercept-url および protect-pointcut 宣言(およびアノテーション、メソッドを保護するためにアノテーションを使用する場合)。

デフォルトの戦略は、AffirmativeBasedAccessDecisionManager を RoleVoter および AuthenticatedVoter とともに使用することです。これらの詳細については、認可の章を参照してください。

AccessDecisionManager のカスタマイズ

より複雑なアクセス制御戦略を使用する必要がある場合は、方法と Web セキュリティの両方の代替手段を設定できます。

メソッドのセキュリティを確保するには、global-method-security の access-decision-manager-ref 属性を、アプリケーションコンテキストで適切な AccessDecisionManager Bean の id に設定します。

<global-method-security access-decision-manager-ref="myAccessDecisionManagerBean">
...
</global-method-security>

Web セキュリティの構文は同じですが、属性は http 要素にあります。

<http access-decision-manager-ref="myAccessDecisionManagerBean">
...
</http>