目次

1. 概要

この記事では、RESTAPIの同じURI構造で基本認証とダイジェスト認証の両方を設定する方法について説明します。 前回の記事では、RESTサービスを保護する別の方法であるフォームベースの認証について説明しました。そのため、基本認証とダイジェスト認証が自然な代替手段であり、よりRESTfulな方法でもあります。

2. 基本認証の構成

フォームベースの認証がRESTfulサービスに理想的でない主な理由は、SpringSecurityがSessions を利用することです。これはもちろんサーバー上の状態であるため、REST[のステートレス制約X226X]は実質的に無視されます。

基本認証を設定することから始めます–最初に、古いカスタムエントリポイントを削除し、メインからフィルタリングしますセキュリティ要素:

<http create-session="stateless">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
</http>

BasicAuthenticationFilterBasicAuthenticationEntryPointの両方の作成と配線を処理する単一の構成行で、基本認証のサポートがどのように追加されたかに注意してください。 。

2.1. ステートレスな制約を満たす–セッションを取り除く

RESTfulアーキテクチャスタイルの主な制約の1つは、元の論文が次のように、クライアント/サーバー通信が完全にステートレスであることです。

5.1.3ステートレス

次に、クライアント/サーバーの相互作用に制約を追加します。セクション3.4.3(図5-3)のクライアント-ステートレス-サーバー(CSS)スタイルのように、通信は本質的にステートレスである必要があります。サーバーには、要求を理解するために必要なすべての情報が含まれている必要があり、サーバーに保存されているコンテキストを利用することはできません。 したがって、セッション状態は完全にクライアントに保持されます。

サーバー上のSessionの概念は、Spring Securityで長い歴史を持つものであり、これまで、特に名前空間を使用して構成を行った場合、完全に削除することは困難でした。

ただし、Spring Securityは、セッション作成用の新しいステートレスオプションを使用して名前空間構成を拡張します。これにより、Springによってセッションが作成または使用されないことが効果的に保証されます。 この新しいオプションが行うことは、セキュリティフィルターチェーンからすべてのセッション関連フィルターを完全に削除し、各要求に対して認証が確実に実行されるようにすることです。

3. ダイジェスト認証の構成

以前の構成から、ダイジェスト認証を設定するために必要なフィルターとエントリーポイントがBeanとして定義されます。 そうしてダイジェストエントリポイントによって作成されたものをオーバーライドします舞台裏。 最後に、カスタムダイジェストフィルターは、セキュリティ名前空間の after セマンティクスを使用してセキュリティフィルターチェーンに導入され、基本認証フィルターの直後に配置されます。

<http create-session="stateless" entry-point-ref="digestEntryPoint">
   <intercept-url pattern="/api/admin/**" access="ROLE_ADMIN" />

   <http-basic />
   <custom-filter ref="digestFilter" after="BASIC_AUTH_FILTER" />
</http>

<beans:bean id="digestFilter" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationFilter">
   <beans:property name="userDetailsService" ref="userService" />
   <beans:property name="authenticationEntryPoint" ref="digestEntryPoint" />
</beans:bean>

<beans:bean id="digestEntryPoint" class=
 "org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint">
   <beans:property name="realmName" value="Contacts Realm via Digest Authentication"/>
   <beans:property name="key" value="acegi" />
</beans:bean>

<authentication-manager>
   <authentication-provider>
      <user-service id="userService">
         <user name="eparaschiv" password="eparaschiv" authorities="ROLE_ADMIN" />
         <user name="user" password="user" authorities="ROLE_USER" />
      </user-service>
   </authentication-provider>
</authentication-manager>

残念ながら、 サポートセキュリティ名前空間で、基本認証を構成できる方法でダイジェスト認証を自動的に構成します 。 そのため、必要なBeanを定義し、セキュリティ構成に手動で配線する必要がありました。

4. 同じRestfulサービスで両方の認証プロトコルをサポートする

基本認証またはダイジェスト認証だけでも、SpringSecurityで簡単に実装できます。 同じURIマッピングで、同じRESTful Webサービスに対して両方をサポートしているため、サービスの構成とテストに新しいレベルの複雑さがもたらされます。

4.1. 匿名のリクエスト

セキュリティチェーンに基本フィルターとダイジェストフィルターの両方がある場合、匿名リクエスト –認証資格情報を含まないリクエスト( Authorization HTTPヘッダー)–がSpringSecurityによって処理される方法は–2つです。認証フィルターは資格情報なしを検出し、フィルターチェーンの実行を続行します。 次に、リクエストがどのように認証されなかったかを確認すると、 AccessDeniedException がスローされ、 ExceptionTranslationFilter でキャッチされます。これにより、ダイジェストエントリポイントが開始され、クライアントに資格情報の入力を求められます。

基本フィルターとダイジェストフィルターの両方の責任は非常に狭く、要求で認証資格情報のタイプを識別できない場合でも、セキュリティフィルターチェーンを実行し続けます。 このため、Spring Securityは、同じURIで複数の認証プロトコルをサポートするように構成できる柔軟性を備えています。

基本またはダイジェストのいずれかの正しい認証資格情報を含む要求が行われると、そのプロトコルが正しく使用されます。 ただし、匿名要求の場合、クライアントはダイジェスト認証資格情報の入力のみを求められます。 これは、ダイジェストエントリポイントがSpringSecurityチェーンのメインの単一エントリポイントとして構成されているためです。 そのため、ダイジェスト認証はデフォルトと見なすことができます。

4.2. 認証資格情報を使用したリクエスト

基本認証用の資格情報を使用した要求は、プレフィックス“ Basic”で始まるAuthorizationヘッダーによって識別されます。 このような要求を処理する場合、資格情報は基本認証フィルターでデコードされ、要求が承認されます。 同様に、ダイジェスト認証の資格情報を持つリクエストは、 Authorizationヘッダーにプレフィックス“ Digest”を使用します。

5. 両方のシナリオのテスト

テストは、基本またはダイジェストのいずれかで認証した後、新しいリソースを作成することによってRESTサービスを消費します。

@Test
public void givenAuthenticatedByBasicAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().preemptive().basic( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}
@Test
public void givenAuthenticatedByDigestAuth_whenAResourceIsCreated_then201IsReceived(){
   // Given
   // When
   Response response = given()
    .auth().digest( ADMIN_USERNAME, ADMIN_PASSWORD )
    .contentType( HttpConstants.MIME_JSON ).body( new Foo( randomAlphabetic( 6 ) ) )
    .post( paths.getFooURL() );

   // Then
   assertThat( response.getStatusCode(), is( 201 ) );
}

基本認証を使用したテストでは、サーバーが認証を要求したかどうかに関係なく、要求プリエンプティブに資格情報が追加されることに注意してください。 これは、サーバーがクライアントにクレデンシャルを要求する必要がないようにするためです。チャレンジする場合は、ダイジェストクレデンシャルがデフォルトであるため、チャレンジが行われます。

6. 結論

この記事では、RESTfulサービスの基本認証とダイジェスト認証の両方の構成と実装について説明しました。主にSpring Security名前空間のサポートと、フレームワークのいくつかの新機能を使用しています。