シングルサインオンサービスKeycloakとWikiシステムGrowiを連携する

# TL;DR

* SSOサービスKeycloakと，WikiシステムGrowiを，連携させる方法を説明します
    * 両者が，Dockerコンテナで稼働している状況で進めます
    * 各サービスのコンテナ立ち上げ方法は以下の参考リンクをご覧ください
        * [OSSなシングルサインオンサービスKeycloakをdockerで立ち上げる](https://qiita.com/myoshimi/items/7e9f1de7373427233880)
        * [Growi(Markdown記法によるWikiプラットフォーム)をdocker-composeで稼働させる](https://qiita.com/myoshimi/items/f7029c3d86869dc13ae5)
* GrowiへのログインがKeycloakへのログインに置き換えられます
    * KeycloakはGrowi以外のサービスへも連携できるので，Keycloakでユーザを作ると，連携した他のサービスのユーザ作成が不要になります

# 手順

* Keyclock，Growi両方で設定が必要です
* Keyclock:
    * Keycloak側でRealm(レルム，領域)を作成し，ユーザやグループを作ります
    * Keycloakで，Growi用のClientを作成し，Growiからのリクエストを受け付けます
* Growi:
    * SAMLの設定を行い，Keycloakに接続します

# Keycloakの設定

* Administration Consoleで作業を行います

## Realmの作成

* まず，（複数の）Webサービスで利用する，Realmを作成します
* 画面左上のドロップダウンリストから，"Add Realm"を選択します（最初は"Master"になっている）
   * ![01_addRealm.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/6added43-229c-a34c-553b-1e72f168a78c.jpeg)

* Name: "dev"のような適当な名前を付けてCreateします
   * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/6c75d155-b4e4-abf3-2cd3-6f00c36107d5.jpeg" width=50%>
* 画面左上の選択中のRealmが"dev"になっていることを確認してください

### X.509証明書の取得

* 以下のような，Realmを指定したURLにアクセスすると，Realmの情報を見ることができます

```
https://sso.example.com/auth/realms/dev/protocol/saml/descriptor
```

* <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/3e95d301-8d1b-1a15-3c32-d59d63bd7b0d.jpeg" width=50%>
* 後に使用するので，```<dsig:X509Certificate>```タグ内の，```MII〜```で始まる文字列をコピーしておきます

### ユーザの作成

* 画面左のメニューから，"Manage"カテゴリの"Users"をクリックします
    * 画面右に表示される"Add User"をクリックし，ユーザを作成します
    * Username, Email, First Name, Last Nameを入力し，"Save"します
    * メール設定をしていない場合は"Email Verified"をONにしておきます
    * ![04_usersAdd.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/0d786328-8941-9883-42b8-77f93865591e.jpeg)
* "Credentials"タブで，パスワードを設定します
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/74175581-20ac-114e-540e-350ac809935a.jpeg" width=50%>
    * "Temporary"をONにしておくと，初回ログイン時にパスワードの変更を求められます（不要であればOFFにします）

## Growi用Clientの作成

* Growiが接続されるClientを作ります
* 画面左のメニューから"Clients"を選択します
* "Lookup"タブから，"Create"ボタンをクリックします
    * ![06_createClient.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/56a83d2b-da09-bd77-c9df-44cd685a8a9f.jpeg)
* Client IDにサービス名を設定して"Save"します（今回の場合は```growi```にしました．）
    * 他の設定は後ほど変更します
* 後述の説明にしたがって，各タブに設定をします
    * Settingsタブと，Mappersタブで設定を記述します

### Settingsタブ

* 表の通り設定します
    * 修正の必要がある項目と，ONにしている部分だけを抜粋しています
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/5d4bb5b6-53e1-9d74-3491-535bcb04551d.jpeg" width=50%>

| 設定名                     | 設定値                                                                                    |
| -------------------------- | ----------------------------------------------------------------------------------------- |
| Client ID                  | growi                                                                                     |
| Enabled                    | ON                                                                                        |
| Client Protocol            | saml                                                                                      |
| Include AuthnStatement     | ON                                                                                        |
| Sign Documents             | ON                                                                                        |
| Sign Assertions            | ON                                                                                        |
| Signature Algorithm        | RSA_SHA1                                                                                  |
| SAML Signature Key Name    | KEY_ID                                                                                    |
| Canonicalization Method    | EXCLUSIVE                                                                                 |
| Force POST Binding         | ON                                                                                        |
| Front Channel Logout       | ON                                                                                        |
| Force Name ID Format       | ON                                                                                        |
| NAME ID Format             | username                                                                                  |
| Root URL                   | GrowiのURL(e.g. ```https://growi.example.com/```)                                         |
| Valid Redirect URIs        | GrowiのURL以下の領域 (e.g. ```https://growi.example.com/*```                              |
| Master SAML Processing URL | ログイン後のコールバックURL (e.g. ```https://growi.example.com/passport/saml/callback```) | 

* さらに，"Fine Grain SAML Endpoint Configuration"を展開して，以下の設定を行います

| 設定名                                          | 設定値                                                                                    |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------- |
| Assertion Consumer Service POST Binding URL     | GrowiのURL(e.g. ```https://growi.example.org/```)       |
| Assertion Consumer Service Redirect Binding URL | ログイン後のコールバックURL (e.g. ```https://growi.example.com/passport/saml/callback```) |
| Logout Service Redirect Binding URL             | ログイン後のコールバックURL (e.g. ```https://growi.example.com/passport/saml/callback```) |

### Mappersタブ

* Mappersタブで，Growiのユーザ情報として必要な情報と，keycloakで管理しているユーザ情報を紐付けます
* "Create"ボタンをクリックして，以下の表の通り，マッピングするエントリを追加します
    * まず"Mapper Type"のドロップダウンリストからTypeを選択すると，入力が必要となるフォームが表示されます

| Name      | Mapper Type   | Property  | Friendly Name | SAML Attribute Name | SAML Attribute NameFormat |
| --------- | ------------- | --------- | ------------- | ------------------- | ------------------------- |
| username  | User Property | username  | username      | username            | Basic                     |
| id        | User Property | id        | id            | id                  | Basic                     |
| email     | User Property | email     | email         | email               | Basic                     |
| firstName | UserProperty  | firstname | firstname     | firstname           | Basic                     |
| lastName | UserProperty  | lastname | lastname     | lastname           | Basic                     |

* 以下のように設定されます
    * 全体
        * ![08_mappers.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/14607230-3ad2-4708-2844-ae6939443c2c.jpeg)
    * 各エントリ
        * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/0ffaef05-2ded-8822-853b-b601f2fafddf.jpeg" width=50%>

# Growiの設定

* 管理者権限を持つアカウントでログインして作業します
    * GrowiはGUIでKeycloak（SAML認証）との接続ができます
* "管理"をクリックし，"セキュリティ設定"を選びます
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/18314eb5-7268-a73f-f22d-0db6db8bf920.jpeg" width=50%>
* "認証機構設定"で，"SAML"タブをクリックします
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/f334f6ef-6653-cd89-e08d-f893ba2cd97e.jpeg" width=50%>
* 以下の表の通り，SAML設定を行います
* 必要な情報を入力後，"更新"をクリックして設定を保存します

| 設定名                    | 設定値                                                                                                             |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| SAML                      | ON                                                                                                                 |
| コールバックURL           | ログイン後のコールバックURL (e.g. ```https://growi.example.com/passport/saml/callback```)                          |
| エントリーポイント        | keycloakの当該Realmに対するSAMLエントリポイント (e.g. ```https://sso.example.com/auth/realms/dev/protocol/saml```) |
| 発行者                    | issuers．Clientで設定したClient ID (今回の場合は```growi```)                                                       |
| 証明書                    | 後述                                                                                                               |
| ID                        | id                                                                                                                 |
| ユーザー名                | username                                                                                                           |
| メールアドレス            | email                                                                                                              |
| 姓                        | lastName                                                                                                           |
| 名                        | firstName                                                                                                          |
| Attribute Mapping Options | チェックしない |

## x.509証明書について

* KeycloakのRealms設定のときに取得した，x.509証明書を，当該欄に記載します．
    * ![12_growiCertificate.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/61c0d174-367d-a1da-626a-8693bd2d0c62.jpeg)
    * 文字列に，```-----BEGIN CERTIFICATE-----```と```-----END CERTIFICATE-----```の行を先頭と末尾にそれぞれ追加します

```
-----BEGIN CERTIFICATE-----
MII〜
-----END CERTIFICATE-----
```

# 動作確認

* いったんログアウトすると，Growiのログイン画面に移りますが，このとき，ログイン画面に"OAuth"という文字が表示されるようになります
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/663e7232-4cc6-76d7-0005-7f5cd15acb3d.jpeg" width=50%>
* マウスを近づけると，"ログイン" with SAMLというボタンが出現するので，クリックします
    * ![14_growiLogin.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/e57e08dc-db10-a696-1ac7-9d5be8928c96.jpeg)
* Keycloakのログイン画面に遷移しますので，Realmで作成したユーザでログインします
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/fb4bcac6-d3f8-6a1b-2c73-2bd8d555dfeb.jpeg" width=50%>
* Growiの画面に遷移し，作業を開始することができます
    * <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/a973c375-926a-c8f7-db80-8fe7c294e898.jpeg" width=50%>

# 参考

* [OSSなシングルサインオンサービスKeycloakをdockerで立ち上げる](https://qiita.com/myoshimi/items/7e9f1de7373427233880)
* [Growi(Markdown記法によるWikiプラットフォーム)をdocker-composeで稼働させる](https://qiita.com/myoshimi/items/f7029c3d86869dc13ae5)