プリザンター(.NET Core版)でSAML認証する

## 前提環境

- プリザンター(.NET Core)版が動作していること
    - 今回は、Ubuntu上で動作している、プリザンターを利用
- IDPが準備されていること
    - 今回は、Microsoft Azure ADを利用

## はじめに

公式のユーザマニュアルに、プリザンター(.NET Framework)の場合のマニュアルは記載があるのですが、.NET Core版は記載がありません。
.NET Coreだからなのかはわかっていませんが、Web.configは関係ないようなので、注意が必要です。


## IDPにプリザンターをアプリケーションとして登録する

今回は、Azure ADの場合で紹介をします。(ほとんどプリザンターとは関係ないです。)

1. Azure ADの管理ポータルを開き、「エンタープライズ アプリケーション」の画面を開きます。   
続けて、「新しいアプリケーション」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/a3bc2c96-5f6a-c71c-4ee7-d12d120f99a4.png)

1. 「独自のアプリケーションの作成」をクリックします。   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/65463561-be6a-b846-e337-3af3fb51ef2c.png)

1. アプリの名前を入力し、「ギャラリー以外」が選択されていることを確認し、「OK」をクリックします。   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/0fa278d0-d5db-3d03-5fb8-f11fd6a91113.png)

1. 作成したアプリを利用出来る、ユーザとグループを選択します。  
「1．ユーザとグループの割り当て」をクリックします。   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/35892b3a-2fda-74b6-e602-fde63a342230.png)

1. 「ユーザまたはグループの追加」をクリックします。   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/053a379d-3505-ee4f-c20b-9c9f03e17ae8.png)

1. 「選択されていません」をクリックします。   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/250b4d53-c0fd-a37e-7442-231490eddaf0.png)

1. 右側のにユーザとグループの一覧が表示されるため、適当なユーザもしくはグループを選択し、「選択」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/46bf6153-dab7-a32a-8ef1-11b4e37bd569.png)

1. ユーザが選択されている事を確認し、「割り当て」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/8c6a6ce5-0756-2aa1-8afd-b1b03d5adea8.png)

1. もとの戻るため、左のメニューから「概要」をクリックします。   
「2．シングルサインオンの設定」をクリックします。 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/866750d5-8d40-1fb1-dc1e-4301fc886de9.png)

1. 「シングルサインオン方式の選択」から「SAML」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/e0fcd7ea-e9e9-de07-ddcb-72562e306d73.png)

1. 「SAMLによるシングルサインオンのセットアップ」が表示されるため、「1 基本的なSAML構成」の「編集」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/932cd63e-f6b0-8abd-66e5-6268afce394b.png)

1. 「基本的なSAML構成」で、下記のように入力し、「保存」をクリックします。
識別子(エンティティID)：https://プリザンターのURL/Saml2   
応答URL(Asserion Consumer Service URL)：https://プリザンターのURL/Saml2/Acs   
ちなみに、応答URLはhttpsで始まるURLしか設定出来ません。 [^1] 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/e3fbfa4e-f5c9-6e5d-7eed-b095ea79b761.png)

1. もとの画面に戻るため、「2 ユーザ属性とクレーム」の「編集」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/1a0c8698-1f79-1cbf-b1a2-01b76e34c4ea.png)

1. 「ユーザ属性とクレーム」から「新しいクレームの追加」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/5b56aabe-af21-eaa0-c6a4-203a00670a24.png)

1. 「要求の管理」が表示されるため、「名前」に「Name」と入力し、「ソース属性」から「user.displayname」を選択し、「保存」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/1c4a8e21-0a3f-9e1b-e9e4-628f138da045.png)

1. もとの画面に戻ります。

Azure AD側での設定は完了です。

## 必要な情報を確認する

引き続き、プリザンターの設定に必要な情報を確認します。
先ほどのAzure ADの画面から「3 SAML署名証明書」「4 Pleasanter のセットアップ」から、次の項目を確認致します。

- 「SAML 署名証明書」の「拇印」
- 「プリザンター(Qiita)のセットアップ」の「ログインURL」
- 「プリザンター(Qiita)のセットアップ」の「Azure AD 識別子」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/2513ae28-894d-676d-1529-a211bffc0604.png)

## プリザンターの設定を行う

```json:Implem.Pleasanter/App_Data/Parameters/Authentication.json
{
    "Provider": "SAML",  // SAMLに書き換えます。
    "ServiceId": null,
//・・・・・・ 中略
    "SamlParameters": {
        "Attributes": {
            "Name": "Name",
            "UserCode": "UserCode",
            "Birthday": "Birthday",
            "Gender": "Gender",
            "Language": "Language",
            "TimeZone": "TimeZone",
            "TenantManager": "TenantManager",
            "DeptCode": "DeptCode",
            "Dept": "Dept",
            "Body": "Body",
            "MailAddress": "{NameId}"
        },
        "SamlTenantId": 1,
        "SPOptions": {
            // この部分は最後で説明
            "PublicOrigin": "https://pleasanter.exapmle.com",
            // https://プリザンターのURL/Saml2
            "EntityId": "https://pleasanter.exapmle.com/Saml2",
            // https://プリザンターのURL/Users/SamlLogin
            "ReturnUrl": "https://pleasanter.exapmle.com/Users/SamlLogin",
            "AuthenticateRequestSigningBehavior": "IfIdpWantAuthnRequestsSigned",
            "OutboundSigningAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
            "MinIncomingSigningAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
            "ServiceCertificates": []
        },
        "IdentityProviders": [
            {
                // Azure ADの画面で確認した、「プリザンター(Qiita)のセットアップ」の「Azure AD 識別子」
                "EntityId": "https://sts.windows.net/........./",
                // 「プリザンター(Qiita)のセットアップ」の「ログインURL」
                "SignOnUrl": "https://login.microsoftonline.com/......../saml2",
                "LogoutUrl": null,
                "AllowUnsolicitedAuthnResponse": true,
                "Binding": "HttpPost",
                "WantAuthnRequestsSigned": false,
                "DisableOutboundLogoutRequests": true,
                "LoadMetadata": false,
                "MetadataLocation": null,
                "SigningCertificate": {
                    "StoreName": "CurrentUser",
                    "StoreLocation": "My",
                    "X509FindType": "FindByThumbprint",
                    // 「SAML 署名証明書」の「拇印」
                    "FindValue": "ABCDEF01234567ABCDEF"
                }

            }
        ]
    }
}
```

## 動作確認

プリザンターを再起動し、ログイン画面を表示します。
設定がうまく出来ていれば、ログイン画面に「SSOログイン」のアイコンが表示されていると思います。

クリックして、問題無くログイン出来れば完了です。
~~なお、プリザンターでは、認証が通れば、プリザンター側にアカウントが無くても、自動でアカウントが作成されるようになっているようです。~~
2021/5/24 修正：上記の記載は誤りでプリザンター側にアカウントがないと、ログイン画面に戻される仕様となっているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25028/65eba1f5-6c13-2966-bdde-c1fcb7d01118.png)

## 補足：リバースProxy環境で使う場合

プリザンターをリバースProxyでSSL化して、SAML認証する場合、次の設定が必要です。
具体的には、SAML認証の際に内部で生成されるURLがhttpsとならず、AzureAD側で設定したACS URLとマッチせず、エラーとなってしまいます。

プリザンターでは、SAML認証に Sustainsys.Saml2 というパッケージが利用されていますが、こちらのパラメタ(publicOrigin)を触る必要があります。
~~2021/5/22現在のコードでは、このパラメタを触ることが出来ないため、次のパッチを当て、ビルドしなおしました。~~

Pleasanter.NetCore 1.1.30.0以降で、本家に取り込んで頂きましたので次のパッチは不要です。


```
diff --git a/Implem.ParameterAccessor/Parts/SPOptions.cs b/Implem.ParameterAccessor/Parts/SPOptions.cs
index a5b01dd4..db607be9 100644
--- a/Implem.ParameterAccessor/Parts/SPOptions.cs
+++ b/Implem.ParameterAccessor/Parts/SPOptions.cs
@@ -7,6 +7,7 @@ namespace Implem.ParameterAccessor.Parts
     {
         public string EntityId;
         public string ReturnUrl;
+        public string PublicOrigin;
         public string AuthenticateRequestSigningBehavior;
         public string OutboundSigningAlgorithm;
         public string MinIncomingSigningAlgorithm;
diff --git a/Implem.Pleasanter/Libraries/DataSources/Saml.cs b/Implem.Pleasanter/Libraries/DataSources/Saml.cs
index 667bcd79..337d4498 100644
--- a/Implem.Pleasanter/Libraries/DataSources/Saml.cs
+++ b/Implem.Pleasanter/Libraries/DataSources/Saml.cs
@@ -227,6 +227,9 @@ namespace Implem.Pleasanter.Libraries.DataSources
                 = paramSPOptions.ReturnUrl.IsNullOrEmpty() ? null : new Uri(paramSPOptions.ReturnUrl);
             options.SPOptions.EntityId
                 = paramSPOptions.EntityId.IsNullOrEmpty() ? null : new EntityId(paramSPOptions.EntityId);
+            options.SPOptions.PublicOrigin
+                = paramSPOptions.PublicOrigin.IsNullOrEmpty() ? null : new Uri(paramSPOptions.PublicOrigin);
+
             options.SPOptions.MinIncomingSigningAlgorithm
                 = paramSPOptions.MinIncomingSigningAlgorithm
                 ?? options.SPOptions.MinIncomingSigningAlgorithm;
@@ -473,4 +476,4 @@ namespace Implem.Pleasanter.Libraries.DataSources
             return true;
         }
     }
-}
\ No newline at end of file
+}
```

その上で、次のように「Authentication.json」の「SamlParameters.SPOptions.PublicOrigin」に
「https://プリザンターのURL」を設定する必要があります。

```json:Implem.Pleasanter/App_Data/Parameters/Authentication.json
{
//・・・・・・ 中略
    "SamlParameters": {
//・・・・・・ 中略
        "SPOptions": {
            "PublicOrigin": "https://pleasanter.exapmle.com",
```

[^1]: リバースProxyなどを入れてSSL化する必要あり