第3章 SAML
本セクションでは、Red Hat Single Sign-On クライアントアダプターまたは汎用 SAML プロバイダーライブラリーを使用して SAML でアプリケーションおよびサービスのセキュリティーを保護する方法を説明します。
3.1. Java アダプター
Red Hat Single Sign-On には、Java アプリケーションのさまざまなアダプターがあります。正しいアダプターの選択は、ターゲットプラットフォームによって異なります。
3.1.1. 汎用アダプターの設定
Red Hat Single Sign-On がサポートする各 SAML クライアントアダプターは、単純な XML テキストファイルで設定できます。これは次のようになります。
<keycloak-saml-adapter xmlns="urn:keycloak:saml:adapter"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:keycloak:saml:adapter https://www.keycloak.org/schema/keycloak_saml_adapter_1_10.xsd">
<SP entityID="http://localhost:8081/sales-post-sig/"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
logoutPage="/logout.jsp"
forceAuthentication="false"
isPassive="false"
turnOffChangeSessionIdOnLogin="false"
autodetectBearerOnly="false">
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-sig/"/>
</KeyStore>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP entityID="idp"
signaturesRequired="true">
<SingleSignOnService requestBinding="POST"
bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
/>
<SingleLogoutService
requestBinding="POST"
responseBinding="POST"
postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
/>
<Keys>
<Key signing="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
</SP>
</keycloak-saml-adapter>
これらの設定スイッチの一部はアダプター固有で、一部の設定がすべてのアダプターで共通となる場合があります。Java アダプターでは、システムプロパティーの置き換えとして ${…} エンクロージャーを使用できます。たとえば ${jboss.server.config.dir} になります。
3.1.1.1. SP 要素
SP 要素属性の説明は次のとおりです。
<SP entityID="sp"
sslPolicy="ssl"
nameIDPolicyFormat="format"
forceAuthentication="true"
isPassive="false"
keepDOMAssertion="true"
autodetectBearerOnly="false">
...
</SP>- entityID
- これは、このクライアントの ID です。IdP では、クライアントが通信しているユーザーを判別するためにこの値が必要です。この設定は 必須 です。
- sslPolicy
-
これは、アダプターが強制する SSL ポリシーです。有効な値は
ALL、EXTERNAL、およびNONEです。ALLの場合、すべてのリクエストは HTTPS 経由で受信する必要があります。EXTERNALの場合、非プライベート IP アドレスのみが HTTPS 経由で有線を通過する必要があります。NONEの場合、HTTPS 経由のリクエストはありません。この設定は 任意 です。デフォルト値はEXTERNALです。 - nameIDPolicyFormat
-
SAML クライアントは、特定の NameID Subject 形式を要求できます。特定の形式が必要な場合は、この値を入力します。標準の SAML 形式の識別子である
urn:oasis:names:tc:SAML:2.0:nameid-format:transientある必要があります。この設定は 任意 です。デフォルトでは、特別な形式は要求されません。 - forceAuthentication
-
SAML クライアントは、ユーザーが IdP にすでにログインしていても、再認証することをリクエストできます。有効にするには、これを
trueに設定します。この設定は 任意 です。デフォルト値はfalseです。 - isPassive
-
SAML クライアントは、IdP にログインしていない場合でも、ユーザーの認証が要求されないように要求できます。必要に応じてこれを
trueに設定します。forceAuthenticationは逆の設定なので、一緒に使用しないでください。この設定は 任意 です。デフォルト値はfalseです。 - turnOffChangeSessionIdOnLogin
-
セッション ID は、一部のプラットフォームで正常にログインしてセキュリティー攻撃ベクトルをプラグインするためにデフォルトで変更されます。これを無効にするには、これを
trueに変更します。オフにしないことが推奨されます。デフォルト値はfalseです。 - autodetectBearerOnly
-
アプリケーションが Web アプリケーションと Web サービス (例: SOAP または REST) の両方に対応する場合は、true に設定する必要があります。Web アプリケーションの認証されていないユーザーを Keycloak ログインページにリダイレクトできますが、認証されていない SOAP または REST クライアントに HTTP
401ステータスコードを送信することができます。ログインページへのリダイレクトは理解できません。Keycloak は、X-Requested-With、SOAPAction、Acceptなどの一般的なヘッダーに基づいて SOAP クライアントまたは REST クライアントを自動検出します。デフォルト値は false です。 - logoutPage
-
これにより、ログアウト後に表示するページが設定されます。ページが
http://web.example.com/logout.htmlなどの完全な URL の場合、ユーザーは HTTP302ステータスコードを使用してログアウト後にそのページにリダイレクトされます。スキーム部分のないリンク (例:/logout.jsp)が指定されると、web.xml のsecurity-constraint宣言に従って保護領域に存在するかどうかに関係なく、ログアウトの後にページが表示され、ページがデプロイメントコンテキストルートとの関連で解決されます。 - keepDOMAssertion
-
この属性は true に設定して、要求に関連付けられた
SamlPrincipal内の元の形式でアダプターストアにアサーションの DOM 表現を設定します。アサーションドキュメントは、プリンシパル内のgetAssertionDocumentメソッドを使用して取得できます。これは、署名済みアサーションの再生時に特に便利です。返されるドキュメントは、Red Hat Single Sign-On サーバーが受信した SAML 応答を解析して生成されたドキュメントです。この設定は 任意 で、デフォルト値は false です (ドキュメントはプリンシパルに保存されません)。
3.1.1.2. サービスプロバイダーキーのキー要素
IdP で、クライアントアプリケーション (または SP) がすべての要求に署名するか、IdP がアサーションを暗号化する場合は、これを実行するために使用するキーを定義する必要があります。クライアント署名のドキュメントでは、ドキュメントの署名に使用される秘密鍵、および公開鍵または証明書の両方を定義する必要があります。暗号化の場合は、復号に使用する秘密鍵のみを定義する必要があります。
キーを記述する方法は 2 つあります。キーは Java KeyStore 内に格納することも、PEM 形式の keycloak-saml.xml にキーを直接コピー/貼り付けることもできます。
<Keys>
<Key signing="true" >
...
</Key>
</Keys>
Key 要素には、2 つの任意の属性の signing および encryption があります。true に設定すると、これらはアダプターにキーの使用目的を通知します。両方の属性が true に設定されていると、キーはドキュメントの署名と暗号化されたアサーションの復号の両方に使用されます。少なくとも 1 つの属性を true に設定する必要があります。
3.1.1.2.1. キーストア要素
Key 要素内で、Java Keystore から鍵と証明書を読み込みます。これは KeyStore 要素内で宣言されます。
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="myPrivate" password="test123"/>
<Certificate alias="myCertAlias"/>
</KeyStore>
</Key>
</Keys>
以下は、KeyStore 要素で定義されている XML 設定属性です。
- file
- キーストアへのファイルパス。このオプションは 任意 です。file または resource 属性を設定する必要があります。
- resource
- KeyStore への WAR リソースパス。これは、ServletContext.getResourceAsStream() へのメソッド呼び出しで使用されるパスです。このオプションは 任意 です。file または resource 属性を設定する必要があります。
- password
- KeyStore のパスワード。このオプションは 必須 です。
SP がドキュメントの署名に使用するキーを定義する場合は、Java KeyStore 内の秘密鍵および証明書への参照も指定する必要があります。上記の例の PrivateKey および Certificate 要素は、キーストア内のキーまたは証明書を参照する エイリアス を定義します。キーストアには、秘密鍵にアクセスするために追加のパスワードが必要です。PrivateKey 要素で、password 属性内にこのパスワードを定義する必要があります。
3.1.1.2.2. キーの PEMS
Key 要素内で、PrivateKeyPem、PublicKeyPemおよび CertificatePem のサブ要素を使用して、キーと証明書を直接宣言します。これらの要素に含まれる値は PEM キー形式に準拠する必要があります。通常、openssl または同様のコマンドラインツールを使用してキーを生成する場合は、このオプションを使用します。
<Keys>
<Key signing="true">
<PrivateKeyPem>
2341251234AB31234==231BB998311222423522334
</PrivateKeyPem>
<CertificatePem>
211111341251234AB31234==231BB998311222423522334
</CertificatePem>
</Key>
</Keys>3.1.1.3. SP PrincipalNameMapping 要素
この要素は任意です。HttpServletRequest.getUserPrincipal() などのメソッドから取得する Java Principal オブジェクトを作成する場合は、Principal.getName() メソッドによって返される名前を定義できます。
<SP ...> <PrincipalNameMapping policy="FROM_NAME_ID"/> </SP> <SP ...> <PrincipalNameMapping policy="FROM_ATTRIBUTE" attribute="email" /> </SP>
policy 属性は、この値に設定するために使用されるポリシーを定義します。この属性に使用できる値は次のとおりです。
- FROM_NAME_ID
- このポリシーは SAML サブジェクト値を使用するだけです。これはデフォルト設定です。
- FROM_ATTRIBUTE
-
これにより、サーバーから受信した SAML アサーションで宣言された属性のいずれかから値をプルします。XML 属性
attribute内で使用する SAML の assertion 属性の名前を指定する必要があります。
3.1.1.4. RoleIdentifiers 要素
RoleIdentifiers 要素は、ユーザーから受け取ったアサーション内の SAML 属性を、ユーザーの Java EE Security Context 内のロール識別子として使用する必要があります。
<RoleIdentifiers>
<Attribute name="Role"/>
<Attribute name="member"/>
<Attribute name="memberOf"/>
</RoleIdentifiers>
デフォルトでは、Role 属性値は Java EE ロールに変換されます。一部の IdP は、member または memberOf 属性アサーションを使用してロールを送信します。1 つ以上の Attribute 要素を定義して、ロールに変換する必要のある SAML 属性を指定できます。
3.1.1.5. RoleMappingsProvider 要素
RoleMappingsProvider は、SAML アダプターによって使用される SPI 実装 org.keycloak.adapters.saml.RoleMappingsProvider の ID および設定を許可するオプションの要素です。
Red Hat Single Sign-On が IDP として使用されると、ビルドされたロールマッパーを使用して、ロールを SAML アサーションに追加する前にマッピングできます。ただし、SAML アダプターを使用して、SAML リクエストをサードパーティの IDP に送信するびに使用できます。この場合は、SP の必要に応じてアサーションから展開されたロールを異なるロールセットにマッピングすることが必要になる場合があります。RoleMappingsProvider SPI は、必要なマッピングを実行するのに使用できるプラグ可能なロールマッパーの設定を可能にします。
プロバイダーの設定は以下のようになります。
...
<RoleIdentifiers>
...
</RoleIdentifiers>
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/role-mappings.properties"/>
</RoleMappingsProvider>
<IDP>
...
</IDP>
id 属性は、使用するインストール済みプロバイダーを特定します。Property サブ要素は複数回使用してプロバイダーの設定プロパティーを指定できます。
3.1.1.5.1. プロパティーベースのロールマッピングプロバイダー
Red Hat Single Sign-On には、properties ファイルを使用してロールマッピングを実行する RoleMappingsProvider 実装が含まれています。このプロバイダーは id properties-based-role-mapper によって識別され、org.keycloak.adapters.saml.PropertiesBasedRoleMapper クラスによって実装されます。
このプロバイダーは、使用される properties ファイルの場所を指定するために使用できる 2 つの設定プロパティーに依存します。最初に、設定値を使用して、ファイルシステムで properties ファイルを見つけることで、properties.file.location プロパティーが指定されているかどうかを確認します。設定したファイルが見つからない場合、プロバイダーは RuntimeException を出力します。以下のスニペットは、properties.file.configuration オプションを使用して、ファイルシステムの /opt/mappers/ ディレクトリーから roles.properties ファイルを読み込むプロバイダーの例を示しています。
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.file.location" value="/opt/mappers/roles.properties"/>
</RoleMappingsProvider>
properties.file.location 設定が設定されていない場合、プロバイダーは properties.resource.location プロパティーをチェックし、設定した値を使用して WAR リソースから properties ファイルを読み込みます。この設定プロパティーがない場合、プロバイダーはデフォルトで /WEB-INF/role-mappings.properties からファイルを読み込もうとします。リソースからファイルを読み込めない場合、プロバイダーは RuntimeException を出力します。以下のスニペットは、properties.resource.location を使用してアプリケーションの /WEB-INF/conf/ ディレクトリーから roles.properties ファイルを読み込むプロバイダーの例を示しています。
<RoleMappingsProvider id="properties-based-role-mapper">
<Property name="properties.resource.location" value="/WEB-INF/conf/roles.properties"/>
</RoleMappingsProvider>
properties ファイルには、ロールとプリンシパルの両方をキーとして含めることができ、0 つ以上のロールを値としてコンマで区切ります。呼び出されると、実装はアサーションから抽出したロールのセットを繰り返し処理し、各ロールについて、マッピングが存在するかどうかを確認します。ロールが空ロールにマップする場合、これは破棄されます。1 つ以上の異なるロールのセットにマップすると、これらのロールは結果セットに設定されます。ロールのマッピングが見つからない場合は、結果セットに組み込まれます。
ロールの処理後、アサーションから抽出したプリンシパルにエントリーの properties ファイルが含まれるかどうかを確認します。プリンシパルのマッピングが存在する場合は、値として一覧表示されるすべてのロールが結果セットに追加されます。これにより、追加のロールをプリンシパルに割り当てることができます。
たとえば、プロバイダーが以下のプロパティーファイルで設定されていると仮定します。
roleA=roleX,roleY roleB= kc_user=roleZ
プリンシパル kc_user が、roleA、roleB、および roleC があるアサーションから抽出されると、プリンシパルに割り当てられたロールの最終セットは roleC、roleX、roleY、および roleZ になります。なぜなら roleA が roleX および roleY にマッピングされ、roleB が空のロールにマッピングされて破棄され、roleC がそのまま使用され、追加ロールが kc_user プリンシパル (roleZ) に追加されるためです。
3.1.1.5.2. 独自のロールマッピングプロバイダーの追加
カスタムロールマッピングプロバイダーを追加するには、単に org.keycloak.adapters.saml.RoleMappingsProvider SPI を実装する必要があります。詳細は、『Server Developer Guide』の「SAML ロールマッピング SPI」を参照してください。
3.1.1.6. IDP 要素
IDP 要素のすべては、SP が通信しているアイデンティティープロバイダー (認証トークン) の設定を記述します。
<IDP entityID="idp"
signaturesRequired="true"
signatureAlgorithm="RSA_SHA1"
signatureCanonicalizationMethod="http://www.w3.org/2001/10/xml-exc-c14n#">
...
</IDP>
以下は、IDP 要素宣言内で指定できる属性設定オプションです。
- entityID
- これは IDP の発行者 ID です。この設定は 必須 です。
- signaturesRequired
-
trueに設定すると、クライアントアダプターは IDP に送信するすべてのドキュメントに署名します。また、クライアントは IDP が送信されたドキュメントに署名されることを想定します。このスイッチは、すべての要求および応答タイプのデフォルトを設定しますが、後でこのタイプを詳細に制御できることがわかります。この設定は 任意 で、デフォルトはfalseに設定されます。 - signatureAlgorithm
-
これは、IDP により署名されたドキュメントで使用することが必要な署名アルゴリズムです。使用できる値は、
RSA_SHA1、RSA_SHA256、RSA_SHA512、およびDSA_SHA1です。この設定は 任意 で、デフォルト値はRSA_SHA256です。 - signatureCanonicalizationMethod
-
これは、IDP により署名されたドキュメントで使用することが必要な署名の正規化方法です。この設定は 任意 です。デフォルト値は
http://www.w3.org/2001/10/xml-exc-c14n#で、大抵の IDP に適しています。 - metadataUrl
- IDP メタデータの取得に使用される URL。現在、これは署名キーと暗号化キーを定期的に取得するためにのみ使用され、SP 側で手動で変更することなく IDP でこれらのキーを循環させることができます。
3.1.1.7. IDP AllowedClockSkew サブ要素
AllowedClockSkew オプションの sub 要素は、IDP と SP の間で許可されるクロックの skew を定義します。デフォルト値は 0 です。
<AllowedClockSkew unit="MILLISECONDS">3500</AllowedClockSkew>
- unit
-
この要素の値に割り当てられた時間単位を定義することができます。使用できる値は MICROSECONDS、MILLISECONDS、MINUTES、NANOSECONDS、および SECONDS です。これは 任意 です。デフォルト値は
SECONDSです。
3.1.1.8. IDP SingleSignOnService サブ要素
サブ要素 SingleSignOnService は、IDP のログイン SAML エンドポイントを定義します。クライアントアダプターは、ログイン時にこの要素内の設定を介してフォーマットされた IDP に要求を送信します。
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="post"
bindingUrl="url"/>この要素で定義できる config 属性を以下に示します。
- signRequest
-
クライアントは認証要求に署名する必要がありますか?この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - validateResponseSignature
-
クライアントは、IDP が auhtn 要求から返送されたアサーション応答ドキュメントに署名することを期待する必要がありますか?この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - requestBinding
-
これは IDP との通信に使用される SAML バインディングタイプです。この設定は 任意 です。デフォルト値は
POSTですが、REDIRECTに設定することもできます。 - responseBinding
-
SAML を使用すると、クライアントは、認証応答で使用するバインディングタイプを要求できます。値は
POSTまたはREDIRECTです。この設定は 任意 です。デフォルトでは、クライアントは応答用に特定のバインディングタイプを要求しません。 - assertionConsumerServiceUrl
-
IDP ログインサービスが応答を送信する必要がある Assertion Consumer Service (ACS) のURL。この設定は 任意 です。デフォルトでは、IdP の設定に依存するため、これは未設定です。設定した場合は、
/saml(例:http://sp.domain.com/my/endpoint/for/saml) で終了する必要があります。このプロパティーの値は SAMLAuthnRequestメッセージのAssertionConsumerServiceURL属性で送信されます。通常、このプロパティーにはresponseBinding属性が伴います。 - bindingUrl
- これは、クライアントが要求を送信する IDP ログインサービスの URL です。この設定は 必須 です。
3.1.1.9. IDP SingleLogoutService サブ要素
サブ要素 SingleLogoutService は、IDP のログアウト SAML エンドポイントを定義します。クライアントアダプターは、ログアウト時にこの要素内の設定を介してフォーマットされた IDP に要求を送信します。
<SingleLogoutService validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="redirect"
responseBinding="post"
postBindingUrl="posturl"
redirectBindingUrl="redirecturl">- signRequest
-
クライアントは、IDP に対して行うログアウト要求に署名する必要がありますか?この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - signResponse
-
クライアントが、IDP 要求に送信するログアウト応答に署名する必要があるかどうか。この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - validateRequestSignature
-
クライアントが、IDP からの署名済みログアウト要求ドキュメントを期待する必要があるかどうか。この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - validateResponseSignature
-
クライアントが、IDPからの署名済みログアウト応答ドキュメントを期待する必要があるか。この設定は 任意 です。デフォルトは、任意の IDP の
signaturesRequired要素の値に設定されます。 - requestBinding
-
これは、IDP への SAML 要求の通信に使用される SAML バインディングタイプです。この設定は 任意 です。デフォルト値は
POSTですが、REDIRECT に設定することもできます。 - responseBinding
-
これは、IDP への SAML 応答の通信に使用される SAML バインディングタイプです。値は
POSTまたはREDIRECTです。この設定は 任意 です。デフォルト値はPOSTですが、REDIRECTに設定することもできます。 - postBindingUrl
-
これは、POST バインディングの使用時に IDP のログアウトサービスの URL です。この設定は、
POSTバインディングを使用する場合に 必須 になります。 - redirectBindingUrl
- これは、REDIRECT バインディングの使用時に IDP のログアウトサービスの URL です。この設定は、REDIRECT バインディングを使用する場合に 必須 になります。
3.1.1.10. IDP キーサブ要素
IDP のキーサブ要素は、IDP によって署名されたドキュメントの検証に使用する証明書またはパブリックキーの定義にのみ使用されます。これは、SP の Keys 要素 と同じ方法で定義されます。ただし、証明書または公開鍵参照を定義するだけで十分です。IDP と SP の両方が Red Hat Single Sign-On サーバーおよびアダプターによって実現される場合、署名の検証にキーを指定する必要はありません。以下を参照してください。
SP と IDP の両方が Red Hat Single Sign-On によって実装されている場合、公開された証明書から IDP 署名検証用の公開鍵を自動的に取得するように SP を設定することができます。これは、キーサブ要素の署名検証キーの宣言をすべて削除することによって行われます。キーサブ要素が空のままになる場合は、完全に省略できます。次に、キーは SP により SAML 記述子から自動的に取得されます。これは、「IDP SingleSignOnService サブ要素」 で指定された SAML エンドポイント URL から派生します。SAML 記述子取得に使用される HTTP クライアントの設定は、通常、追加設定は必要ありませんが、IDP HttpClient サブ要素 で設定することもできます。
署名の検証に複数のキーを指定することもできます。これは、signing 属性が true に設定されている Keys サブ要素内で複数の Key 要素を宣言することによって行われます。これは、IDP 署名鍵がローテートされる場合などに便利です。通常、新しい SAML プロトコルメッセージとアサーションが新しいキーで署名される際に移行期間がありますが、以前のキーで署名されたものは引き続き受け入れる必要があります。
署名検証用のキーの自動取得および追加の静的署名検証キーの定義の両方を行うように Red Hat Single Sign-On を設定することはできません。
<IDP entityID="idp">
...
<Keys>
<Key signing="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>3.1.1.11. IDP HttpClient サブ要素
HttpClient オプションのサブ要素は、enabled の場合に、IDP の SAML 記述子で IDP 署名検証用の公開鍵を含む証明書を自動的に取得するために使用される HTTP クライアントのプロパティーを定義します。
<HttpClient connectionPoolSize="10"
disableTrustManager="false"
allowAnyHostname="false"
clientKeystore="classpath:keystore.jks"
clientKeystorePassword="pwd"
truststore="classpath:truststore.jks"
truststorePassword="pwd"
proxyUrl="http://proxy/" />- connectionPoolSize
-
この設定オプションでは、Red Hat Single Sign-On サーバーへプールする接続の数を定義します。これは 任意 です。デフォルト値は
10です。 - disableTrustManager
-
Red Hat Single Sign-On サーバーに HTTPS が必要で、この設定オプションが
trueに設定されている場合は、トラストストアを指定する必要はありません。この設定は開発時のみ使用してください。これは SSL 証明書の検証を無効にするため、実稼働環境では 使用しないで ください。これは 任意 です。デフォルト値はfalseです。 - allowAnyHostname
-
Red Hat Single Sign-On サーバーに HTTPS が必要で、この設定オプションが
trueに設定されている場合、Red Hat Single Sign-On サーバーの証明書はトラストストア経由で検証されますが、ホスト名の検証は行われません。この設定は開発時のみ使用してください。これは SSL 証明書の検証を一部無効にするため、実稼働環境では 使用しないで ください。この設定は、テスト環境で役に立ちます。これは 任意 です。デフォルト値はfalseです。 - truststore
-
値は、トラストストアファイルへのファイルパスです。
classpath:でパスを接頭辞にすると、代わりにデプロイメントのクラスパスからトラストストアが取得されます。Red Hat Single Sign-On サーバーへの送信 HTTPS 通信に使用されます。HTTPS 要求を実行するクライアントでは、通信先のサーバーのホストを確認する方法が必要です。これは、トラストストアが行なうことです。キーストアには、1 つ以上の信頼できるホスト証明書または認証局が含まれます。Red Hat Single Sign-On サーバーの SSL キーストアの公開証明書を抽出して、このトラストストアを作成できます。これは、disableTrustManagerがtrueでない限り 必須 になります。 - truststorePassword
-
トラストストアのパスワード。これは、
トラストストアが設定され、トラストストアにパスワードが必要な場合は 必須 になります。 - clientKeystore
- これはキーストアファイルに対するファイルパスです。このキーストアには、アダプターが Red Hat Single Sign-On サーバーに対して HTTPS を要求する際に双方向 SSL のクライアント証明書が含まれます。これは 任意 です。
- clientKeystorePassword
-
クライアントキーストアおよびクライアントの鍵のパスワード。これは、
clientKeystoreが設定されている場合は REQUIRED になります。 - proxyUrl
- HTTP 接続に使用する HTTP プロキシーの URL。これは 任意 です。
3.1.2. JBoss EAP Adapter
JBoss EAP にデプロイされた WAR アプリケーションのセキュリティーを保護できるようにするには、Red Hat Single Sign-On アダプターサブシステムをインストールおよび設定する必要があります。
次に、WAR で keycloak 設定ファイル /WEB-INF/keycloak-saml.xml を指定し、auth-method を web.xml 内の Keycloak-SAML に変更します。本セクションでは、両方の方法を説明します。
3.1.2.1. アダプターのインストール
各アダプターは、Red Hat Single Sign-On のダウンロードサイトの個別ダウンロードです。
JBoss EAP 7.x にインストールします。
$ cd $EAP_HOME $ unzip rh-sso-saml-eap7-adapter.zip
JBoss EAP 6.x にインストールします。
$ cd $EAP_HOME $ unzip rh-sso-saml-eap6-adapter.zip
これらの zip ファイルは、JBoss EAP ディストリビューション内に JBoss EAP SAML アダプターに固有の新しい JBoss モジュールを作成します。
モジュールを追加したら、アプリケーションサーバーのサーバー設定 (domain.xml または standalone.xml) 内で Red Hat Single Sign-On SAML サブシステムを有効にする必要があります。
サーバー設定の変更に役立つ CLI スクリプトがあります。サーバーを起動し、サーバーの bin ディレクトリーからスクリプトを実行します。
JBoss EAP 7.1 以降
$ cd $JBOSS_HOME $ ./bin/jboss-cli.sh -c --file=bin/adapter-elytron-install-saml.cli
JBoss EAP 7.0 および EAP 6.4
$ cd $JBOSS_HOME $ ./bin/boss-cli.sh -c --file=bin/adapter-install-saml.cli
JBoss EAP 7.1 以上でも従来の非 Elytron アダプターを使用できます。つまり、これらのバージョンでも adapter-install-saml.cli を使用できます。ただし、新しい Elytron アダプターを使用することが推奨されます。
スクリプトは、以下に説明するように、拡張機能、サブシステム、およびオプションの security-domain を追加します。
<server xmlns="urn:jboss:domain:1.4">
<extensions>
<extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
...
</extensions>
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1"/>
...
</profile>
セキュアな Web 層で作成されたセキュリティーコンテキストを、呼び出している EJB (他の EE コンポーネント) に伝播する必要がある場合には、keycloak セキュリティードメインを EJB およびその他のコンポーネントと併用する必要があります。それ以外の場合、この設定は任意です。
<server xmlns="urn:jboss:domain:1.4">
<subsystem xmlns="urn:jboss:domain:security:1.2">
<security-domains>
...
<security-domain name="keycloak">
<authentication>
<login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
flag="required"/>
</authentication>
</security-domain>
</security-domains>セキュリティーコンテキストは EJB 階層に自動的に伝播されます。
3.1.2.2. JBoss SSO
JBoss EAP は、同じ JBoss EAP インスタンスにデプロイされた web アプリケーションに対するシングルサインオンのサポートが組み込まれています。これは、Red Hat Single Sign-On を使用する場合に有効にしないでください。
3.1.3. RPM からの JBoss EAP アダプターのインストール
RPM から EAP 7 アダプターをインストールします。
Red Hat Enterprise Linux 7 では、チャンネル という用語はリポジトリーという用語に置き換えられました。これらの手順では、リポジトリーという用語のみが使用されています。
RPM から EAP 7 アダプターをインストールする前に、JBoss EAP 7 リポジトリーにサブスクライブする必要があります。
前提条件
- Red Hat Subscription Manager を使用して、Red Hat Enterprise Linux システムがお使いのアカウントに登録されている必要があります。詳細は、Red Hat Subscription Management のドキュメント を参照してください。
- すでに別の JBoss EAP リポジトリーにサブスクライブしている場合は、最初にそのリポジトリーからサブスクライブを解除する必要があります。
Red Hat Enterprise Linux 6、7 の場合: Red Hat Subscription Manager を使用して、以下のコマンドで JBoss EAP 7.3 リポジトリーにサブスクライブします。お使いの Red Hat Enterprise Linux のバージョンに応じて、<RHEL_VERSION> を 6 または 7 に置き換えてください。
$ sudo subscription-manager repos --enable=jb-eap-7-for-rhel-<RHEL_VERSION>-server-rpms
Red Hat Enterprise Linux 8 の場合: Red Hat Subscription Manager を使用して、以下のコマンドで JBoss EAP 7.3 リポジトリーにサブスクライブします。
$ sudo subscription-manager repos --enable=jb-eap-7.3-for-rhel-8-x86_64-rpms --enable=rhel-8-for-x86_64-baseos-rpms --enable=rhel-8-for-x86_64-appstream-rpms
以下のコマンドを使用して、SAML の EAP 7 アダプターをインストールします。
$ sudo yum install eap7-keycloak-saml-adapter-sso7_4
または、Red Hat Enterprise Linux 8 に以下のいずれかを使用します。
$ sudo dnf install eap7-keycloak-adapter-sso7_4
RPM インストールのデフォルトの EAP_HOME パスは /opt/rh/eap7/root/usr/share/wildfly です。
適切なモジュールインストールスクリプトを実行します。
SAML モジュールには、以下のコマンドを入力します。
$ $EAP_HOME/bin/jboss-cli.sh -c --file=$EAP_HOME/bin/adapter-install-saml.cli
インストールが完了しました。
RPM から EAP 6 アダプターをインストールします。
Red Hat Enterprise Linux 7 では、チャンネル という用語はリポジトリーという用語に置き換えられました。これらの手順では、リポジトリーという用語のみが使用されています。
RPM から EAP 6 アダプターをインストールする前に、JBoss EAP 6 リポジトリーにサブスクライブする必要があります。
前提条件
- Red Hat Subscription Manager を使用して、Red Hat Enterprise Linux システムがお使いのアカウントに登録されている必要があります。詳細は、Red Hat Subscription Management のドキュメント を参照してください。
- すでに別の JBoss EAP リポジトリーにサブスクライブしている場合は、最初にそのリポジトリーからサブスクライブを解除する必要があります。
Red Hat Subscription Manager を使用して、以下のコマンドを使用して JBoss EAP 6 リポジトリーにサブスクライブします。お使いの Red Hat Enterprise Linux のバージョンに応じて、<RHEL_VERSION> を 6 または 7 に置き換えてください。
$ sudo subscription-manager repos --enable=jb-eap-6-for-rhel-<RHEL_VERSION>-server-rpms
以下のコマンドを使用して、SAML 用の EAP 6 アダプターをインストールします。
$ sudo yum install keycloak-saml-adapter-sso7_4-eap6
RPM インストールのデフォルトの EAP_HOME パスは /opt/rh/eap6/root/usr/share/wildfly です。
適切なモジュールインストールスクリプトを実行します。
SAML モジュールには、以下のコマンドを入力します。
$ $EAP_HOME/bin/jboss-cli.sh -c --file=$EAP_HOME/bin/adapter-install-saml.cli
インストールが完了しました。
3.1.3.1. WAR ごとの設定
このセクションでは、WAR パッケージ内に設定ファイルを追加してファイルを編集することにより、WAR を直接保護する方法について説明します。
最初に、WAR の WEB-INF ディレクトリーに keycloak-saml.xml アダプター設定ファイルを作成する必要があります。この設定ファイルの形式は、「一般的なアダプター設定」セクションで説明されています。
次に、web.xml で auth-method を KEYCLOAK-SAML に設定する必要があります。また、標準のサーブレットセキュリティーを使用して URL に role-base 制約を指定する必要があります。以下は web.xml ファイルの例です。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<security-constraint>
<web-resource-collection>
<web-resource-name>Admins</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Customers</web-resource-name>
<url-pattern>/customers/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>KEYCLOAK-SAML</auth-method>
<realm-name>this is ignored currently</realm-name>
</login-config>
<security-role>
<role-name>admin</role-name>
</security-role>
<security-role>
<role-name>user</role-name>
</security-role>
</web-app>
auth-method 設定を除くすべての標準サーブレット設定。
3.1.3.2. Red Hat Single Sign-On SAML サブシステムを使用した WAR のセキュリティー保護
Red Hat Single Sign-On で WAR を保護するために、WAR をオープンする必要はありません。代わりに、Red Hat Single Sign-On SAML Adapter Subsystem 経由で外部からセキュリティーを確保することもできます。KEYCLOAK-SAML を auth-method として指定する必要はありませんが、web.xml で security-constraints を定義する必要があります。ただし、WEB-INF/keycloak-saml.xml ファイルを作成する必要がありません。このメタデータは、サーバーの サブシステム設定 domain.xml または standalone.xml の XML 内で定義されます。
<extensions>
<extension module="org.keycloak.keycloak-saml-adapter-subsystem"/>
</extensions>
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
<secure-deployment name="WAR MODULE NAME.war">
<SP entityID="APPLICATION URL">
...
</SP>
</secure-deployment>
</subsystem>
</profile>
secure-deployment name 属性は、セキュリティーを保護する WAR を識別します。この値は web.xml に .war を追加した module-name です。残りの設定は、一般的なアダプター設定 で定義される keycloak-saml.xml 設定と同じ XML 構文を使用します。
設定例:
<subsystem xmlns="urn:jboss:domain:keycloak-saml:1.1">
<secure-deployment name="saml-post-encryption.war">
<SP entityID="http://localhost:8080/sales-post-enc/"
sslPolicy="EXTERNAL"
nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
logoutPage="/logout.jsp"
forceAuthentication="false">
<Keys>
<Key signing="true" encryption="true">
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
<Certificate alias="http://localhost:8080/sales-post-enc/"/>
</KeyStore>
</Key>
</Keys>
<PrincipalNameMapping policy="FROM_NAME_ID"/>
<RoleIdentifiers>
<Attribute name="Role"/>
</RoleIdentifiers>
<IDP entityID="idp">
<SingleSignOnService signRequest="true"
validateResponseSignature="true"
requestBinding="POST"
bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
<SingleLogoutService
validateRequestSignature="true"
validateResponseSignature="true"
signRequest="true"
signResponse="true"
requestBinding="POST"
responseBinding="POST"
postBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"
redirectBindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
<Keys>
<Key signing="true" >
<KeyStore resource="/WEB-INF/keystore.jks" password="store123">
<Certificate alias="saml-demo"/>
</KeyStore>
</Key>
</Keys>
</IDP>
</SP>
</secure-deployment>
</subsystem>3.1.4. Java Servlet Filter Adapter
サーブレットプラットフォーム用のアダプターを持たない Java サーブレットアプリケーションで SAML を使用する場合は、Red Hat Single Sign-On が持つサーブレットフィルターアダプターを使用することを選択できます。このアダプターは、他のアダプターとは異なります。「一般的なアダプター設定」セクションに定義されているように /WEB-INF/keycloak-saml.xml ファイルを指定する必要がありますが、web.xml でセキュリティー制約を定義する必要はありません。代わりに、Red Hat Single Sign-On サーブレットフィルターアダプターを使用してフィルターマッピングを定義し、セキュリティーを保護する url パターンを保護します。
Backchannel ログアウトの動作は、標準アダプターとは少々異なります。HTTP セッションを無効にする代わりに、セッション ID をログアウトとしてマークします。セッション ID に基づいて http セッションを任意に無効にする方法はありません。
SAML フィルターを使用するクラスター化されたアプリケーションがある場合は、バックチャネルログアウトは現在機能しません。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<module-name>customer-portal</module-name>
<filter>
<filter-name>Keycloak Filter</filter-name>
<filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Keycloak Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>Red Hat Single Sign-On フィルターには、他のアダプターと同じ設定パラメーターがあります。ただし、これらはコンテキストパラメーターではなく、フィルター init パラメーターとして定義する必要があります。
さまざまな異なる安全な URL パターンと安全でない URL パターンがある場合は、複数のフィルターマッピングを定義できます。
/saml に対応するフィルターマッピングがある。このマッピングは、すべてのサーバーコールバックに対応します。
IdP で SP を登録する場合は、http[s]://hostname/{context-root}/saml を Assert Consumer Service URL および Single Logout Service URL として登録する必要があります。
このフィルターを使用するには、この maven アーティファクトを WAR pom に組み込みます。
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-saml-servlet-filter-adapter</artifactId> <version>9.0.17.redhat-00001</version> </dependency>
マルチテナント を使用するには、keycloak.config.resolver パラメーターをフィルターパラメーターとして渡す必要があります。
<filter>
<filter-name>Keycloak Filter</filter-name>
<filter-class>org.keycloak.adapters.saml.servlet.SamlFilter</filter-class>
<init-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.SamlMultiTenantResolver</param-value>
</init-param>
</filter>3.1.5. ID プロバイダーを使用した登録
サーブレットベースのアダプタごとに、アサートコンシューマサービス URL およびシングルログアウトサービスに登録するエンドポイントは/saml が追加されたサーブレットアプリケーションのベース URL、つまり https://example.com/contextPath/saml である必要があります。
3.1.6. ログアウト
Web アプリケーションからログアウトする方法は複数あります。Java EE サーブレットコンテナーでは、HttpServletRequest.logout() を呼び出すことができます。他のブラウザーアプリケーションでは、ブラウザーをセキュリティー制約のある Web アプリケーションの任意の URL に指定し、クエリーパラメーター GLO (つまり http://myapp?GLO=true) に渡すことができます。ブラウザーに SSO セッションがある場合は、ログアウトします。
3.1.6.1. クラスター化された環境でログアウト
SAML アダプターは内部的には、SAML セッションインデックス、プリンシパル名 (既知の場合)、および HTTP セッション ID 間のマッピングを保存します。このマッピングは、分散可能なアプリケーションのクラスター全体で、JBoss アプリケーションサーバーファミリー (WildFly 10/11、EAP 6/7) で維持できます。前提条件として、HTTP セッションをクラスター全体に分散する必要があります (つまり、アプリケーションはアプリケーションの web.xml の <distributable/> タグでマークされます)。
この機能を有効にするには、以下のセクションを /WEB_INF/web.xml ファイルに追加します。
EAP 7 (WildFly 10/11) の場合:
<context-param>
<param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
<param-value>org.keycloak.adapters.saml.wildfly.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>EAP 6 の場合:
<context-param>
<param-name>keycloak.sessionIdMapperUpdater.classes</param-name>
<param-value>org.keycloak.adapters.saml.jbossweb.infinispan.InfinispanSessionCacheIdMapperUpdater</param-value>
</context-param>
デプロイメントのセッションキャッシュの名前が deployment-cache の場合、SAML マッピングに使用されるキャッシュの名前が deployment-cache.ssoCache になります。キャッシュの名前は、コンテキストパラメーター keycloak.sessionIdMapperUpdater.infinispan.cacheName で上書きできます。キャッシュを含むキャッシュコンテナーはデプロイメントセッションキャッシュを含むものと同じですが、コンテキストパラメーター keycloak.sessionIdMapperUpdater.infinispan.containerName で上書きできます。
デフォルトでは、SAML マッピングキャッシュの設定はセッションキャッシュから派生します。この設定は、他のキャッシュと同じように、サーバーのキャッシュ設定セクションで手動でオーバーライドできます。
現在、信頼できるサービスを提供するには、SAML セッションキャッシュにレプリケートされたキャッシュを使用することが推奨されます。分散キャッシュを使用すると、SAML のログアウト要求が HTTP セッションマッピングへの SAML セッションインデックスにアクセスできないノードに到達する結果となり、ログアウトに失敗する可能性があります。
3.1.6.2. クロス DC シナリオにおけるログアウト
DC の間のシナリオは、WildFly 10 以降および EAP 7 以降にのみ適用されます。
複数のデータセンターにまたがるセッションを処理するには、特別な処理が必要です。以下のシナリオを見てみましょう。
- ログイン要求は、データセンター 1 のクラスター内で処理されます。
- 管理者は、特定の SAML セッションに対してログアウト要求を発行し、要求はデータセンター 2 に送信されます。
データセンター 2 は、データセンター 1 (および HTTP セッションを共有する他のすべてのデータセンター) にあるすべてのセッションをログアウトする必要があります。
この場合、上記 の SAML セッションキャッシュを個別のクラスター内だけでなく、スタンドアロン Infinispan/JDG サーバーを介して すべてのデータセンターにレプリケートする必要があります。
- スタンドアロン Infinispan/JDG サーバーにキャッシュを追加する必要があります。
- 各 SAML セッションキャッシュのリモートストアとして、以前のアイテムからのキャッシュを追加する必要があります。
デプロイメント中にリモートストアが SAML セッションキャッシュに存在することが検出されると、変更がないか監視され、それに応じてローカル SAML セッションキャッシュが更新されます。
3.1.7. assertion 属性の取得
正常な SAML ログインの後、アプリケーションコードが SAML アサーションで渡される属性値を取得することをお勧めします。HttpServletRequest.getUserPrincipal() は、org.keycloak.adapters.saml.SamlPrincipal と呼ばれる Red Hat Single Sign-On 固有のクラスに型変換できる Principal オブジェクトを返します。このオブジェクトを使用すると、raw アサーションを確認でき、属性値を検索するための便利な関数もあります。
package org.keycloak.adapters.saml;
public class SamlPrincipal implements Serializable, Principal {
/**
* Get full saml assertion
*
* @return
*/
public AssertionType getAssertion() {
...
}
/**
* Get SAML subject sent in assertion
*
* @return
*/
public String getSamlSubject() {
...
}
/**
* Subject nameID format
*
* @return
*/
public String getNameIDFormat() {
...
}
@Override
public String getName() {
...
}
/**
* Convenience function that gets Attribute value by attribute name
*
* @param name
* @return
*/
public List<String> getAttributes(String name) {
...
}
/**
* Convenience function that gets Attribute value by attribute friendly name
*
* @param friendlyName
* @return
*/
public List<String> getFriendlyAttributes(String friendlyName) {
...
}
/**
* Convenience function that gets first value of an attribute by attribute name
*
* @param name
* @return
*/
public String getAttribute(String name) {
...
}
/**
* Convenience function that gets first value of an attribute by attribute name
*
*
* @param friendlyName
* @return
*/
public String getFriendlyAttribute(String friendlyName) {
...
}
/**
* Get set of all assertion attribute names
*
* @return
*/
public Set<String> getAttributeNames() {
...
}
/**
* Get set of all assertion friendly attribute names
*
* @return
*/
public Set<String> getFriendlyNames() {
...
}
}3.1.8. エラー処理
Red Hat Single Sign-On には、サーブレットベースのクライアントアダプターに対するエラー処理機能があります。認証でエラーが発生した場合、クライアントアダプターは HttpServletResponse.sendError() を呼び出します。web.xml ファイル内に error-page を設定して、必要なエラーを処理できます。クライアントアダプターは 400、401、403、および 500 のエラーを出力できます。
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
クライアントアダプターは、取得可能なHttpServletRequest 属性も設定します。属性名は org.keycloak.adapters.spi.AuthenticationError です。このオブジェクトは、org.keycloak.adapters.saml.SamlAuthenticationError に型変換されます。このクラスは、何が起こったのかを正確に知ることができます。この属性が設定されていない場合、アダプターはエラーコードを担当しませんでした。
public class SamlAuthenticationError implements AuthenticationError {
public static enum Reason {
EXTRACTION_FAILURE,
INVALID_SIGNATURE,
ERROR_STATUS
}
public Reason getReason() {
return reason;
}
public StatusResponseType getStatus() {
return status;
}
}3.1.9. トラブルシューティング
問題のトラブルシューティングを行う最適な方法として、クライアントアダプターと Red Hat Single Sign-On サーバーの両方で SAML のデバッグをオンにすることができます。ロギングフレームワークを使用して、org.keycloak.saml パッケージのログレベルを DEBUG に設定します。これをオンにすると、サーバーとの間で送受信される SAML 要求および応答ドキュメントを確認できます。
3.1.10. マルチテナンシー
SAML は マルチテナント の OIDC と同じ機能を提供します。つまり、1 つのターゲットアプリケーション (WAR) は複数の Red Hat Single Sign-On レルムでセキュリティー保護されます。レルムは、同じ Red Hat Single Sign-On インスタンスまたは別のインスタンスに配置できます。
これを実行するには、複数の keycloak-saml.xml アダプター設定ファイルが必要です。
異なるアダプター設定ファイルを含む WAR の複数のインスタンスを異なるコンテキストパスにデプロイすることができますが、これは不便である可能性があるため、コンテキストパス以外のものに基づいてレルムを選択することをお勧めします。
Red Hat Single Sign-On では、カスタム設定リゾルバーの設定が可能で、これにより、リクエストごとに使用するアダプター設定を選択できるようになります。SAML では、設定はログイン処理のみに関連し、ユーザーがログインするとセッションが認証され、返された keycloak-saml.xml が異なるかどうかは問題ありません。そのため、同じセッションで同じ設定を返すことが、適切な方法になります。
そのためには、org.keycloak.adapters.saml.SamlConfigResolver の実装を作成します。以下の例では、Host ヘッダーを使用して適切な設定を検索し、アプリケーションの Java クラスパスから関連する要素を読み込みます。
package example;
import java.io.InputStream;
import org.keycloak.adapters.saml.SamlConfigResolver;
import org.keycloak.adapters.saml.SamlDeployment;
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.saml.common.exceptions.ParsingException;
public class SamlMultiTenantResolver implements SamlConfigResolver {
@Override
public SamlDeployment resolve(HttpFacade.Request request) {
String host = request.getHeader("Host");
String realm = null;
if (host.contains("tenant1")) {
realm = "tenant1";
} else if (host.contains("tenant2")) {
realm = "tenant2";
} else {
throw new IllegalStateException("Not able to guess the keycloak-saml.xml to load");
}
InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak-saml.xml");
if (is == null) {
throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak-saml.xml");
}
ResourceLoader loader = new ResourceLoader() {
@Override
public InputStream getResourceAsStream(String path) {
return getClass().getResourceAsStream(path);
}
};
try {
return new DeploymentBuilder().build(is, loader);
} catch (ParsingException e) {
throw new IllegalStateException("Cannot load SAML deployment", e);
}
}
}
また、web.xml のコンテキストパラメーター keycloak.config.resolver で使用する SamlConfigResolver 実装を構成する必要があります。
<web-app>
...
<context-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.SamlMultiTenantResolver</param-value>
</context-param>
</web-app>