はじめに
Slack cloneとして有名なMattermostですが、完成度は非常に高いのですが残念ながらSAMLによるSSOに関しては有償版のEnterprise E20でないと提供されていません。フリー版のTeam EditionやEnterprise E10を使ってSSOしたい場合は、下記の記事などで紹介されているとおり、GitLabと組み合わせる必要がありました。
MattermostはGitLabを使ってのログイン機能であれば全エディションで利用可能なため、
Mattermost --GitLabログイン機能--> GitLab --SAMLでログイン--> Keycloak
というログイン連携ができるわけです。
GitLabを使っているところならこれでいいのですが、Mattermostだけ使いたいんだよ、という場合はこれだと困ります。MattermostはOSSなのでソース改修すれば対応できるでしょうが、改修なしで何とか認証連携できないか?と探ってみたところ、実現方式を思いついたので今回紹介したいと思います。
方式
実はMattermostのGitLabログイン機能は、連携の際のHTTPリクエスト/レスポンスを見ると、単にOAuth2.0の認可コードフローでID連携しているということが分かります。つまり、OAuth2.0に対応した認可サーバを使えば別にGitLabでなくても連携ができてしまう可能性があります。これにより、Keycloakを使えば
Mattermost --GitLabログイン機能(OAuth2.0)--> Keycloak
という構成がとることができます。ただし、いくつか注意点がありますので設定方法とともに説明します。
動作確認したバージョン
- Keycloak: 3.4.3.Final
- Mattermost: 4.10.0
設定方法
前提として、Keycloakが既にインストール済みで、連携用にsample
レルムが作成済みの状態、とします。KeycloakのインストールはKeycloakのセットアップを、レルムの作成についてはKeycloakでOpenID Connectを使ってみるなどの記事を参考にするとよいでしょう。
MattermostとのSSOの設定手順としては、
- KeycloakにMattermost用のクライアントを登録する
- クライアントの登録
- Mapperの編集
- テスト用ユーザの登録
- MattermostにGitLab認証を設定する
となります。以下、詳細を説明していきます。なお、注意点として今回はすべてHTTPで通信しておりHTTPSを利用していませんが、実環境ではセキュリティのためHTTPSを使うようにしてください(OAuth2はHTTPSであることを前提としているため)。
KeycloakにMattermost用のクライアントを登録する
クライアントの登録
KeycloakにSSO対象のアプリケーションを登録する場合は、クライアントと呼ばれるものを登録する必要があります。また、KeycloakにはこのクライアントのプロトコルとしてOpenID ConnectとSAMLの二種類があります。MattermostのGitLabログイン機能はOAuth2を利用しているため、作成するクライアントのプロトコルにはopenid-connect
を選択します(OpenID ConnectはOAuth2をベースとしているため、OAuth2を喋ることもできます)。
Keycloakの管理コンソールにログインし、sample
レルムにて画面左メニューのConfigure > Clients
からクライントを登録します。ポイントとなる設定箇所は下記のとおりです。
- Standard Flow Enabled:
ON
- Access Type:
confidential
- Valid Redirect URIs:
http://<MattermostのFQDN>/signup/gitlab/complete
また、Credential
タブを開きSecretの値をコピーしておきます。この値とクライアント登録時に設定したClient IDの値をMattermost側に後ほど設定します。
Mapperの編集
MattermostにSSOログインする際に、MattermostはOAuth2のアクセストークンを利用してKeycloakのUserInfoエンドポイントにアクセスし、そのレスポンス値に含まれるユーザ情報を利用してMattermostにログインする仕組みとなっています。Mattermost側としては、返されるユーザ情報としては以下のGo言語の構造体で表現されるJSONデータを期待しています。
type GitLabUser struct {
Id int64 `json:"id"`
Username string `json:"username"`
Login string `json:"login"`
Email string `json:"email"`
Name string `json:"name"`
}
よって、KeycloakのUserInfoエンドポイントでは上記項目を返すように設定を行う必要があります。KeycloakではMapperと呼ばれる機能で返す値を細かくカスタマイズできますので、上記構造体に合うように設定していきます。デフォルトだと、以下のような内容でKeycloakはユーザ情報を返します。
{
"sub": "c092a81a-1835-493f-95a7-46c7b8d4dff1",
"name": "test test",
"preferred_username": "test",
"given_name": "test",
"family_name": "test",
"email": "test@example.org"
}
そのため、KeycloakのMapperの設定にて
-
preferred_username
=>username
に変更 -
id
項目を新規に追加
を行います。login
項目はMattermost側は必須ではないようなので(username
がない場合に代わりに使用される)、今回はなしとしています。
作成したクライアントのMappers
タブを開き、以下の設定を行います。
-
username
の設定を開き、Token Claim Nameの設定値をusername
に変更する - 新規にMapperの追加を下記設定項目で行う
- Name:
mid
- MapperType:
User Attribute
- User Attribute:
mid
- Token Claim Name:
id
- Claim JSON Type:
long
- Add to userinfo:
ON
- Name:
Nameは任意名称で構いません。User AttributeはMattermost側のアカウントとリンクするために使われるIDを格納するための、ユーザのカスタム属性名となります。今回はmid
(Mattermost Id)としました。
テスト用ユーザの登録
SSOログインテスト用にユーザをKeycloakの管理コンソールから登録しておきます。
- First Name
- Last Name
がMattermostで使用される属性なのでこれらを入力しておきます。
また、アカウントリンク用のカスタム属性(今回の設定例だとmid
属性)も設定しておきます。値は、1以上としておきます(0はMattermost側で無効と判断されるので注意)。
注意点
このカスタム属性が他のユーザと被ってしまった場合、MattermostへSSOログインのタイミングでMattermost側のユーザテーブルの同IDのレコードが存在すると上書きされてしまうようです。よって、実運用においてはこの値が被らないようユーザごとに必ず一意になる仕組みを考える必要があります。この対応が地味に面倒な予感がします。
MattermostにGitLab認証を設定する
MattermostのSystem Console > AUTHENTICATION > GitLab から連携設定を有効化します。用意したClient IDとSecretをここで設定します。また、ここでOAuth2のエンドポイントURL設定を行うのですが、GitLab Site URL
しか入力できず、エンドポイント単位に細かく設定できません。そのため、Keycloakが提供する形式のOAuth2エンドポイントURLを設定することができません。
対応策として、以下の2方式を思いつきました。どちらでも対応可能でした。
A) Keycloakの前段にリバースプロキシを配置しURL置換を行う
例えばApache HTTPD Serverを使う場合は、mod_rewrite
を使って以下のように設定すればOKです(Apacheと同じサーバでKeycloakを8080ポートで動かしている場合)。
RewriteEngine On
RewriteRule ^/auth/realms/(.*)/api/v4/user http://localhost:8080/auth/realms/$1/protocol/openid-connect/userinfo [P,L]
RewriteRule ^/auth/realms/(.*)/oauth/authorize http://localhost:8080/auth/realms/$1/protocol/openid-connect/auth [P,L]
RewriteRule ^/auth/realms/(.*)/oauth/token http://localhost:8080/auth/realms/$1/protocol/openid-connect/token [P,L]
B) GUIで設定せずMattermostの設定ファイルを直接編集する
MattermostではGitLabログインの設定はconfig.jsonファイルで設定できるようになっています。GUIで設定せず、このファイルを直接編集することで細かくOAuth2エンドポイントURLを設定することができます。
例えば、Keycloakのsample
レルムでSSOログインさせるには、以下のような設定になります。
"GitLabSettings": {
"Enable": true,
"Secret": "694ce9b7-9bed-4961-9ad2-8c680a9e1daa",
"Id": "mattermost",
"Scope": "",
"AuthEndpoint": "http://sso.example.org/auth/realms/sample/protocol/openid-connect/auth",
"TokenEndpoint": "http://sso.example.org/auth/realms/sample/protocol/openid-connect/token",
"UserApiEndpoint": "http://sso.example.org/auth/realms/sample/protocol/openid-connect/userinfo"
},
動作確認
Mattermostの画面にアクセスし、画面下部に表示されるSign in withからGitLabをクリックします。GitLabの代わりにKeycloakを設定しているため、Keycloakのログイン画面が表示されますので、登録しておいたテスト用ユーザでログインします。ログイン後Mattermostにリダイレクトで戻りますが、OAuth2の設定が正しくされていれば無事にSSOログインできているはずです。
本当は「GitLab」という文字列の代わりに「Keycloak」とか任意名称に変えれると良いですが、MattermostはUIカスタマイズができるっぽいのでそちらで対応可能かもしれませんね。
まとめ
Mattermostのフリー版のTeam Editionでも実現可能なSSOの設定方法について紹介しました。今回はSSOサーバにKeycloakを利用していますが、OAuth2に対応している認可サーバでUserInfoエンドポイントがあり(つまり、OpenID Connectに対応していれば、ですね)、返すユーザ属性をMattermost側が期待する内容にカスタマイズできるのであれば、おそらく連携できるのではないかと思います。