ファイルを作成し、そのファイルにSPIのクラスを追加します。インターフェイスを作成します。通常、ユースケースで必要なビジネスメソッドが含まれます。ライフサイクル毎にスコープされます)。最後に、サービス・プロバイダー・インターフェイスの章で説明したのと同じ方法で、プロバイダーを実装する必要があります。配布物のサンプルを参照してください。そこには、上記と同じようなSPIのサンプルが示されています。追加のリソースカスタムRESTエンドポイントカスタムJPAエンティティーをKeycloakデータモデルへ追加Keycloakデータモデルが要求するソリューションとは厳密には違っていた場合やコアの機能をKeycloakに追加する場合、もしくは独自のRESTエンドポイントがある場合、Keycloakデータモデルの拡張が検討した方がいいかもしれません。追加することが可能になりました。実装する必要があります。よって、カスタムJPAエンティティーのリストを返し、Liquibaseの変更履歴の場所とidを提供することができます。実装サンプルは、以下のとおりになります。これはサポートされていないAPIです。使用することはできますが、警告なしで削除または変更される可能性があります。クラスによって表現された単一のJPAエンティティーを追加しました。取得し、その上でDBオペレーションを呼び出すことができます。メソッドは、Liquibaseによるエンティティーの自動更新をサポートするために重要です。データベース・スキーマを更新するためのフレームワークです。これはKeycloakで内部的に使用され、DBスキーマを作成してバージョン間でDBスキーマを更新します。これを同じように使用して、エンティティーの変更履歴を作成する必要があるかもしれません。独自のLiquibaseの変更履歴のバージョニングはKeycloakのバージョンとは異なる独立したものであることに注意してください。新しいKeycloakバージョンへ更新した際、同時にスキーマを更新する必要はありません。その逆の場合でも、Keycloakバージョンを更新しなくてもスキーマを更新することができます。同じJAR内に含まれていなければなりません)になります)を追加して再起動するだけで、スキーマのDB更新のトリガーとなります。起動時に、DBスキーマが自動的に更新されます。サンプル内のサンプル配布物を参照してください。サンプルが示されています。Liquibase変更履歴に変更を加えたりDBの更新をトリガーにする前に、必ずデータベースをバックアップするようにしてください。認証SPIKeycloakには、ケルベロス、パスワード、OTPなどのさまざまな認証機構が用意されています。これらの機構は、要件をすべて満たしているわけではなく、独自のカスタムプラグインを必要とする場合もあります。Keycloakは、新しいプラグインの作成に使用できる認証SPIを提供します。管理コンソールは、これらの新しい機構の適用、順序、設定をサポートしています。Keycloakでは簡単な登録フォームもサポートされます。このフォームのさまざまな要素を有効、無効にすることができます。reCAPTCHAのサポートをオフにすることができます。同じ認証SPIを使用して、他のページを登録フローに追加したり、それを完全に再実装することができます。追加のきめ細かいSPIを使用して、組み込みの登録フォームに特定のバリデーションやユーザー拡張機能を追加することもできます。Keycloakでの必須アクションとは、認証後にユーザーが実行する必要のあるアクションのことです。アクションが実行された後、ユーザーはそのアクションを再実行する必要はありません。Keycloakには、"パスワードリセット"などの必須アクションがいくつか組み込まれています。パスワードリセットは、ユーザーがログインした後にパスワードを変更するよう強制します。必須アクションを作成してプラグインすることができます。オーセンティケーターまたは必須アクションの実装で、ユーザーのアイデンティティーをリンク/確立するためのメタデータ属性として一部のユーザー属性を使用している場合は、ユーザーが属性を編集できず、対応する属性が読み取り専用であることを確認してください。用語まず最初に、認証SPIについて学ぶには、それを説明するためのいくつかの用語を確認していきます。認証フローフローは、ログインまたは登録中に必ず発生するすべての認証のためのコンテナーです。管理コンソールの認証ページに移動すると、システム内で定義されたすべてのフローと、どのようなオーセンティケーターで構成されているかが表示されます。フローには、他のフローを含めることができます。ブラウザーのログイン、ダイレクト・グラント・アクセス、および登録用に、新しい異なるフローをバインドすることもできます。オーセンティケーターオーセンティケーターは、フロー内で認証またはアクションを実行するためのロジックを保持する、プラグイン可能なコンポーネントです。通常は、シングルトンです。エグゼキューションエグゼキューションは、オーセンティケーターをフローにバインドしたり、オーセンティケーターの設定にオーセンティケーターをバインドするオブジェクトです。フローには、エグゼキューション・エントリーが含まれます。エグゼキューションのRequirementエグゼキューションごとに、オーセンティケーターがフロー内でどのように動作するかを定義します。要件には、オーセンティケーターがenabled、disabled、conditional、required、またはalternativeのいずれであるかを定義します。alternativeの要件は、オーセンティケーターがそれが入っているフローを検証するのに十分であることを意味しますが、必須ではありません。組み込みのブラウザーフローでは、Cookie認証、アイデンティティー・プロバイダー・リダイレクター、およびフォーム・サブフロー内のすべてのオーセンティケーターのセットがすべてalternativeです。これらは上から下へ順番に実行されるため、そのうちの1つが成功した場合、フローは成功し、フロー(またはサブフロー)での後続のエグゼキューションは評価されません。オーセンティケーター設定このオブジェクトは、認証フロー内の特定のエグゼキューションに対してのオーセンティケーターの設定を定義します。エグゼキューションごとに異なる設定を持つことができます。必須アクション認証が完了した後、ユーザーは、ログインを許可される前に完了する必要がある1つ以上の1回限りのアクションを行う場合があります。ユーザーは、OTPトークン・ジェネレーターをセットアップするか、期限切れのパスワードをリセットするか、利用規約文書に同意する必要があります。アルゴリズムの概要これがブラウザー・ログインでどのように機能するか説明します。以下のフロー、エグゼキューション、サブフローを想定してみましょう。REQUIREDフォームのトップレベルには、すべてが選択的に必要な3つのエグゼキューションがあります。これらのいずれかが成功した場合、ほかは実行する必要がないことを意味します。Cookieセットまたはケルベロスのログインが成功した場合、Username/Passwordフォームは実行されません。クライアントが最初にKeycloakにリダイレクトし、ユーザーを認証するまでの手順を説明します。ConnectまたはSAMLプロトコル・プロバイダーは、関連するデータを展開し、クライアントと署名を検証します。AuthenticationSessionModelを作成します。ブラウザーフローを検索し、フローの実行を開始します。このフローは、Cookieのエグゼキューションを参照し、それがALTERNATIVEであることを確認します。Cookieプロバイダーをロードし、ユーザーが認証セッションに関連付けられていることをCookieプロバイダーが要求しているかどうかを確認します。Cookieプロバイダーには、ユーザーは必要ありません。あれば、フローは中断され、ユーザーにはエラー画面が表示されます。その後、Cookieプロバイダーが実行されます。Cookieセットがあるかどうかを確認することです。CookieとUserSessionModelが検証され、AuthenticationSessionModelに関連付けられます。Cookieが存在し、検証が済むと、Cookieプロバイダーはsuccess()ステータスを返します。Cookieプロバイダーは成功を返すと、このフローのレベルでのそれぞれのエグゼキューションはALTERNATIVEであるため、他のエグゼキューションは実行されず、ログインに成功します。Cookieが存在しない場合は、Cookieプロバイダーはattempted()のステータスを返します。この場合、エラー状態ではありませんが、成功でもないことを意味します。プロバイダーは試行しましたが、リクエストはこのオーセンティケーターを処理するようには設定されていませんでした。次に、フローはケルベロス・エグゼキューションを参照します。これもALTERNATIVEです。ケルベロス・プロバイダーもまた、このプロバイダーを実行されるように、ユーザーに設定されていることと、AuthenticationSessionModelに関連付けられていることを要求しません。ケルベロスは、SPNEGOブラウザー・プロトコルを使用します。これは、サーバーとクライアントがネゴシエーション・ヘッダーを交換する一連のチャレンジ/レスポンスを必要とします。ケルベロス・プロバイダーは、ネゴシエーション・ヘッダーをまったく見ないため、これがサーバーとクライアント間の最初のやりとりであることを前提とします。したがって、クライアントへのHTTPチャレンジ・レスポンスを作成し、forceChallenge()ステータスを設定します。forceChallenge()は、このHTTPレスポンスがフローで無視できないため、クライアントに返す必要があることを意味します。代わりにプロバイダーがchallenge()ステータスを返した場合、フローは他のすべてのALTERNATIVEが試行されるまでチャレンジ・レスポンスを保持します。したがって、この初期フェーズでフローが停止し、チャレンジ・レスポンスがブラウザーに返されます。ブラウザーが成功のネゴシエーション・ヘッダーで応答すると、プロバイダーはユーザーをAuthenticationSessionに関連付け、フローが終了します(このフローのレベルの残りのエグゼキューションはALTERNATIVEであるため)。それ以外の場合は、ケルベロス・プロバイダーは、attempted()を設定し、フローを続行します。次のエグゼキューションは、Formsと呼ばれるサブフローです。このサブフローのエグゼキューションがロードされ、同じ処理ロジックが発生します。Formsサブフローの最初のエグゼキューションは、UsernamePasswordプロバイダーです。このプロバイダーも、ユーザーがフローに関連付けられていることを要求しません。このプロバイダーは、チャレンジHTTPレスポンスを作成し、そのステータスをchallenge()に設定します。このエグゼキューションは必須なので、フローはこのチャレンジを優先し、ブラウザーにHTTPレスポンスを返します。HTMLページのレンダリングです。ユーザーは、ユーザー名とパスワードを入力し、送信をクリックします。このHTTPリクエストは、UsernamePasswordプロバイダーに送信されます。ユーザーが無効なユーザー名またはパスワードを入力した場合、新しいチャレンジ・レスポンスが作成され、このエグゼキューションにfailureChallenge()のステータスが設定されます。failureChallenge()は、チャレンジがあるが、エラーログにエラーとして記録する必要があることを意味します。このエラーログは、ログイン失敗回数の多いアカウントまたはIPアドレスをロックするのに使用できます。ユーザー名とパスワードが有効な場合、プロバイダーはUserModelをAuthenticationSessionModelに関連付け、success()ステータスを返します。OTPと呼ばれるサブフローです。このサブフローのエグゼキューションがロードされ、同じ処理ロジックが発生します。そのRequirementはConditionalです。これは、フローが最初に含まれるすべてのConditionalエグゼキューターを評価することを意味します。実装する必要があります。メソッドを呼び出し、それらすべてがtrueと評価されると、必要なサブフローであるかのように動作します。ない場合は、無効なサブフローであるかのように動作します。Conditionalオーセンティケーターはこの目的にのみ使用され、オーセンティケーターとしては使用されません。評価した場合でも、フローまたはサブフローが成功としてマークされないことを意味します。Conditionalオーセンティケーターのみを持つConditionalサブフローのみを含むフローでは、ユーザーはログインできません。Configuredです。このプロバイダーでは、ユーザーがフローに関連付けられている必要があります。UsernamePasswordプロバイダーは既にユーザーをフローに関連付けているため、このRequirementは満たされています。メソッドを評価します。メソッドはtrueに評価されます。メソッドがtrueと評価されます。次のエグゼキューションは、OTPフォームです。このプロバイダーでも、ユーザーがフローに関連付けられている必要があります。UsernamePasswordプロバイダーがすでにユーザーをフローに関連付けているため、この要件は満たされます。このプロバイダーは、ユーザーが必須であることから、ユーザーがこのプロバイダーを使用するように設定されているかを求められます。ユーザーが設定されていない場合、フローは認証が完了した後にユーザーが実行する必要のある必須アクションを設定します。OTPの場合、これはOTP設定ページを意味します。ユーザーが設定されている場合、ユーザーはOTPコードを入力するよう求められます。OTPサブフローが必須に設定されていない限り、ユーザーにはOTPログインページが表示されません。フローが完了すると、認証プロセッサーはUserSessionModelを作成し、それをAuthenticationSessionModelに関連付けます。その後、ユーザーはログイン前に必須アクションを完了する必要があるかどうかを確認します。それぞれの必須アクションのevaluateTriggers()メソッドが呼び出されます。これにより、必須アクション・プロバイダーは、アクションが実行されるトリガーとなる可能性があるかを判断できます。レルムにパスワード有効期限ポリシーがある場合、このメソッドによってトリガーされる可能性があります。ユーザーに関連付けられた各必須アクションにあるrequiredActionChallenge()メソッドが呼び出されます。ここでプロバイダーは、必須アクションのページをレンダリングするHTTPレスポンスをセットアップします。これは、チャレンジ・ステータスを設定することで実行されます。必須アクションが最終的に成功すると、ユーザーの必須アクションリストから必須アクションが削除されます。すべての必須アクションが解決した後、ユーザーはようやくログインしたことになります。オーセンティケーターSPIのウォークスルーこのセクションでは、オーセンティケーター・インターフェイスについて説明します。これを説明するために、"あなたの母親の旧姓は何ですか?"のような秘密の質問にユーザーが回答を入力する必要のあるオーセンティケーターを実装していきます。この例は、完全に実装されており、Keycloakのデモ配布物のexamples/providers/authenticatorディレクトリーに含まれています。オーセンティケーターを作成するには、少なくともorg.keycloak.authentication.AuthenticatorFactoryおよびAuthenticatorインターフェースを実装する必要があります。Authenticatorインターフェイスはロジックを定義します。AuthenticatorFactoryは、Authenticatorインスタンスの作成を担います。それらは両方とも、ユーザー・フェデレーションのような他のKeycloakコンポーネントが行う、より汎用的なProviderとProviderFactoryのインターフェイスのセットを継承します。CookieAuthenticatorなどの一部のオーセンティケーターは、ユーザーを認証するためにユーザーが持っている、または知っているCredentialに依存しません。PasswordFormオーセンティケーターやOTPFormAuthenticatorなどの一部のオーセンティケーターは、ユーザーが何らかの情報を入力し、その情報をデータベース内のいくつかの情報と照合することに依存しています。PasswordFormの場合、オーセンティケーターはデータベースに保存されているハッシュに対してパスワードのハッシュを検証し、OTPFormAuthenticatorはデータベースに保存されている共有シークレットから生成されたOTPに対して受信したOTPを検証します。これらのタイプのオーセンティケーターはCredentialValidatorsと呼ばれ、さらに次のいくつかのクラスを実装する必要があります。org.keycloak.credential.CredentialModelを継承し、データベースでクレデンシャルの正しい形式を生成できるクラスorg.keycloak.credential.CredentialProviderとインターフェイスを実装するクラス、およびそのCredentialProviderFactoryファクトリー・インターフェイスを実装するクラス。このウォークスルーで確認するSecretQuestionAuthenticatorはCredentialValidatorであるため、これらのクラスをすべて実装する方法を確認します。クラスのパッケージ化とデプロイ1つのjarファイル内にクラスをパッケージ化します。ディレクトリーに含まれている必要があります。このファイルには、jarファイル内にある各AuthenticatorFactory実装の完全修飾クラス名が一覧化されている必要があります。以下のとおりになります。org.keycloak.examples.authenticator.SecretQuestionAuthenticatorFactoryorg.keycloak.examples.authenticator.AnotherProviderFactoryこのservices/ファイルは、システムにロードする必要があるプロバイダーをKeycloakがスキャンするために使用されます。このjarをデプロイするには、これをprovidersディレクトリーにコピーします。CredentialModelクラスの継承Keycloakでは、クレデンシャルはデータベースのCredentialsテーブルに保存されます。次のテーブル定義になっています。|-----------------------------各列は以下のとおりです。Credentialsテーブルの主キーです。クレデンシャルをユーザーにリンクする外部キーです。作成中に設定される文字列で、既存のクレデンシャル・タイプを参照する必要があります。クレデンシャルの作成タイムスタンプ(長い形式)です。ユーザーによるクレデンシャルの編集可能な名前です。Keycloakの外部に送信できない情報を持つ静的JSONが含まれます。APIを介して共有できるクレデンシャルの静的情報を含むJSONが含まれています。ユーザーが複数の選択肢を持っているときにどのクレデンシャルを提示するかを決定するために、ユーザーにとってクレデンシャルがどのように"優先される"かを定義します。secret_dataフィールドとcredential_dataフィールドはjsonを含むように設計されているため、これらのフィールドの構成や、読み取り、書き込みの方法を柔軟に変更できます。この例では、ユーザーに尋ねられた質問のみを含む非常に単純なクレデンシャル・データを使用します。"question":"aQuestion"}以下は、同様に単純な秘密データを使用します(秘密の答えのみを含む)。"answer":"anAnswer"}ここでは、簡単にするために、回答はデータベースにプレーンテキストで保存しますが、Keycloakのパスワードの場合のように、回答にソルトハッシュを使用することもできます。この場合、秘密データには、ソルトのフィールドと、使用されたアルゴリズムのタイプや使用された反復数などのアルゴリズムに関するクレデンシャル・データ情報も含まれている必要があります。クラスの実装を参照してください。データベースに書き込むcredential_typeです。一貫性を保つために、このクレデンシャルの型を取得するときにこのStringが常に参照されるようにします。jsonのマーシャリングとアンマーシャリングに使用されます。オブジェクトには、その親クラスからのそのままのjsonデータと、独自の属性のアンマーシャルされたオブジェクトの両方が含まれている必要があります。生成するメソッドは次のようになります。}}CredentialProviderの実装すべてのプロバイダーで同様に、KeycloakがCredentialProviderを生成できるようにするには、CredentialProviderFactoryが必要です。この要件のために、SecretQuestionCredentialProviderFactoryを生成します。メソッドが呼び出されます。}}CredentialProviderインターフェイスは、CredentialModelを継承するジェネリックなパラメーターを扱います。この場合、作成したSecretQuestionCredentialModelを使用します。}このプロバイダーを使用してAuthenticatorのクレデンシャルを検証できることをKeycloakが知ることができるため、CredentialInputValidatorインターフェイスも実装します。TYPE文字列を返します。既存の静的メソッドを呼び出します。SecretQuestionCredentialModel.createFromCredentialModel(model);}最後に、クレデンシャルを作成するメソッドと、クレデンシャルを削除するメソッドがあります。これらには、クレデンシャルの読み取りまたは書き込みの場所(たとえば、ローカル・ストレージやフェデレーション・ストレージなど)を把握する責任があります。これは、特定のレルム内の特定のユーザーに対して認証情報が有効かどうかをテストします。これは、Authenticatorがユーザーの入力を検証しようとしたときに呼び出されるメソッドです。ここでは、入力文字列がクレデンシャルに記録されたものであることを確認するだけです。sqcm.getSecretQuestionSecretData().getAnswer().equals(challengeResponse);}実装する他の2つの方法は、CredentialProviderが指定されたクレデンシャル・タイプをサポートするかどうかのテストと、クレデンシャル・タイプが特定のユーザーに対して設定されているかどうかを確認するテストです。私たちの場合、後者のテストは単に、ユーザーがSECRET_QUESTIONタイプのクレデンシャルを持っているかどうかを確認することを意味します。credentialType).isEmpty();}Authenticatorの実装Credentialsを使用してユーザーを認証するオーセンティケーターを実装する場合、AuthenticatorにCredentialValidatorインターフェイスを実装させる必要があります。このインターフェイスは、CredentialProviderをパラメーターとして拡張するクラスを取り、KeycloakがCredentialProviderからメソッドを直接呼び出すことを許可します。この例では、SecretQuestionAuthenticatorがSecretQuestionCredentialProviderを取得できます。SecretQuestionCredentialProviderFactory.PROVIDER_ID);}Authenticatorインターフェースを実装する場合、実装する必要がある最初のメソッドはrequiresUser()メソッドです。この例では、ユーザーに関連付けられた秘密の質問を検証する必要があるため、このメソッドはtrueを返す必要があります。Kerberosのようなプロバイダーは、Negotiateヘッダーからユーザーを解決できるため、このメソッドからfalseを返します。この例では、特定のユーザーの特定のクレデンシャルを検証しています。実装する次のメソッドはconfiguredFor()メソッドです。このメソッドは、ユーザーがこの特定の認証用に設定されているかどうかを判断します。この場合、SecretQuestionCredentialProviderに実装されているメソッドを呼び出すだけです。getType(session));}Authenticatorに実装する次のメソッドはsetRequiredActions()です。メソッドがtrueを返す場合に限られます。setRequiredActions()メソッドは、ユーザーが実行する必要のある必要なアクションを登録します。この例では、秘密の質問への回答をユーザーに設定させる必要なアクションを登録する必要があります。この必須のアクション・プロバイダーは、この章の後半で実装します。setRequiredActions()メソッドの実装は次のとおりです。}Authenticatorの実装の要点を説明します。実装する次のメソッドはauthenticate()です。これは、実行が最初にアクセスされたときにフローが呼び出す最初のメソッドです。ユーザーがブラウザーのマシン上で秘密の質問にすでに答えている場合、ユーザーは質問に再度答える必要がなく、そのマシンを"信頼できる"ものにすることが望まれます。authenticate()メソッドは、秘密の質問フォームの処理を担当しません。その唯一の目的は、ページをレンダリングするか、フローを継続することです。result;}hasCookie()メソッドは、秘密の質問がすでに回答されたことを示すCookieがブラウザーに設定されているかどうかを確認します。それがtrueを返す場合、AuthenticationFlowContext.success()メソッドを使用してauthentication()メソッドから戻ることで、この実行のステータスをSUCCESSとしてマークします。hasCookie()メソッドがfalseを返す場合、秘密の質問のHTMLフォームをレンダリングするレスポンスを返す必要があります。AuthenticationFlowContextには、フォームの構築に必要な適切な基本情報でFreemarkerページビルダーを初期化するform()メソッドがあります。LoginFormsProvider.createForm()メソッドは、ログインテーマからFreemarkerテンプレートファイルをロードします。Freemarkerテンプレートに追加情報を渡す場合は、LoginFormsProvider.setAttribute()メソッドを呼び出すことができます。これについては後で説明します。Responseオブジェクトが返されます。次に、このレスポンスで渡すAuthenticationFlowContext.challenge()を呼び出します。これにより、エグゼキューションのステータスがCHALLENGEに設定され、エグゼキューションがREQUIREDの場合、このJAX-RSレスポンスのオブジェクトがブラウザーに送信されます。したがって、秘密の質問に対する回答を求めるHTMLページがユーザーに表示され、ユーザーが回答を入力して送信をクリックします。HTMLフォームのアクションURLは、HTTPリクエストをフローに送信します。フローは、Authenticatorの実装のaction()メソッドを呼び出すことになります。context.success();}回答が有効でない場合、HTMLフォームを追加のエラーメッセージで再構築します。次に、原因となる値とJAX-RSレスポンスを渡すAuthenticationFlowContext.failureChallenge()を呼び出します。failureChallenge()はchallenge()と同じ働きをしますが、失敗も記録するので、攻撃検出サービスによって解析できます。検証に成功すると、秘密の質問に回答したことを記憶するCookieを設定し、AuthenticationFlowContext.success()を呼び出します。検証自体は、フォームから受信したデータを取得し、SecretQuestionCredentialProviderからisValidメソッドを呼び出します。クレデンシャルIDの取得に関するコードのセクションがあることに気付くでしょう。これは、Keycloakが複数のタイプの代替オーセンティケーターを許可するように設定されている場合、またはユーザーがSECRET_QUESTIONタイプの複数のクレデンシャルを記録できる場合(たとえば、複数の質問から選択でき、ユーザーがこれらの質問の1つ以上に回答できるようにできる場合)、Keycloakはユーザーのログ記録に使用されているクレデンシャルを知る必要があります。複数のクレデンシャルがある場合、Keycloakを使用すると、ログイン時にユーザーがどのクレデンシャルを使用するかを選択できます。情報はフォームからオーセンティケーターに送信されます。メソッドによって与えられます。このメソッドは、ユーザーの正しいタイプの"最も優先される"クレデンシャルを返します。input);}次のメソッドはsetCookie()です。これは、オーセンティケーターの設定を提供する例です。この場合、Cookieの最大有効期間を設定可能にする必要があります。true);}AuthenticationFlowContext.getAuthenticatorConfig()メソッドからAuthenticatorConfigModelを取得します。設定が存在する場合は、その設定の最大有効期間を取り出します。何を設定するべきかを定義する方法については、AuthenticatorFactoryの実装について説明する際に確認していきます。AuthenticatorFactory実装で設定の定義をした場合、管理コンソール内で設定値を定義できます。metadataContext)です。各クレデンシャル・プロバイダーは、このメソッドを提供および実装する必要があります。このメソッドは、CredentialTypeMetadataのインスタンスを返します。これには、少なくともオーセンティケーターのタイプとカテゴリー、displayName、および取り外し可能なアイテムが含まれている必要があります。この例では、ビルダーはメソッドgetType()からオーセンティケーターのタイプを取り、カテゴリーは2要素(オーセンティケーターは認証の2番目の要素として使用できます)かつ取り外し可能で、falseに設定されています(ユーザーは以前に登録されたクレデンシャルを削除できません)。ビルダーの他の項目は、helpText(さまざまな画面でユーザーに表示されます)、createAction(必要なアクションのプロバイダーID、ユーザーが新しいクレデンシャルを作成するために使用できます)、またはupdateAction(createActionと同じですが、新しいクレデンシャルを作成する代わりに、クレデンシャルを更新します)です。AuthenticatorFactoryの実装このプロセスでの次のステップは、AuthenticatorFactoryを実装することです。このファクトリーはAuthenticatorのインスタンス化を担当します。Authenticatorに関する配備と設定のメタデータも提供します。getId()メソッドは、コンポーネントの一意の名前です。create()メソッドは、Authenticatorを割り当てて処理するために、ランタイムによって呼び出されます。}ファクトリーが次に受け持つのは、許可されたスイッチの要件を指定することです。ALTERNATIVE、REQUIRED、CONDITIONAL、DISABLEDの4種類の要件タイプがありますが、AuthenticatorFactoryの実装では、フローを定義する際に管理コンソールに表示されるオプションの要件を制限できます。CONDITIONALは常にサブフローにのみ使用する必要があり、そうする正当な理由がない限り、オーセンティケーターの要件はREQUIRED、ALTERNATIVE、およびDISABLEDである必要があります。}AuthenticatorFactory.isUserSetupAllowed()は、Authenticator.setRequiredActions()メソッドが呼び出されるかどうかをフロー・マネージャーに通知するフラグです。オーセンティケーターがユーザーに設定されていない場合、フロー・マネージャーはisUserSetupAllowed()をチェックします。falseの場合、エラーを返して異常終了します。trueを返すと、フロー・マネージャーはAuthenticator.setRequiredActions()を呼び出します。}次のいくつかのメソッドは、オーセンティケーターの設定方法を定義します。isConfigurable()メソッドは、オーセンティケーターをフロー内で設定することができるかどうかを管理コンソールに指定するフラグです。getConfigProperties()メソッドは、ProviderConfigPropertyオブジェクトのリストを返します。これらのオブジェクトは、特定の設定属性を定義します。}それぞれのProviderConfigPropertyは、設定プロパティーの名前を定義します。これが、AuthenticatorConfigModelに格納されている設定マップで使用されるキーとなります。ラベルは、管理コンソールでどのように設定オプションが表示されるかを定義します。タイプは、そのプロパティーがString、Booleanまたはその他のタイプであるかを定義します。管理コンソールには、タイプによって異なるUI入力が表示されます。ヘルプのテキストは、管理コンソールの設定属性のツールチップに表示されるものです。詳しくは、ProviderConfigPropertyのjavadocを参照してください。残りのメソッドは管理コンソール用です。getHelpText()は、エグゼキューションにバインドさせるオーセンティケーターを選択するときに表示されるツールチップ・テキストです。getDisplayType()は、オーセンティケーターを一覧表示する際に管理コンソールに表示されるテキストです。getReferenceCategory()は、オーセンティケーターが属するカテゴリーです。オーセンティケーター・クラスのauthenticate()内で呼び出されたcreateForm()メソッドは、ログインテーマ内のsecret-question.ftlファイルからHTMLページを構築します。追加する必要があります。詳細については、テーマ・リソース・プロバイダを参照してください。secret-question.ftlの詳細を見ていきましょう。以下は、短いコードスニペットになります。囲まれたテキストは、属性またはテンプレートの関数に対応します。この値は、AuthenticationFlowContext.form()メソッドを呼び出すと自動的に生成されます。JavaコードでAuthenticationFlowContext.getActionURL()メソッドを呼び出すことで、この値を取得することもできます。これらは、テーマのtheme.propertiesファイルで定義されたプロパティに対応します。files)に対応します。値を追加することができます。これがユーザーに要求する質問になります。AuthenticationFlowContext.form()を呼び出すと、LoginFormsProviderインスタンスが生成されます。いう形式で参照することができます。beanでも構いません。ファイルの上部を見ると、テンプレートをインポートしていることがわかります。代わりにこのテンプレートをインポートすると、Keycloakはユーザーが別のクレデンシャルまたはエグゼキューションを選択できるドロップダウン・ボックスを表示できます。フローにオーセンティケーターを追加オーセンティケーターをフローに追加するには、管理コンソールで行う必要があります。Authenticationメニュー項目に移動してFlowタブに移動すると、現在定義されているフローを表示できます。組み込みフローを変更することはできないため、作成した認証システムを追加するには、既存のフローをコピーするか、独自のフローを作成する必要があります。ユーザー・インターフェイスが十分に明確であり、フローの作成方法とオーセンティケーターの追加方法を決定できることが期待されます。章を参照してください。フローを作成したら、バインドさせたいログイン・アクションに、そのフローをバインドする必要があります。Grantフローにバインドするオプションが表示されます。必須アクションのウォークスルーこのセクションでは、必須アクションを定義する方法について説明します。オーセンティケーターのセクションでは、"どのようにしてシステムに入力された秘密の質問に対するユーザーの回答をもらえば良いのだろう"と疑問に思ったかもしれません。例で示したように、回答が設定されていない場合は、必須アクションがトリガーされます。このセクションでは、シークレット・クエスチョン・オーセンティケーターに必須アクションを実装する方法について説明します。クラスのパッケージ化とデプロイ1つのJARファイル内にクラスをパッケージ化します。ディレクトリーに含まれている必要があります。このファイルには、JARファイル内にある各RequiredActionFactory実装の完全修飾クラス名が一覧化されている必要があります。以下のとおりになります。org.keycloak.examples.authenticator.SecretQuestionRequiredActionFactoryこのservices/ファイルは、システムにロードする必要があるプロバイダーをKeycloakがスキャンするために使用されます。必須アクションは、最初にRequiredActionProviderインターフェイスを実装する必要があります。RequiredActionProvider.requiredActionChallenge()は、フロー・マネージャーによる必須アクションの最初の呼び出しになります。このメソッドは、必須アクションを実行するHTMLフォームのレンダリングを行います。}RequiredActionContextには、AuthenticationFlowContextと同じようなメソッドがあります。form()メソッドにより、Freemarkerテンプレートからページをレンダリングすることができます。アクションURLは、このform()メソッドの呼び出しにより事前に設定されるため、HTMLフォーム内で参照するだけで済みます。これについては、後ほど説明します。challenge()メソッドは、必須アクションを実行する必要があることをフローマネージャーに通知します。次のメソッドは、必須アクションのHTMLフォームからの入力を処理します。フォームのアクションURLは、RequiredActionProvider.processAction()メソッドにルーティングされます。}回答はフォームのpostから取り出されます。UserCredentialValueModelが作成され、クレデンシャルのタイプと値がセットされます。その後、UserModel.updateCredentialDirectly()が呼び出されます。最後に、RequiredActionContext.success()は、必須アクションが成功したことをコンテナーに通知します。RequiredActionFactoryの実装このクラスは非常にシンプルです。これは必須アクション・プロバイダー・インスタンスの作成を行うだけです。}getDisplayText()メソッドは、必須アクションに対して分かりやすい名前を表示させたいときに、管理コンソールで使用されます。最後に、管理コンソールに移動する必要があります。左メニューのAuthenticationをクリックします。Actionsタブをクリックします。Registerボタンをクリックし、新しい必須アクションを選択します。必須アクションのリストに新しい必須アクションが表示され、有効になります。登録フォームの変更または拡張Keycloakでの登録方法を完全に変更するために、オーセンティケーターのセットを使用して独自のフローを実装することが可能です。独自の登録ページにちょっとしたバリデーションを加えたいことも普通にあるかと思います。これを行うために追加のSPIが作成されました。このSPIは、基本的には、ページにフォーム要素のバリデーションを追加するだけでなく、ユーザー登録後にUserModel属性とデータを初期化することもできます。Recaptchaプラグインの登録の両方を説明していきます。実装する必要のあるコアとなるインターフェイスは、FormActionインターフェイスです。FormActionは、ページの一部のレンダリングと処理を受け待ちます。レンダリングはbuildPage()メソッド、バリデーションはvalidate()メソッド、バリデーション後の動作はsuccess()で行います。RecaptchaプラグインのbuildPage()メソッドを見ていきます。}RecaptchaのbuildPage()メソッドは、ページのレンダリングを支援するフォームフローからのコールバックです。これは、LoginFormsProviderであるフォーム・パラメーターを受け取ります。フォーム・プロバイダーに追加属性を加えて、登録Freemarkerテンプレートによって生成されたHTMLページに表示させることができます。上記のコードは、登録Recaptchaプラグインからのものです。Recaptchaには、設定から取得する必要のある特定の設定が必要です。FormActionsは、オーセンティケーターとまったく同じように設定されています。Recaptchaの公開鍵を設定から取り出し、フォーム・プロバイダーに属性として追加します。これで、登録テンプレート・ファイルはこの属性を読み込むことができます。Recaptchaには、JavaScriptの読み込み要件もあります。これを行うには、URLを渡すLoginFormsProvider.addScript()を呼び出します。ユーザー・プロファイルを処理する場合、フォームに加える必要がある追加情報はないため、buildPage()メソッドは空です。このインターフェイスの次の部分は、validate()メソッドです。これは、フォームのpostを受け取ると、直後に呼び出されます。最初に、Recaptchaのプラグインを見ていきます。}ここでは、Recaptchaウィジェットがフォームに追加するフォームデータを取得します。設定からRecaptchaの秘密鍵を取得します。次に、Recaptchaを検証します。成功すると、ValidationContext.success()が呼び出されます。成功しなかった場合は、formDataで渡すValidationContext.validationError()を呼び出します(ユーザーがデータを再入力する必要はありません)。表示するエラーメッセージを指定します。エラーメッセージは、国際化されたメッセージ・バンドルのメッセージ・バンドル・プロパティーを指し示している必要があります。他の登録拡張の場合、validate()はフォーム要素のフォーマット、つまり別の電子メール属性を検証する可能性もあります。登録時にメールアドレスや他のユーザー情報を検証するために使用されるユーザー・プロファイル・プラグインについても見ていきましょう。}上記に示されているとおり、ユーザー・プロファイル処理のvalidate()メソッドは、電子メール、名および姓がフォームに入力されていることを確認します。電子メールが適切なフォーマットであることを確認します。これらのバリデーションのいずれかが失敗すると、レンダリング用にエラーメッセージがキューに入れられます。エラーのあるフィールドは、すべてフォームデータから削除されます。エラーメッセージは、FormMessageクラスによって表されます。このクラスのコンストラクターでの最初のパラメーターは、HTML要素IDが取得されます。フォームが再レンダリングされると、エラー入力がハイライトされます。2番目のパラメーターはメッセージ参照IDです。このIDは、テーマ内でローカライズされたメッセージ・バンドル・ファイルのいずれかのプロパティーに対応している必要があります。すべてのバリデーションが処理された後、フォームフローはFormAction.success()メソッドを呼び出します。Recapthaに対して、これは何も行わないので説明はしません。ユーザー・プロファイル処理の場合、このメソッドは登録ユーザーの値を入力します。}とてもシンプルな実装です。新しく登録されたユーザーのUserModelは、FormContextから取得されます。適切なメソッドが呼び出され、UserModelデータが初期化されます。最後に、FormActionFactoryクラスを定義する必要もあります。このクラスは、AuthenticatorFactoryと同様に実装されるため、ここでは説明はしません。アクションのパッケージ化1つのJARファイル内にクラスをパッケージ化します。ディレクトリーに含まれている必要があります。このファイルには、JARファイル内にある各FormActionFactory実装の完全修飾クラス名が一覧化されている必要があります。以下のようになります。org.keycloak.authentication.forms.RegistrationProfileorg.keycloak.authentication.forms.RegistrationRecaptchaこのservices/ファイルは、システムにロードする必要があるプロバイダーをKeycloakがスキャンするために使用されます。登録ページフローへのFormActionの追加は管理コンソールで行う必要があります。Authenticationメニュー項目へ移動してFlowタブを選択すると、現在定義されているフローが表示されます。組み込みのフローは変更することはできません。そのため、作成したオーセンティケーターを追加するには、既存のフローをコピーするか独自のフローを作成する必要があります。このUIは非常に分かりやすく作られているので、フローを作成してFormActionを追加する方法を見つけることができると思っています。基本的には、Registrationフローをコピーする必要があります。execution"を選択して新しいエグゼキューションを追加します。選択リストからFormActionを選択します。Creation"の後に来ることを確認してください。Creationのsuccess()メソッドは、新しいUserModelの作成を受け持つため、FormActionはユーザー作成の後に表示される必要があります。フローを作成した後、そのフローをRegistrationにバインドする必要があります。Grantフローにバインドするオプションが表示されます。パスワード忘れおよびクレデンシャル・フローの変更Keycloakには、パスワードを忘れた場合の特定の認証フロー、またはユーザーにより発行されたクレデンシャルのリセットもあります。Credentials"フローがあります。デフォルトでは、Keycloakはユーザーの電子メールまたはユーザー名を要求し、ユーザーに電子メールを送信します。ユーザーがリンクをクリックすると、パスワードとOTP(OTPが設定されている場合)の両方をリセットすることができます。OTP"オーセンティケーターを無効にすると、自動のOTPリセットを無効にすることができます。このフローにも機能を追加することができます。多くのデプロイメントでは、リンク付きの電子メールを送信することに加え、ユーザーが1つ以上の秘密の質問に回答するようにしたいと考えています。Credentialフローに組み込むことができます。Credentialsフローを拡張する場合、1つ注意点があります。最初の"オーセンティケーター"は、ユーザー名または電子メールを取得するための単なるページです。ユーザー名または電子メールが存在する場合、AuthenticationFlowContext.getUser()はそのユーザーを返します。それ以外の場合はnullになります。攻撃者が有効なユーザーを推測できないようにする必要があるため、AuthenticationFlowContext.getUser()がnullを返す場合、有効なユーザーが選択されたかのように見せかけるために、フローを続行する必要があります。このフローに秘密の質問を追加する場合は、電子メールの送信後にこれらの質問をすることをお勧めします。Email"オーセンティケーターの後に、カスタム・オーセンティケーターを追加してください。Loginフローは、アイデンティティー・プロバイダーに最初にログインした時に使用されます。いう用語は、特定の認証されたアイデンティティー・プロバイダー・アカウントにリンクされているKeycloakアカウントがまだ存在していないことを意味します。章を参照してください。クライアント・アプリケーションのためのプラグイン可能な認証をサポートしています。クライアント(アプリケーション)の認証は、Keycloakアダプターがバックチャネル・リクエストをKeycloakサーバーに送信中に内部で使用されます(認証が成功した後にコードとアクセストークンを交換する要求をしたり、リフレッシュトークンを要求したりするなど)。)でクライアント認証を直接使用することも可能です。Guideを参照してください。実際、Keycloakには、以下の2つのクライアント認証の実装が組み込まれています。仕様で記載されているデフォルトのメカニズムであり、Keycloakは初期段階からサポートしています。ヘッダーとともに、ユーザー名とパスワードとして使用されるクライアントIDとクライアント・シークレットが含まれている必要があります。仕様に基づいています。生成し、秘密鍵で署名します。Keycloakは、署名されたJWTをクライアントの公開鍵で検証し、それに基づいてクライアントを認証します。独自のクライアント・オーセンティケーターをプラグインするには、クライアント(アダプター)とサーバー側の両方にいくつかのインターフェイスを実装する必要があります。実装し、以下のいずれかにその実装を入れる必要があります。WARファイル内のWEB-INF/classes。この場合、実装はこの単一のWARアプリケーションに対してのみ使用できます。WARのWEB-INF/libに追加されるJARファイル。JBossモジュールとして使用され、WARのjboss-deployment-structure.xmlで設定されるJARファイル。ファイルを作成する必要があります。実装する必要があります。ファイルに実装クラスの名前を追加する必要があります。Token(JWT)の特別なインスタンスで、その持参者がいくつかの動作を実行できるようにするものです。パスワードをリセットしたり、電子メールアドレスを検証したりすることができます。それらは通常、特定のレルムのアクション・トークンを処理するエンドポイントを指すリンクの形式でユーザーに送信されます。Keycloakは、4つの基本のトークンタイプを提供して、持参者が以下を実行できるようにします。外部のアイデンティティー・プロバイダーのアカウントを使用した、アカウントのリンク付けの確認これに加えて、アクショントークンSPIを使用して認証セッションを開始したり、変更したりする機能を実装することができます。これについて、詳しくは、以下で説明していきます。(optional)さらに、アクション・トークンには、JSON内にシリアライズできるカスタム・フィールドをいくつか含めることができます。パラメーターを介して渡されると、それが検証され、適切なアクション・トークン・ハンドラーが実行されます。新しいものかアクション・トークン・サービスが既存の認証セッションに加わります(詳しくは、後で説明します)。アクション・トークン・ハンドラーは、トークン(これで認証セッションを変更することが多い)によって規定されたアクションを実行し、HTTPレスポンスを返すことができます(たとえば、認証を続けるか、情報またはエラーページを表示することができます)。これらの手順について、詳しくは以下のとおりです。基本的なアクショントークンの検証。フィールドに基づいて決定されます。認証セッションの決定。アクション・トークンURLが既存の認証セッションを使用するブラウザーで開かれ、トークンにブラウザーからの認証セッションと一致する認証セッションIDが含まれている場合、アクション・トークンの検証と処理により、この進行中の認証セッションが追加されます。ない場合は、アクション・トークン・ハンドラーはその時点でブラウザーに存在する他の認証セッションを置き換える新しい認証セッションを作成します。トークンタイプ固有のトークンの検証。)が存在し、無効ではないことを検証します。次に、アクション・トークン・ハンドラー内で定義されたカスタム・バリデーションがすべて検証されます。トークン・ハンドラーは、トークンを使い捨てるように要求できます。これで、すでに使用済みのトークンは、アクション・トークン・エンドポイント・ロジックによって拒否されます。これらの検証がすべて行われた後で、トークン内のパラメーターに応じて実際にアクションを実行する、アクション・トークン・ハンドラー・コードが呼び出されます。使い捨てトークンの無効化。トークンを使い捨てるように設定されている場合、認証フローが完了次第、アクション・トークンは無効になります。代わりにそのクラスを使うことで活用できます。次の例は、単純なアクショントークンの実装を示しています。クラスには引数のないprivateコンストラクターが必要です。これは、JWTからトークンクラスをデシリアライズするために必要です。クラスの子孫を実装することを検討する必要があります。クラスは、すでに両方の条件を満たしており、直接使用するか、そのクラスの子を実装することができます。)を付けることができます。}}クラスのパッケージ化とデプロイ独自のアクション・トークンとそのハンドラーをプラグインするには、サーバー側のインターフェイスを少し実装する必要があります。トークン・フィールドに指定された値に対する)アクション・トークンの実際のハンドラー。通常、それは認証セッション記録の変更ですが、一般的には任意です。メソッドによって返されるクラスであることが保証されている場合にのみ呼び出されます。メソッドで宣言されなければなりません。フィールドの値を返します。このメソッドをオーバーライドして、トークンに関係なく、現在の認証セッションIDを返すことができることに注意してください。任意の認証フローを開始する前に進行中の認証フローにステップインするトークンを作成できます。呼び出すことにより新しいセッションを開始するよう要求されます。メソッドを介して、トークンが使用されて認証が完了した後に、トークンが無効になるかどうかが決定されます。複数のアクション・トークンを利用するフローがある場合、最後のトークンだけが無効になることに注意してください。使用し、使用されたトークンを手動で無効にする必要があります。