Keycloak を使用したシングルサインオン

シングルサインオンについて調べる機会がありkeycloakを使用してみたので、忘れないうちにまとめておきます。

広告

環境

  • Java(jdk 1.8.0_221)
  • docker desktop(2.1.0.3)
  • eclipse(2019-06)
    – Spring Tools 3(3.9.11)
  • keycloak(12.0.4)

最終的にできあがるもの

  • 認証サーバー(keycloak)
  • サーバーアプリケーション(API)
    – 認証が必要な機能がある
  • クライアントアプリケーション
    – 上記APIを呼び出して使用する画面
    – 一回のログインでAPIが利用可能になる

インストール

公式サイトの Get started with Keycloak on Docker を参照して導入します。
https://www.keycloak.org/getting-started/getting-started-docker

コマンド:

docker run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:12.0.4

※環境変数の「KEYCLOAK_USER」「KEYCLOAK_PASSWORD」の値で管理者ユーザが作成されます。

管理画面へログイン

インストールが完了したらkeycloakへログインします。
http://localhost:8080/auth/admin
ログインIDとパスワードはコマンドで指定した管理者ユーザです。

※ログイン成功後にパスワード変更の警告が出ましたが(adminだから?)、無視して進めます。

日本語化

「Realm Settings」→「Themes」の「Internationalization Enabled」をONにし、
「Default Locale」で「ja」を選択してSaveします。

※Saveした直後は反映されません。左上のロゴをクリックしてトップページへ遷移し、
もう一度管理画面へ入ると反映されます。

レルム作成

左上の「Master」にマウスオーバーすると、「レルムの追加」ボタンが表示されるので押下します。

名前を入力して作成ボタンを押下します。

ロール作成

左メニューから「ロール」を選択し、ロールの追加ボタンを押下します。

ロール名を入力し保存ボタンを押下します。

ユーザ作成

左メニューから「ユーザー」を選択し、ユーザーの追加ボタンを押下します。

ユーザー名、名、姓に入力し保存ボタンを押下します。

パスワード設定

ユーザー作成後、詳細画面へ遷移するので「クレデンシャル」タブを表示しパスワードの設定を行います。

「一時的」項目をオンにしておくと、初回ログイン時にパスワード変更が求められます。
今回は必要ないのでオフにします。

ロール設定

「ロールマッピング」タブを表示しロールの設定を行います。
「user」ロールをアサイン済みロールへ移動させます。

ユーザー作成確認

アカウント管理画面を表示し、先ほど作成したユーザーでログインします。
http://localhost:8080/auth/realms/myrealm/account

ログインできました。

keycloakクライアント作成

keycloakを使用するクライアントを追加します。
この時点で実際のアプリケーションは作成していなくてもOKです。
左メニューから「クライアント」を選択し、作成ボタンを押下します。

クライアントID、クライアント・プロトコル、ルートURLを入力して保存ボタンを押下します。

サーバーアプリケーション作成

まずはSpting BootでAPIを作成します。
今回はquickstartsのservice-springboot-restをまるごと使用するのでgithubから持ってきます。(latestブランチ)
https://github.com/keycloak/keycloak-quickstarts/tree/latest/service-springboot-rest
このサービスには下記2つのエンドポイントがあります。

  • public: 認証なしで呼び出すことができる
  • products: 「user」ロールのユーザーのみ呼び出すことができる

application.properties変更

githubから持ってきたソースのapplication.propertiesを変更します。

server.compression.enabled: true
server.compression.min-response-size: 1
server.connection-timeout=5000
server.port = 8081 ※8080はkeycloakで使用しているので8081
keycloak.realm=myrealm ※先ほど作成したレルム
keycloak.auth-server-url=http://localhost:8080/auth ※keycloakのURL
keycloak.ssl-required=external
keycloak.resource=myclient ※先ほど作成したkeycloakクライアント
keycloak.public-client=true
keycloak.bearer-only=true
keycloak.securityConstraints[0].securityCollections[0].name = protected resource
keycloak.securityConstraints[0].authRoles[0] = user ※作成したロール
keycloak.securityConstraints[0].securityCollections[0].patterns[0] = /products
keycloak.securityConstraints[0].securityCollections[0].patterns[1] = /products/

keycloakクライアント変更

先ほど作成したkeycloakクライアントを変更します。
アクセスタイプを「bearer-only」、管理URLを「http://localhost:8081/」(サーバーアプリケーションのURL)に変更しました。

動作確認

public(http://localhost:8081/public) を呼び出してみます。

値が返却されました。

products(http://localhost:8081/products) を呼び出してみます。

401エラー(アクセス権限なし)になりました。

クライアントアプリケーション作成

次に、先ほど作成したサーバーアプリケーションを利用するるクライアントアプリケーションを作成します。
こちらもgithubのquickstartsのapp-springbootを使用します。(latestブランチ)
https://github.com/keycloak/keycloak-quickstarts/tree/latest/app-springboot

下記2つのページがあります。

  • public: 認証なしで表示できる
  • product: 認証が必要なAPI(上記で作成したサーバーアプリケーション)から値を取得して表示する

application.properties変更

githubから持ってきたソースのapplication.propertiesを変更します。

server.compression.enabled: true
server.compression.min-response-size: 1
server.connection-timeout=5000
spring.freemarker.cache=false
server.port = 8082 ※8082を指定
keycloak.realm=myrealm ※作成したレルム
keycloak.auth-server-url=http://localhost:8080/auth ※keycloakのURL
keycloak.ssl-required=external
keycloak.resource=myclient2 ※新しく追加するkeycloakクライアント(この後作成)
keycloak.public-client=true
product.service.url=http://localhost:8081/products ※先ほど作成したサーバーアプリケーションのproductのURL

keycloakクライアント追加

クライアントアプリケーション用のkeycloakクライアントを追加します。
先ほどと同じようにクライアントの作成ボタンから追加します。

動作確認1

実行しようとすると、エラーになりました。

java.lang.ClassNotFoundException: org.apache.http.client.methods.HttpUriRequest

pom.xmlの「httpclient」のscopeがtestになっているのが原因のようです。
scopeタグを消します。(masterブランチを確認したらscopeタグは削除されていたので、latestにもそのうち反映されるかも?)

pomの修正後、public(http://localhost:8082/) へ、アクセスしてみます。

画面が表示されました。

productsへ遷移してみます。

エラーになりました。設定が間違っているようです。

githubのreadmeのサンプルをそのまま採用したのが問題でした。
下記の設定を修正します。
※「8082/app-springboot」の「app-springboot」を削除します。

もう一度、productsへ遷移してみます。

ログイン画面にリダイレクトしました。

作成したユーザーでログインしてみます。

表示されました。

一旦ログインに成功したので、その後はログイン画面なしでAPIから値が取得されます。

動作確認2

ユーザーからロール「user」を外し

productsへ遷移してみます。

403エラー(閲覧禁止)になりました。
正常に認証できていることが確認できました。

最後に

シングルサインオンの調査の一環でkeycloakを使用しました。
実際にkeycloakが採用されるかはわかりませんが、
いざという時に今回の環境をベースにして使い方を学ぶ事ができると思います。