13. SAML2

13.1 SAML 2.0 ログイン

SAML 2.0 ログイン、saml2Login() 機能は、SAML 2.0 ID プロバイダー(Okta、ADFS など)で既存のアカウントを使用してユーザーがアプリケーションにログインできるようにする機能をアプリケーションに提供します。

[Note] メモ

SAML 2.0 ログインは、SAML 2 プロファイル (英語) で指定されている Web ブラウザー SSO プロファイルを使用して実装されます。現在、実装は単純な認証スキームに制限されています。

13.1.1 Spring Security での SAML 2 サポート

SAML 2 サービスプロバイダー、SP (依存パーティ) のサポートは 2009 年から独立プロジェクト: GitHub (英語) として存在していました。1.0.x ブランチはまだ使用されていますが、SP 実装に基づいて SAML 2.0 ID プロバイダー実装も作成した Cloud Foundry ユーザーアカウントと認証サーバー: GitHub (英語) に含まれます。

2018 年に、サービスプロバイダーとアイデンティティプロバイダー: GitHub (英語) とスタンドアロンライブラリの両方の更新された実装を作成する実験を行いました。Spring Security チームである私たち Spring Security は、慎重かつ長期にわたる審議の結果、その努力を中止することにしました。この取り組みにより、そのスタンドアロン 1.0.x ライブラリの代替が作成されましたが、別のライブラリの上にライブラリを構築する必要はないと感じました。

代わりに、コア Spring Security: GitHub (英語) の一部として SAML 2 認証のフレームワークサポートを提供することを選択しました。

13.1.2 Saml 2 ログイン - 高レベルの概念

saml2Login() は、認証プロバイダー、別名アサーティングパーティーから XML アサーションを受信するサービスプロバイダー、SP、依存パーティーである認証に焦点を当てて、SAML 2 機能セット (英語) の一部をサポートすることを目的としています。

SAML 2 ログインまたは認証は、SP が IDP からアサーションと呼ばれる XML メッセージを受信して検証するという概念です。

現在、2 つのサポートされている認証フローがあります

  1. IDP 開始フロー - 例: Okta に直接ログインし、認証対象の Web アプリケーションを選択します。IDP である Okta は、Web アプリケーションである SP にアサーションを送信します。
  2. SP 開始フロー - 例: Web アプリケーション(SP)にアクセスし、アプリケーションが IDP に認証リクエストを送信してアサーションをリクエストします。IDP での認証が成功すると、IDP はアサーションを SP に送信します。

13.1.3 Saml 2 ログイン - 現在の機能セット

  1. サービスプロバイダー(SP/ 証明書利用者)は entityId = {baseUrl}/saml2/service-provider-metadata/{registrationId} によって識別されます
  2. {baseUrl}/login/saml2/sso/{registrationId} で Http-POST または Http-Redirect を介して SAML レスポンスに埋め込まれたアサーションを受信する
  3. レスポンスが署名されていない限り、アサーションに署名する必要があります
  4. 暗号化されたアサーションをサポート
  5. 暗号化された NameId 要素をサポート
  6. Converter<Assertion, Collection<? extends GrantedAuthority>> を使用して、アサーション属性を機関に抽出できます
  7. GrantedAuthoritiesMapper を使用して機関のマッピングとホワイトリストを許可する
  8. java.security.cert.X509Certificate 形式の公開鍵。
  9. AuthNRequest を介した SP 開始認証

Saml 2 ログイン - まだサポートされていません

  1. アサーション条件と属性をセッション機能にマッピングする (タイムアウト、追跡など)
  2. シングルログアウト
  3. 動的なメタデータの生成
  4. スタンドアロンアサーションの受信と検証 (レスポンスオブジェクトにラップされていません)

13.1.4 Saml 2 ログイン - Java 構成の概要

saml2Login() を Spring Security フィルターチェーンに追加するには、最小限の Java 構成には、SAML 構成と HttpSecurity.saml2Login() メソッドの呼び出しを含む構成リポジトリ RelyingPartyRegistrationRepository が必要です。

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
        //SAML configuration
        //Mapping this application to one or more Identity Providers
        return new InMemoryRelyingPartyRegistrationRepository(...);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .saml2Login()
        ;
    }
}

Bean 宣言は便利ですが、オプションのアプローチです。メソッド呼び出しを使用してリポジトリを直接接続できます

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .saml2Login()
                .relyingPartyRegistrationRepository(...)
        ;
    }
}

RelyingPartyRegistration

RelyingPartyRegistration: GitHub (英語) オブジェクトは、このアプリケーション、SP、アサーティングパーティ、IDP 間のマッピングを表します。

URI パターン

URI パターンは、受信リクエストに基づいて URI を自動的に生成するために頻繁に使用されます。saml2Login の URI パターンには、次の変数を含めることができます

  • baseUrl
  • registrationId
  • baseScheme
  • baseHost
  • basePort

例:

{baseUrl}/login/saml2/sso/{registrationId}
証明書利用者
  • registrationId - (必須)この構成マッピングの一意の識別子。この識別子は URI パスで使用される可能性があるため、URI エンコードが必要ないことに注意する必要があります。
  • localEntityIdTemplate - (オプション)受信リクエストに基づいてこのアプリケーションのエンティティ ID を作成する URI パターン。デフォルトは {baseUrl}/saml2/service-provider-metadata/{registrationId} であり、小さなサンプルアプリケーションの場合は次のようになります。
http://localhost:8080/saml2/service-provider-metadata/my-test-configuration

この構成オプションはパターンである必要はなく、固定 URI 値を使用できます。

  • remoteIdpEntityId - (必須)ID プロバイダーのエンティティ ID。常に固定 URI 値または文字列。パターンは許可されません。
  • assertionConsumerServiceUrlTemplate - (オプション)SP が開始したフロー中に SP から IDP に AuthNRequest とともに送信されるアサーションコンシューマーサービス URI を示す URI パターン。これはパターンにすることができますが、実際の URI は SP 上の ACS エンドポイントに解決する必要があります。デフォルト値は {baseUrl}/login/saml2/sso/{registrationId} であり、 Saml2WebSsoAuthenticationFilter: GitHub (英語) エンドポイントに直接マップします
  • idpWebSsoUrl - (必須)SP が AuthNRequest メッセージを送信する IDP シングルサインオンエンドポイントの固定 URI 値。
  • credentials - メッセージの署名、検証、暗号化、復号化に使用される資格情報、秘密鍵、x509 証明書のリスト。このリストには、資格情報を簡単にローテーションできるように冗長な資格情報を含めることができます。たとえば

    • [0] - X509Certificate{VERIFICATION,ENCRYPTION} - 検証と暗号化に使用される IDP の最初の公開鍵。
    • [1]-X509Certificate/{VERIFICATION,ENCRYPTION}- 検証に使用される IDP の 2 番目の検証キー。暗号化は常にリストの最初の ENCRYPTION キーを使用して行われます。
    • [2] - PrivateKey/X509Certificate{SIGNING,DECRYPTION} - SP の最初の署名および復号化資格。
    • [3]-PrivateKey/X509Certificate{SIGNING,DECRYPTION}-SP の 2 番目の復号化資格。署名は常にリストの最初の SIGNING キーを使用して行われます。

受信メッセージを受信すると、署名が常に必要になります。システムは最初にインデックス [0] の証明書を使用して署名の検証を試み、最初の証明書が失敗した場合にのみ 2 番目の証明書に移動します。

同様に、SP で構成された秘密キーが復号化に使用され、同じ順序で試行されます。IDP へのメッセージに署名するときに、最初の SP 資格情報(type=SIGNING)が使用されます。

証明書利用者構成の複製

アプリケーションが複数の ID プロバイダーを使用するユースケースでは、2 つの RelyingPartyRegistration オブジェクト間で一部の構成が重複していることが明らかになります。

  • localEntityIdTemplate
  • 資格情報 (すべての SP 資格情報、IDP 資格情報の変更)
  • assertionConsumerServiceUrlTemplate

構成値の複製にはいくつかの欠点がありますが、バックエンド構成リポジトリはこのデータストレージモデルを複製する必要はありません。

このセットアップには利点があります。一部の ID プロバイダーと他の ID プロバイダーでは、資格情報のローテーションがより簡単になる場合があります。このオブジェクトモデルにより、マルチ IDP のユースケースで構成が変更されたときに混乱が生じず、すべての ID プロバイダーで資格情報をローテーションできなくなります。

サービスプロバイダーのメタデータ

Spring Security SAML 2 実装は、XML 形式で SP メタデータをダウンロードするためのエンドポイントをまだ提供していません。交換される最小限のピース

  • entity ID - デフォルトは {baseUrl}/saml2/service-provider-metadata/{registrationId} この同じ値を使用する他の既知の構成名

    • ビューアーの制限
  • single signon URL - デフォルトは {baseUrl}/login/saml2/sso/{registrationId} この同じ値を使用する他の既知の構成名

    • 受信者の URL
    • リンク先 URL
    • アサーションコンシューマーサービス URL
  • X509Certificate - {SIGNING、DECRYPTION} 資格情報の一部として設定する証明書は、アイデンティティプロバイダーと共有する必要があります

認証リクエスト - SP 開始 Flow

Web アプリケーションから認証を開始するには、単純なリダイレクト

{baseUrl}/saml2/authenticate/{registrationId}

エンドポイントは、構成可能なファクトリで createAuthenticationRequest メソッドを呼び出して、AuthNRequest を生成します。構成で Saml2AuthenticationRequestFactory を Bean として公開するだけです。

public interface Saml2AuthenticationRequestFactory {
    String createAuthenticationRequest(Saml2AuthenticationRequest request);
}

13.1.5 Spring Boot 2.x サンプル

現在、Spring Security SAML ログインの自動構成: GitHub (英語) Spring Boot チームと協力しています。それまでの間、Yaml 設定をサポートする Spring Boot サンプルを提供しました。

サンプルを実行するには、次の 3 つの手順を実行する

  1. Spring Boot アプリケーションを起動する

    • ./gradlew :spring-security-samples-boot-saml2login:bootRun
  2. ブラウザーを開く

  3. これにより、ID プロバイダーに移動し、次を使用してログインします。

    • ユーザー: user
    • パスワード: password

複数のアイデンティティプロバイダーのサンプル

複数のプロバイダーを使用するのは非常に簡単ですが、注意を払わないと失敗する可能性のあるデフォルトがいくつかあります。RelyingPartyRegistration オブジェクトの SAML 構成では、SP エンティティ ID をデフォルトに

{baseUrl}/saml2/service-provider-metadata/{registrationId}

つまり、2 つのプロバイダー構成では、システムは次のようになります

registration-1 (Identity Provider 1) - Our local SP Entity ID is:
http://localhost:8080/saml2/service-provider-metadata/registration-1

registration-2 (Identity Provider 2) - Our local SP Entity ID is:
http://localhost:8080/saml2/service-provider-metadata/registration-2

以下のサンプルに示すこの構成では、外部に対して、実際に同じアプリケーション内でホストされる 2 つの仮想サービスプロバイダー ID を作成しました。

spring:
  security:
    saml2:
      login:
        relying-parties:
          - entity-id: &idp-entity-id https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php
            registration-id: simplesamlphp
            web-sso-url: &idp-sso-url https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php
            signing-credentials: &service-provider-credentials
              - private-key: |
                  -----BEGIN PRIVATE KEY-----
                  MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE
                  ...................SHORTENED FOR READ ABILITY...................
                  INrtuLp4YHbgk1mi
                  -----END PRIVATE KEY-----
                certificate: |
                  -----BEGIN CERTIFICATE-----
                  MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC
                  ...................SHORTENED FOR READ ABILITY...................
                  RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B
                  -----END CERTIFICATE-----
            verification-credentials: &idp-certificates
              - |
                -----BEGIN CERTIFICATE-----
                MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
                ...................SHORTENED FOR READ ABILITY...................
                lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk
                -----END CERTIFICATE-----
          - entity-id: *idp-entity-id
            registration-id: simplesamlphp2
            web-sso-url: *idp-sso-url
            signing-credentials: *service-provider-credentials
            verification-credentials: *idp-certificates

これが望ましくない場合は、次を使用してローカル SP エンティティ ID を手動で上書きできます。

localEntityIdTemplate = {baseUrl}/saml2/service-provider-metadata

ローカル SP エンティティ ID をこの値に変更する場合、登録 ID に基づいて登録済み ID プロバイダーごとに正しいシングルサインオン URL(アサーションコンシューマーサービス URL)を提供することが重要です。{baseUrl}/login/saml2/sso/{registrationId}

現行バージョンへ切り替える