2
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Spring SecurityでForm認証とRequest-Header認証を併用する場合の実装サンプル

Posted at

きっかけ

とあるWebアプリケーション開発において、以下の2つを同時に実現する要件があった。 ①ログイン画面からIDとパスワードを入力することでForm認証ができる ②HTTPリクエストヘッダの特定の属性の値で認証ができる

②は、既存の外部認証システムが、認証成功時にHTTPリクエストヘッダにトークンを設定してリダイレクトするため、それを利用したSSOを実現するという要件。

①単独、または②単独の実装サンプルはインターネットの随所に見られるんだけど、併用するパターンは見受けられなかった(かつそれなりにテクニカルだった)ので、どうやって実現したかを紹介する。

ソース

以下のように設定する。 https://github.com/ShandyGaffLover/sample001/blob/master/src/main/resources/spring-security.xml

解説

「PRE_AUTH_FILTER」と「FORM_LOGIN_FILER」の2つをカスタマイズする。
    <sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
    <sec:custom-filter position="FORM_LOGIN_FILTER" ref="formLoginFilter" />

PRE_AUTH_FILTERのカスタマイズ

「PRE_AUTH_FILTER」のカスタマイズは以下のようにRequestHeaderAuthenticationFilterクラスを利用する。Form認証と併用する都合上、exceptionIfHeaderMissingプロパティをfalseに、continueFilterChainOnUnsuccessfulAuthenticationプロパティをtrueに設定する。

  <bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="SM_USER"/>
    <property name="authenticationManager" ref="sm_authenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false"/>

    <property name="continueFilterChainOnUnsuccessfulAuthentication" value="true"/>
  </bean>

ここで、AuthenticationManager(とAuthenticationProvider)は以下のように定義する。

  <sec:authentication-manager id="sm_authenticationManager">
    <sec:authentication-provider ref="preauthAuthProvider" />
  </sec:authentication-manager>

  <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="preAuthenticatedUserDetailsService">
      <bean id="userDetailsServiceWrapper"
          class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
        <property name="userDetailsService" ref="customUserDetailsService"/>
      </bean>
    </property>
  </bean>

AuthenticationProviderにはPreAuthenticatedAuthenticationProviderクラスを利用する。このときpreAuthenticatedUserDetailsServiceプロパティに与えるUserDetailsServiceはUserDetailsByNameServiceWrapperクラスによりラッパーされたものでなければならない点に注意。

FORM_LOGIN_FILERのカスタマイズ

「FORM_LOGIN_FILER」のカスタマイズは以下の通りである。
 <sec:authentication-manager id="form_authenticationManager">
    <sec:authentication-provider  user-service-ref="customUserDetailsService" >
    </sec:authentication-provider>
  </sec:authentication-manager>

  <bean id="formLoginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <property name="authenticationManager" ref="form_authenticationManager" />
    <property name="authenticationSuccessHandler" ref="formLoginSuccessHandler" />
    <property name="authenticationFailureHandler" ref="formLoginFailureHandler" />
    <property name="filterProcessesUrl" value="/login" />
  </bean>

ここで、カスタムフィルターを使うので、以下のようにタグのentry-point-ref属性を設定する必要がある点に注意。

  <sec:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">

  ~中略~

    <sec:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
    <sec:custom-filter position="FORM_LOGIN_FILTER" ref="formLoginFilter" />
  </sec:http>

  <bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <constructor-arg value="/loginPage" />
  </bean>

実物

以下から動作確認ができる。[^1] https://shandygafflover.herokuapp.com/

①ログイン画面から、usernameに「user」、passwordに「password」を入力しログインすると、認証される。
②HTTPリクエストヘッダの属性「SM_USER」に、値「user」を設定1すると、認証される。
 ここでは以下の記事で紹介されているModHeaderを利用する。

 ブラウザのHTTPヘッダーに外部から認証情報を設定する - Qiita
 https://qiita.com/utwang/items/1eeb25d27e8acea33a8a

実行結果

HTTPリクエストヘッダの属性「SM_USER」に、値「user」を設定する。 ![requestheader.png](https://qiita-image-store.s3.amazonaws.com/0/322008/7b04e084-5929-255d-8d10-7ee600665ee6.png)

この状態で例えば以下のURLにアクセスする。
url.png

すると認証されるので、ページが表示される。
greeting.png

HTTPリクエストヘッダに属性「SM_USER」が設定されていない場合はログイン画面に遷移するので、usernameとpasswordにより認証される。
login.png
greeting.png

参考URL

Spring Security 使い方メモ 認証・認可 - Qiita
https://qiita.com/opengl-8080/items/032ed0fa27a239bdc1cc

03-1.Spring Security 2の設定方法 - soracane
https://sites.google.com/site/soracane/home/springnitsuite/spring-security/spring-securityno-settei-houhou

テックノート – spring security 認証処理を自作する方法を解説
http://javatechnology.net/spring/spring-security-login-filter-original/

Spring Securityを適用するときの作業メモ - なみひらブログ
http://namihira.hatenablog.com/entry/20160817/1471396975

AbstractAuthenticationProcessingFilter (Spring Security 4.2.6.RELEASE API)
https://docs.spring.io/spring-security/site/docs/4.2.6.RELEASE/apidocs/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

Spring Security Java - Multiple Authentication Manager - 2 bean found error - Stack Overflow
https://stackoverflow.com/questions/32105846/spring-security-java-multiple-authentication-manager-2-bean-found-error

  1. リクエストヘッダの属性名「SM_USER」はあくまでも一例。実際の開発では、属性名は推測しにくいものとし機密事項とすべき。

2
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?