KeycloakでSAMLを使ってみる（WordPress編）

# 今日やること

Keycloakアドベントカレンダー4日目の今回は、SAMLを利用したKeycloakとWordpressの連携を試してみます。Keycloakのドキュメント「[SAML VS OIDC] (http://www.keycloak.org/docs/latest/server_admin/index.html#openid-connect-vs-saml)」では、SAMLよりもOIDCを推奨するとありますが、SAMLは、OIDCより実績があり成熟しているため、採用しているシステムが多いとも言及されています。Keycloakでは、標準で SAML2.0とOIDC がSSO認証プロトコルとして利用できます。標準で利用できるSSO認証プロトコルのうち、今回は、SAML認証連携を試してみます。

# SAMLの概要
SAMLとは「Security Assertion Markup Language」の略称です。ドメインの異なるシステム間で安全に認証・認可情報の伝送を行うためOASIS(構造化情報標準促進協会）で定められたXMLベースのマークアップ言語規格です。様々なサービスにおいてSAMLを利用した認証連携が行われています。


# 動作確認用サーバー構成

Wordpressには、いくつかSAML用のプラグインがありますが、今回は、Wordpress ＋ OneLogin SAML SSOプラグインを使用してKeycloakとのSAML連携を確認します。以下のように動作確認用のサーバーを用意しました。KeycloakがIdentity Provider(IdP), WordpressがService Provider(SP)です。


| FQDN | OS | JDK | 構成 |  
| ----- | ----- | ----- | ----- |
| keycloak.example.com | CentOS7.1 | open-jdk 1.8.0_101 | Keycloak 3.3.0Final |
| wordpress.example.com | CentOS7.1 | | Wordpress + OneLogin SAML SSOプラグイン |

Keycloakのセットアップは、[KeycloakAdventCalendar](https://qiita.com/advent-calendar/2017/keycloak-by-openstandia) 2日目の記事を参照ください。また、Wordpressのセットアップは、[こちら](https://qiita.com/katakura__pro/items/07c02f691e673eb50cee)の記事をご覧ください。なお、Wordpressは日本語化していませんのでご了承ください :bow:

# Keycloakサーバー(IdP)側の設定

以下の手順は、管理者ユーザーでログインして行います。
<table><tr><td>:information_source: 以降の手順において、設定の入力項目が記述されていない項目は、デフォルト値で設定します。</td></tr></table>

## レルムの追加
画面左上の「レルムの選択」メニューから「レルムの追加」ボタンをクリックします。下記の通りにレルムを作成します。

  * 名前 : `wordpress`
  * 有効 : `オン`

![realm1.png](https://qiita-image-store.s3.amazonaws.com/0/208407/c8b72611-9e92-87cd-316c-3bbfe8947f36.png)


## クライアントの追加・設定  

1. クライアントの追加  
  1. レルムから「wordpress」を選択し、「クライアント」メニューをクリックします。  
  1. 画面右の「作成」ボタンをクリックします。  
  1. クライアントの設定は以下のとおり設定し、「保存」ボタンをクリックします。  
        * クライアントID : `https://wordpress.example.com/`  
        * クライアントプロトコル : `saml`  
![client1.png](https://qiita-image-store.s3.amazonaws.com/0/208407/6f9f5ec4-7eb3-74af-1922-68961d5fbdee.png)
1. クライアントの詳細設定を行います。
「設定」タブから、以下を設定します。  
  * 設定
      * 名前 : `wordpress`(任意)  
      * 有効 : `オン` (デフォルト)
      * AuthnStatement を含める : `オン`
      * ドキュメントを署名する : `オン`
      * アサーションを署名する : `オン`
      * 署名アルゴリズム : `RSA_SHA256`
      * SAML Signature Key Name : `KEY_ID`
      * 正規化方式 : `EXCLUSIVE`
      * クライアント署名が必須 : `オン`  
      * POST Binding を強制 : `オン`  
      * フロントチャンネルログアウト : `オン`  
      * Name ID フォーマットを強制 : `オン`  
      * Name ID フォーマット : `username`  
      * ルート URL :  `https://wordpress.example.com/`  
      * 有効なリダイレクト URI : `https://wordpress.example.com/*`
  * SAML エンドポイントの詳細設定
      * アサーションコンシューマサービスの POST Binding URL : `https://wordpress.example.com/`  
      * アサーションコンシューマサービスの Redirect Binding URL : `https://wordpress.example.com/`  
1. 「保存」ボタンをクリックします。  
1. 「SAML鍵」タブをクリックし、署名鍵が作成されていない場合、「新しい鍵を生成」ボタンをクリックします。  
1. クライアントのマッパーの設定を行います。  
SAMLで属性連携を行うための属性マッピング設定です。今回は、Wordpressユーザーの必須属性である`username`と`email`の設定を行います。「マッパー」タブをクリックし、「作成」ボタンをクリックします。  
  1. usernameマッパーの作成  
      * 名前 : `username`
      * マッパータイプ : `User Property`
      * プロパティ : `username`
      * SAML Attribute Name : `username`  
      * SAML Attribute NameFormat : `Basic`  
  1. 「保存」ボタンをクリックします。  
  1. 「作成」ボタンをクリックします。
  1. emailマッパーの作成。
      * 名前 : `email`
      * マッパータイプ : `User Property`
      * プロパティ : `email`
      * SAML Attribute Name : `email`  
      * SAML Attribute NameFormat : `Basic`  
    1. 「保存」ボタンをクリックします。

※ クライアント作成時にデフォルトで作成される`role list`マッパーをそのまま使用するとOneLoginSSO側でエラーとなります。`role list`マッピングを削除するか、`role list`の編集から`Single Role Attribute`を`ON`に変更してください。
## SAML鍵タブから鍵情報を取得

SP側の設定で必要となりますので、秘密鍵と証明書のテキストエリアの文字列をそれぞれ控えておきます。
![saml-key.png](https://qiita-image-store.s3.amazonaws.com/0/208407/65763a52-5fbc-843d-0e6b-897e31d9efe3.png)


## Keycloakへユーザーを追加

作成したレルムへユーザーを追加します。

1. 管理コンソールへログインします。  
1. wordpressレルムを選択します。
1. 「管理」－「ユーザー」メニューをクリックします。
1. 「ユーザーの追加」ボタンをクリックします。
  * 以下の通り入力します。
      * ユーザー名 : `wp-user1`  
      * Eメール : `wp-user1@example.com`  
      * ユーザーの有効 : `オン`  

1. 「保存」ボタンをクリックします。
1. 作成したユーザーの「クレデンシャル」タブからパスワードを設定します。
「新しいパスワード」・「新しいパスワード(確認)」項目へ同じパスワードを入力します。
「一時的」項目はオフにします。
1. 「パスワードをリセット」ボタンが表示されますので、クリックします。
1. 確認のポップアップが表示されますので、「Change Password」ボタンをクリックします。

パスワード変更確認のポップアップ画面が日本語化されていませんでしたが、以上でユーザーの追加は完了です。

# Wordpressサーバー(SP)側の設定

## SAML用SSOプラグインのインストール
1. プラグインをダウンロードします  
[OneLogin SAML SSO プラグイン](https://ja.wordpress.org/plugins/onelogin-saml-sso/)
2. Wordpressにプラグインを追加します。  
  1. wordpressの管理コンソールから「Plugins」メニューをクリック
  1. 「Add New」ボタンをクリック
  1. 「Upload Plugin」ボタンをクリック
  1. 「参照」からダウンロードしたプラグインを選択して「Install Now」をクリック
  1. 追加したプラグインを有効化する(Activateボタン)  

プラグインのインストールは完了です。

## SAML用SSOプラグインの設定
プラグインの設定には、IdPの情報が必要です。KeycloakのSAML情報エンドポイントへアクセスして情報を取得します。https://keycloak.example.com/auth/realms/wordpress/protocol/saml/descriptor へアクセスすると以下のようなXMLが取得できます。

```
<?xml version="1.0" encoding="UTF-8"?>
<EntitiesDescriptor Name="urn:keycloak" xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
	<EntityDescriptor entityID="https://keycloak.example.com/auth/realms/wordpress">
		<IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
                        <KeyDescriptor use="signing">
                          <dsig:KeyInfo>
                            <dsig:KeyName>xdyS...HLxc</dsig:KeyName>
                            <dsig:X509Data>
                              <dsig:X509Certificate>MIICnT...RXx3Aw==</dsig:X509Certificate>
                            </dsig:X509Data>
                          </dsig:KeyInfo>
                        </KeyDescriptor>

			<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://keycloak.example.com/auth/realms/wordpress/protocol/saml"/>
			<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://keycloak.example.com/auth/realms/wordpress/protocol/saml"/>
			<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
			<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
			<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
			<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
			<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://keycloak.example.com/auth/realms/wordpress/protocol/saml"/>
			<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://keycloak.example.com/auth/realms/wordpress/protocol/saml"/>
			<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://keycloak.example.com/auth/realms/wordpress/protocol/saml"/>
		</IDPSSODescriptor>
	</EntityDescriptor>
</EntitiesDescriptor>
```

<table><tr><td>:warning: 上記XML中の秘密鍵や証明書文字列は、長いため省略しています。</td></tr></table>  

1. wordpressの管理コンソールから「Settings」メニューをクリック  
1. 「Settings」メニュー内の「SSO/SAML Settings」メニューをクリック
1. 対応する項目をそれぞれ埋めてゆきます。
設定項目名が記載していないものは、デフォルト(設定なし）です。  

  1. IDENTITY PROVIDER SETTINGS  
      * IdP Entity Id : `EntityDescriptor`タグ`entityID`の値(XMLから取得)  
      * Single Sign On Service Url : `SingleSignOnService`タグの`urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST`の値(XMLから取得)
      * Single Log Out Service Url : (設定なし)
      * X.509 Certificate : `KeyDescriptor`タグの`dsig:X509Certificate`の値(XMLから取得) **(注1)**  
![wordpress-plugin-setting-cut1.png](https://qiita-image-store.s3.amazonaws.com/0/208407/e9ae3080-4a7c-5ac8-1b3d-d5fbdbede68e.png)
  1. OPTIONS
      * Force SAML login : `check`
      * Match Wordpress account by : `Username`  
![wordpress-plugin-setting-cut2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/501ebaf3-05d8-85b2-b8c9-334c1c671e83.png)
  1. ATTRIBUTE MAPPING
      * Username : `username`
      * E-mail : `email`  
![wordpress-plugin-setting-cut3.png](https://qiita-image-store.s3.amazonaws.com/0/208407/20ee10b3-9eae-0fed-fc05-36ff5d5368a5.png)
  1. ADVANCED SETTINGS
      * Service Provider Entity Id : `https://wordpress.example.com/`
      * Sign AuthnRequest : `check`
      * NameIDFormat : `urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified`
      * requestedAuthnContext : `urn:oasis:names:tc:SAML:2.0:classes:unspecified`
      * Service Provider X.509 Certificate : `Keycloakサーバー(IdP)側の設定 5. で取得したSAML鍵の証明書の値` **(注1)**  
      * Service Provider Private Key : `Keycloakサーバー(IdP)側の設定 5. で取得したSAML鍵の秘密鍵の値の値` **(注1)**  
      * Signature Algorithm : `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
      * Digest Algorithm : `http://www.w3.org/2001/04/xmlenc#sha256`  
![wordpress-plugin-setting-cut4.png](https://qiita-image-store.s3.amazonaws.com/0/208407/44f92051-044f-6fa7-b9f4-a7bcf100196e.png)
3. SaveChangesボタンをクリック

<table><tr><td>:warning: <b>(注1) 証明書や秘密鍵項目では、以下のように <code>BEGIN</code>/<code>END</code> の宣言を記述しなければなりません。</b>  </td></tr></table>

```
-----BEGIN CERTIFICATE-----
証明書文字列  
-----END CERTIFICATE-----  

-----BEGIN RSA PRIVATE KEY-----  
秘密鍵文字列  
-----END RSA PRIVATE KEY-----  
```

これでプラグイン設定は完了です。

## Wordpressユーザーの追加

Wordpressへユーザーを追加します。  

1. wordpressの管理コンソールから「Users」メニューをクリック  
1. 「Add New」ボタンをクリック
1. 以下のユーザーを追加します。
  * wp-user1
      * Username : `wp-user1`  
      * Email : `wp-user1@example.com`  
      * Send User Notification : `オフ`  
上記設定以外は、デフォルト(設定なし・オフ)です。  
1. 「Add New User」ボタンをクリックします。

# 動作確認

Wordpressをログアウトし、wordpressのトップページへアクセスしてみましょう。OneLogin SAML SSO プラグイン設定の`Force SAML login`項目がオンになっているため、Keycloakのログイン画面が表示されます。それでは、作成した`wp-user1`ユーザーでログインしてみます。
![keycloak-saml-login2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/358a2665-9baf-7e5a-5d9d-6fe24e97b765.png)

Wordpressへログインすることができました！
![login-success.png](https://qiita-image-store.s3.amazonaws.com/0/208407/73eb416c-2d1d-46ee-6257-eafe55d712ce.png)

# JIT(Just In Time)プロビジョニング
JITプロビジョニングとは、SP側にユーザーが存在しない場合に、IdPのユーザー情報を属性マッピングに従ってSPへ連携し、ユーザーを作成・設定する機能のことです。JITプロビジョニングは、属性マッピングをしっかり設定しておかなくてはいけませんが、ユーザーの管理をサービスごとに行わなくて済むというメリットがあります。

Wordpressの「SSO/SAML Settings」の「Create user if not exists」の項目にチェックを入れます。ユーザー属性がKeycloak側で変更された場合に、Wordpressへ更新を連携する場合は、「Update user data」項目にチェックを入れます。

* SSO/SAML Settings
  * Options
      * Create user if not exists : `check`
      * Update user data : `check`  
![user-add1.png](https://qiita-image-store.s3.amazonaws.com/0/208407/8fd9e76e-f902-1de9-1088-b88fe6c3fb9b.png)

Keycloakで以下のユーザーを作成して試してみましょう。

  * ユーザー名 : `wp-user2`  
  * Eメール : `wp-user2@example.com`  

![user-add2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/3522bf26-2da9-5509-91e7-b937e4f52887.png)

「クレデンシャル」タブから、`wp-user2`のパスワードも設定しておきます。ブラウザを立ち上げなおして、wordpressのトップページへアクセスしします。ログイン画面が表示されたら`wp-user2` でログインしてみます。
![user-add3.png](https://qiita-image-store.s3.amazonaws.com/0/208407/bdc48312-d06e-ca56-c41c-01580f8c2535.png)

Wordpressにユーザーを作成しなくても、ログインすることができました。
![user-add4.png](https://qiita-image-store.s3.amazonaws.com/0/208407/96a9809c-eeed-cc02-9ed0-86303ea3a50c.png)

管理者ユーザーでユーザーの一覧を確認してみると、wp-user2が追加されています！
![user-add5.png](https://qiita-image-store.s3.amazonaws.com/0/208407/61308b82-86c7-5cf6-ec9d-669a71f38867.png)


# まとめ

今回SAMLによる認証連携を試してみました。プラグイン設定の証明書や秘密鍵の記述方法などの”はまり”ポイントがありますが、無事にSSOすることができました。今回試したSAMLシーケンスは、以下の通りです。
![SAML_new2.png](https://qiita-image-store.s3.amazonaws.com/0/208407/cca7d129-9e1b-7403-ca55-a4251120e635.png)

ありがとうございました。

# 参考資料

* [SAML | Keycloak Documentation] (http://www.keycloak.org/docs/latest/server_admin/#_saml)

* [NRI OpenStandia Keycloak日本語ドキュメント | SAML] (http://keycloak-documentation.openstandia.jp/master/ja_JP/server_admin/index.html#_saml)

* [Wordpress] (http://wordpress.org/)

* [OneLogin SAML SSO] (https://ja.wordpress.org/plugins/onelogin-saml-sso/)