---
title: Spring Boot 1/2のアプリにKeycloakのOpenID Connectを使ってシングルサインオン
tags: ["Java", "Spring", "Spring Boot", "Spring Security", "Keycloak", "OpenID Connect"]
categories: ["Programming", "Java", "org", "springframework", "security", "oauth2"]
date: 2018-01-16T16:30:37Z
updated: 2018-01-16T18:26:05Z
---
KeycloakとSpring Bootを連携するために、RedHatより[`org.keycloak:keycloak-spring-boot-starter`](https://github.com/keycloak/keycloak/tree/master/misc/spring-boot-starter)というSpring Boot用のStarterライブラリが提供されていますが、これはKeycloakのAPIを使っています。Spring BootとKeycloakを合わせて検索するとだいたいこのライブラリが使われています。
KeycloakをOpenID Connectという標準仕様を使ってアクセスするのに、ベンダ提供ライブラリを使うとアプリケーションのポータビリティが損なわれるので、この記事ではSpringのOAuth2/OpenID Connect機能のみを使った連携方法を紹介します。
> `keycloak-spring-boot-starter`に関しては、[RedHatのブログ](https://developers.redhat.com/blog/2017/05/25/easily-secure-your-spring-boot-applications-with-keycloak/)が参考になります。
**目次**
### クライアントの定義
まずはKeycloak側にクライアントを作成します。
`demo` Realmにクライアントを登録します。
サイドバーの"Clients"をクリックして、右の"Create"ボタンをクリック。
"Client ID"に`demo`を、"Root URL"に"http://localhost:8080"(これから作成するSpring BootアプリのURL)を入力し、"Save"ボタンをクリック。
"Access Type"を"confidential"に変更して、"Save"ボタンをクリック。
"Clients"から`demo`クライアントを選択すると"Credentials"タブが増えているので、クリックすると"Secret"(Client Secret)が表示されているので、これをコピー。
### Spring Bootでクライアントを実装
Spring Security 5でOpenID Connect対応が入ったため、Spring Boot 1.5と2以降で大きく設定方法が変わります。
#### Spring Boot 1.5の場合
Spring Boot 1.5 (Spring Security 4)の場合は、Spring Security OAuth2を使って、Spring Bootの[Single Sign On機能](https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/html/boot-features-security.html#boot-features-security-oauth2-single-sign-on)を使用できます。
[Spring Initializr](https://start.spring.io)でDependenciesに"Web"と"Cloud OAuth2"を選択します。
> でDependenciesにに"Keycloak"を選ぶ必要はありません。
`application.properties`に次の内容を設定。`security.oauth2.client.client-secret`には"クライアントの定義"で生成された"Client Secret"を設定してください。
``` properties
keycloak.auth-server-url=/auth
keycloak.realm=demo
keycloak.base.uri=${keycloak.auth-server-url}/realms/${keycloak.realm}/protocol/openid-connect
security.oauth2.client.client-id=demo
security.oauth2.client.client-secret=dd3cb803-4151-45d5-92b9-230be9813f40
security.oauth2.client.scope=openid
security.oauth2.client.access-token-uri=${keycloak.base.uri}/token
security.oauth2.client.user-authorization-uri=${keycloak.base.uri}/auth
security.oauth2.resource.user-info-uri=${keycloak.base.uri}/userinfo
security.oauth2.resource.jwk.key-set-uri=${keycloak.base.uri}/certs
```
メインのクラスに`@EnableOAuth2Sso`アノテーションをつけ、
``` java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
@SpringBootApplication
@EnableOAuth2Sso
public class DemoSsoWithKeycloakApplication {
public static void main(String[] args) {
SpringApplication.run(DemoSsoWithKeycloakApplication.class, args);
}
}
```
あとはControllerの引数にログインユーザー情報として`java.security.Principal`あるいは`org.springframework.security.core.Authentication`を取れるようになります。
``` java
package com.example.demo;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/")
public Object hi(Authentication authentication) {
return authentication;
}
}
```
`main`メソッドを実行して、[http://localhost:8080](http://localhost:8080)にアクセスすると、Keycloakのログイン画面にリダイレクトされます。
`demo` Realmのユーザーでログインすると、ログインユーザー情報が表示されます。
ログインユーザーをカスタマイズしたい場合は、`org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor`と`org.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor`を実装すれば良いです。
[この辺](https://www.slideshare.net/makingx/spring-boot-tips/85)を見てください。
Roleの設定は省略しました。
また、取得するScopeの同意画面やScopeの細かい設定は、"Consent Required"を"ON"にして、"Scope"や"Mappers"タブを調整する必要があります。
> Spring Boot 1の場合は、[Spring Security OAuth Workshop](https://github.com/Pivotal-Japan/spring-security-oauth-workshop)の内容が活かせます。
#### Spring Boot 2の場合
Spring Boot 2は[Spring Security 5のOAuth 2.0 Login機能](https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#jc-oauth2login)をそのまま使用できます。
[Spring Initializr](https://start.spring.io)でSpring Bootのバージョンを`2.0.0.M7`にし、Dependenciesに"Web"と"Security"を選択します。
OAuth2対応に必要なSpring Securityのライブラリは`spring-boot-starter`に含まれておらず、`2.0.0.M7`の段階ではStarterライブラリも用意されていないので、次のライブラリを`pom.xml`の``に追加する必要があります。
``` xml
org.springframework.security
spring-security-oauth2-client
org.springframework.security
spring-security-oauth2-jose
```
Keycloakの情報を`application.properties`に定義します。Keycloakは[`CommonOAuth2Provider`](https://github.com/spring-projects/spring-security/blob/master/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java)に含まれていないのでフル定義が必要です。
``` properties
keycloak.auth-server-url=/auth
keycloak.realm=demo
keycloak.base.uri=${keycloak.auth-server-url}/realms/${keycloak.realm}/protocol/openid-connect
spring.security.oauth2.client.provider.keycloak.token-uri=${keycloak.base.uri}/token
spring.security.oauth2.client.provider.keycloak.authorization-uri=${keycloak.base.uri}/auth
spring.security.oauth2.client.provider.keycloak.user-info-uri=${keycloak.base.uri}/userinfo
spring.security.oauth2.client.provider.keycloak.jwk-set-uri=${keycloak.base.uri}/certs
spring.security.oauth2.client.provider.keycloak.user-name-attribute=preferred_username
spring.security.oauth2.client.registration.keycloak.client-name=Keycloak
spring.security.oauth2.client.registration.keycloak.client-authentication-method=basic
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.redirect-uri-template={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.keycloak.client-id=demo
spring.security.oauth2.client.registration.keycloak.client-secret=dd3cb803-4151-45d5-92b9-230be9813f40
spring.security.oauth2.client.registration.keycloak.scope=openid
```
メインのクラスには特に何も設定する必要はありません。
``` java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoSsoWithKeycloak2Application {
public static void main(String[] args) {
SpringApplication.run(DemoSsoWithKeycloak2Application.class, args);
}
}
```
`HelloController`の引数は`OAuth2AuthenticationToken`に変え、返り値も少し変えます。
``` java
package com.example.demo;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/")
public Object hi(OAuth2AuthenticationToken authentication) {
return authentication.getPrincipal().getAttributes();
}
}
```
`OAuth2AuthenticationToken`は`Authentication`の実装クラスなのですが、JSONシリアライズできないので、シリアライズのできる`principal.attributes`を返します。
`main`メソッドを実行して、[http://localhost:8080](http://localhost:8080)にアクセスすると、クライアント選択画面にリダイレクトされます。
"Keycloak"をクリックすると、Keycloakのログイン画面にリダイレクトされます。
`demo` Realmのユーザーでログインすると、ログインユーザー情報が表示されます。
----
Spring BootとKeycloakの連携について説明しました。
というか、Keycloakはあまり関係なくて、一般的なOpenID Connect連携の方法でした。
個人的にはKeycloakのライブラリを使うより、こっちが好みです。