--- 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のライブラリを使うより、こっちが好みです。