KeycloakとSpring Bootを連携するために、RedHatよりorg.keycloak:keycloak-spring-boot-starter
というSpring Boot用のStarterライブラリが提供されていますが、これはKeycloakのAPIを使っています。Spring BootとKeycloakを合わせて検索するとだいたいこのライブラリが使われています。
KeycloakをOpenID Connectという標準仕様を使ってアクセスするのに、ベンダ提供ライブラリを使うとアプリケーションのポータビリティが損なわれるので、この記事ではSpringのOAuth2/OpenID Connect機能のみを使った連携方法を紹介します。
keycloak-spring-boot-starter
に関しては、RedHatのブログが参考になります。
目次
クライアントの定義
まずは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機能を使用できます。
Spring InitializrでDependenciesに"Web"と"Cloud OAuth2"を選択します。
でDependenciesにに"Keycloak"を選ぶ必要はありません。
application.properties
に次の内容を設定。security.oauth2.client.client-secret
には"クライアントの定義"で生成された"Client Secret"を設定してください。
keycloak.auth-server-url=<Keycloakの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
アノテーションをつけ、
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
を取れるようになります。
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にアクセスすると、Keycloakのログイン画面にリダイレクトされます。
demo
Realmのユーザーでログインすると、ログインユーザー情報が表示されます。
ログインユーザーをカスタマイズしたい場合は、org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor
とorg.springframework.boot.autoconfigure.security.oauth2.resource.AuthoritiesExtractor
を実装すれば良いです。
この辺を見てください。
Roleの設定は省略しました。 また、取得するScopeの同意画面やScopeの細かい設定は、"Consent Required"を"ON"にして、"Scope"や"Mappers"タブを調整する必要があります。
Spring Boot 1の場合は、Spring Security OAuth Workshopの内容が活かせます。
Spring Boot 2の場合
Spring Boot 2はSpring Security 5のOAuth 2.0 Login機能をそのまま使用できます。
Spring InitializrでSpring Bootのバージョンを2.0.0.M7
にし、Dependenciesに"Web"と"Security"を選択します。
OAuth2対応に必要なSpring Securityのライブラリはspring-boot-starter
に含まれておらず、2.0.0.M7
の段階ではStarterライブラリも用意されていないので、次のライブラリをpom.xml
の<dependencies>
に追加する必要があります。
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
Keycloakの情報をapplication.properties
に定義します。KeycloakはCommonOAuth2Provider
に含まれていないのでフル定義が必要です。
keycloak.auth-server-url=<Keycloakの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
メインのクラスには特に何も設定する必要はありません。
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
に変え、返り値も少し変えます。
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にアクセスすると、クライアント選択画面にリダイレクトされます。
"Keycloak"をクリックすると、Keycloakのログイン画面にリダイレクトされます。
demo
Realmのユーザーでログインすると、ログインユーザー情報が表示されます。
Spring BootとKeycloakの連携について説明しました。 というか、Keycloakはあまり関係なくて、一般的なOpenID Connect連携の方法でした。
個人的にはKeycloakのライブラリを使うより、こっちが好みです。