AD FS 上に WS-Federation 認証でサインインするサンプル アプリを登録するために必要な手順

#はじめに
ほとんど需要が無いと思いますが、WS-Federation で動作するサンプル アプリを AD FS 上の「証明書利用者信頼」に登録して動作する環境を用意する必要があったので備忘録も兼ねて記事に残します。

AD FS 3.0 上で動いているくらいなので、AD FS 2016 及び AD FS 2019 上でも問題なく動作すると思います。

必要な環境は以下のとおりです。
・AD FS サーバー 3.0 (Windows Server 2012 R2 OS) 以降
・AD DS (属性ストア及び Kerberos 認証で必要)
・.NET 5.0 が動く環境 (今回は Visual Studio 2019 で動かしています)

#やってみる
結論を言ってしまうと下記 Microsoft 公開情報に書いている内容をきちんと理解できる人であればこちらを見た方が早いです。
(日本語は機械翻訳しているので英語の方が良いと思います。)

-参考情報
Authenticate users with WS-Federation in ASP.NET Core
URL:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/ws-federation?view=aspnetcore-5.0

ASP.NET Core で WS-Federation を使用してユーザーを認証する
URL:https://docs.microsoft.com/ja-jp/aspnet/core/security/authentication/ws-federation?view=aspnetcore-5.0

今回 Azure AD を経由せずに AD FS の「証明書利用者信頼」に登録するので上記公開情報内の「Azure Active Directory」の項目で行っている「アプリの登録」の作業は不要です。逆に Azure AD 認証させたい場合はこちらを設定する必要がありますが今回の目的の主旨に反するので本記事では記載はしません。

以下は AD FS を IdP として WS-Federation 認証する手順になります。

###手順概要
1. AD FS の「証明書利用者信頼」にアプリを登録する
2. Visual Studio 2019 上でサンプル アプリを構成する
3. サンプル アプリを起動してフェデレーション ユーザーでサインインを試す

#####1. AD FS の「証明書利用者信頼」にアプリを登録する

AD FS 管理ツールより「証明書利用者信頼」→「証明書利用者信頼の追加」の順に選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/b1b81050-c9af-a0e0-5a01-3e600f4eefdb.png)

画面右下の「開始」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/bab830f6-999c-cd80-e8b7-11198dc8b6cc.png)

「証明書利用者信頼についてのデータを手動で入力する」を選択し「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/915af97f-722f-7c60-d237-023ce2ff3c0e.png)

表示名は任意の名前を設定し「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/8db5f30e-b6bc-2760-9636-3ec923f3c5be.png)

そのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/3557aa7d-1947-b3f0-2480-16b5e5995183.png)

そのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/7958a691-e660-f610-a571-87eac06e06cf.png)

「WS-Federation のパッシブ プロトコルのサポートを有効にする」にチェックを入れ、パッシブ プロトコルの URL を入力し「次へ」をクリックします。ここのパッシブ プロトコル URL がサンプル アプリが公開している URL になりますが、現時点はアプリを公開していないので公開情報のとおりの URL を一旦入力しています。後で必ず変更する必要がある URL になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/71a13f0d-51db-d3a4-2f6d-f1f70e46ef50.png)

識別子として「https://localhost:44307/」 が入力されていることを確認し「次へ」をクリックします。
今回利用するサンプル アプリが持つ識別子が「https://localhost:44307/」 になるのでこのまま変更することなく利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/ce561d60-9cb7-f616-42ea-841feefea575.png)

今回は多要素認証を構成しないのでそのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/06daa912-fa65-ddbf-a3b9-c9aa950fb4f3.png)

今回はすべてのフェデレーション ユーザーのアクセスを許可するアプリケーションになるので、そのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/8f46addf-bc33-4458-daed-abfff043fee5.png)

そのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/934c9f27-cf67-c962-5ab0-b99e3df1c293.png)

「閉じる」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/d1e2fcef-a3f4-8755-bbed-2364a13c923d.png)

閉じるをクリックすると「要求規則の編集」画面がポップアップ表示されるので「発行変換規則」タブが選択されていることを確認し「規則の追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/364cc0ce-d85d-3d1d-a005-63fd5efa44f9.png)

そのまま「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/812f3d5a-a12b-2834-5f58-2d209d2c8ab8.png)

アプリケーション側が要求する属性 (クレーム) としてユーザーを一意に識別するための識別子を AD DS から「SAM-Account-Name」を取得し「Name ID (名前 ID)」としてサンプル アプリケーションに渡す構成をしています。
以下のとおりに選択して「完了」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/cd3623d3-d1fd-54e4-e4d4-dd9425fe3d93.png)

| 項目 | 値 | 
|:-----------|:------------|
| 要求規則名   | 任意の名前を入力 |
| 属性ストア| Active Directoy | 
| LDAP 属性 | SAM-Account-Name | 
| 出力方向の要求の種類| 名前 ID | 

OK をクリックして画面を閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/fcf9815f-e82b-1a18-25be-8aafa8156701.png)

以下画面ショットのように「証明書利用者信頼」にさきほど作成したサンプル アプリが登録されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/3e7d3c04-372b-c853-d121-8a85365c30b1.png)

次は Visual Studio 側でサンプル アプリの構成をしていきます。

######2. Visual Studio 2019 上でサンプル アプリを構成する

Visual Studio の「ファイル」→「新規作成」→「プロジェクト」の順に選択し表示される「ASP.NET Core Web アプリ」を選択し「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/58c90f0b-dea3-8ce2-c679-403915cfb675.png)

任意のプロジェクト名を記入し「次へ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/0fd849a9-cf42-765b-ce8e-4fc30694a9c3.png)

追加情報の画面でターゲット フレームワークに「.NET 5.0」が選択されていることを確認し、「認証の種類」に「個別のアカウント」プルダウンメニューから選択をし、「作成」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/6e17d9f5-7bc9-f4f8-7a49-6daa6fe30424.png)

プロジェクト作成完了後に画面上部の「プロジェクト」タブから「NuGet パッケージの管理」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/e3bd4a0f-da4b-16d7-cbc1-0dbadf6c03a0.png)

「参照」タブに「Microsoft.AspNetCore.Authentication.WsFederation」と入力し表示される「Microsoft.AspNetCore.Authentication.WsFederation」を選択し画面右の「インストール」をクリックします。
これが WS-Federation で認証するサンプル アプリの実体になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/320348e8-805e-b824-059f-16feba7d3da2.png)

確認画面が表示されるので「OK」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/e177908d-7e86-30d5-59de-bbc993307d44.png)

ライセンスへの同意画面が表示されるので「同意する」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/9f5997bf-1654-8a4b-93a8-93c8875d341a.png)

インストールが完了すると画面上部の「インストール済み」の項目に「Microsoft.AspNetCore.Authentication.WsFederation」が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/69ccbe8a-42fa-4f7d-a7f8-bdcf9dee257b.png)

次にインストールしたサンプルアプリの **Startup.cs** を編集します。
リポジトリ (場所) 内にある Startup.cs ファイルを Visual Studio で開きます。
(プロジェクト作成時に指定された「場所」の中の「repos」フォルダ内にプロジェクト名がフォルダとして作成されていますので同フォルダ内に「Startup.cs」ファイルが自動的に作成されています)

公開情報にも書かれていますが編集対象は以下の部分になります。
(変更前)

```c#
       // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDatabaseDeveloperPageExceptionFilter();
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();
            services.AddRazorPages();
        }
```

厳密には編集、確認が必要な個所は以下たったの 3 行です。
(変更後)

```c#

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddDatabaseDeveloperPageExceptionFilter();
            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddAuthentication()
       .AddWsFederation(options =>
       {
            // MetadataAddress represents the Active Directory instance used to authenticate users.
            options.MetadataAddress = "https://sts.xxxxxx.xxx/FederationMetadata/2007-06/FederationMetadata.xml";

            // Wtrealm is the app's identifier in the Active Directory instance.
            // For ADFS, use the relying party's identifier, its WS-Federation Passive protocol URL:
            options.Wtrealm = "https://localhost:44307/";

            // For AAD, use the Application ID URI from the app registration's Overview blade:
            //options.Wtrealm = "api://bbd35166-7c13-49f3-8041-9551f2847b69";
       });

            services.AddControllersWithViews();
            services.AddRazorPages();
        }
```

| 項目 | 値 | 備考|
|:-----------|:------------|:------------|
|  options.MetadataAddress   |"https://sts.xxxxxx.xxx/FederationMetadata/2007-06/FederationMetadata.xml"; |フェデレーション メタデータは AD FS と交換するので 「xxx」の部分はAD FS サーバーのフェデレーション サービス名を入力してください |
| options.Wtrealm| "https://localhost:44307/"; |サンプル アプリが持つ識別子になります。AD FS サーバー側の証明書利用者信頼で設定したアプリの「識別子」の値と完全に一致していることを確認してください |
| options.Wtrealm |コメント アウトする |api で始まる識別子は Azure AD の「アプリの登録」で登録した場合のアプリケーション ID を指定しますが今回は AD FS と連携するので "//" を先頭につけてコメント アウトしてください |

以下画面ショットのように編集が完了したら画面上部の「保存」アイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/d75397a2-f1e1-47a6-39a7-3207ff392ddc.png)

最後に起動前に「パッシブ プロトコル URL」を編集するためにサンプル アプリが公開している URL を確認します。
「プロジェクト」タブを選択し「(プロジェクト名)のプロパティ」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/acf43598-526d-1cf4-e22e-beabff7a1c1e.png)

左ペインにある「デバッグ」を選択し表示される画面の下側にある「SSL を有効にする」の欄にある URL を「コピー」します。
このアドレスが SAML 2.0 でいうところの「応答 URI (Redirect URI)」となり AD FS 認証が完了後に AD FS が発行するセキュリティ トークンを渡す先の URL になりますので、必ずここに表示されている URL を AD FS 側の「パッシブ プロトコル URL」として設定するようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/52b10050-c3c7-a2c2-05ee-370e1924fd4f.png)

AD FS 管理ツール側に戻り作成した「証明書利用者信頼」の「プロパティ」をクリックし「エンドポイント」タブにある仮設定したパッシブ エンドポイントを「編集」します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/77ce3d84-b8b6-d655-48dc-02f426198b01.png)

Visual Studio 側でコピーしてきた URL に変更し「OK」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/e54b994a-541e-851d-08dc-4f3fef2d3663.png)

パッシブ プロトコル URL が変更されていることを確認し「OK」をクリックし画面を閉じます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/a7992ba4-cf1c-36e1-a494-8841cb2ab4c4.png)

これで一通り設定は完了しましたのでサンプル アプリを起動し接続テストをしてみます。

#####3. サンプル アプリを起動してフェデレーション ユーザーでサインインを試す

Visual Studio の画面に戻り画面上部にある「IIS  Express」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/0652258b-8aa2-43a5-4893-2b6cb721b8d6.png)

構成が問題なければブラウザーが以下画面ショットのように起動してきますので画面右上にある「Login」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/963be447-b9bf-b0ba-1f6d-cc3073d07e30.png)

今回は AD FS に対して WS-Federation 認証したいので「WSFederation」のアイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/5fc1e432-0eed-b6b8-3ed5-f0e51e8a12ab.png)

初回アクセス時に以下のようなエラー画面が表示される場合 (どうやら対象のデータベースに必要なスキーマが不足しているようです) は「Apply Migrations」のアイコンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/2e4f6559-4e08-6df6-b193-f30a98cf0099.png)

ページを更新されるよう促されるのでページを更新します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/83afe8d2-857b-885c-bc10-1e2769df6b75.png)

お馴染みの AD FS フォーム認証の画面が表示されました。ここで認証可能なフェデレーション ユーザーの資格情報を入力し「サインイン」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/4ab9d680-e145-61c1-7865-b04387b15538.png)

WS-Federation 認証が成功した旨のメッセージが表示されましたので、対象のフェデレーション ユーザーが持つメール アドレスを入力し「Register」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/af1b676b-1be3-d072-0fb3-da97e9ba55fd.png)

登録が完了しました。このサンプル アプリ自体は登録として入力したメール アドレスにメールを飛ばす機能は実装されていないので実際にはメールは飛んできません。WS-Federation 認証が完了したことが確認できれば問題ないのでここの動作は気にしなくて問題ありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/cf19731c-5416-771d-a9f5-4c66fcf0e55d.png)

画面を更新するとフェデレーション認証した test012 ユーザーでサインインしていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373423/557c78f1-bf08-6cf3-cb1f-58dbac16a5fd.png)

#おわりに
今回は AD FS サーバーに WS-Federation で連携可能なサンプル アプリを登録、構成、テスト接続するまでの一連の作業を試してみました。
ほとんど活用する機会はないと思いますが、ちょっとした時に WS-Federation で動くアプリを AD FS と連携して試す機会があるときに参考手順書的な感じで使っていただけると幸いです。