Spring SecurityでOpenID Connect認証してみた

Java,OAuth,OpenID Connect,Spring Boot,Spring Framework,Spring Security,プログラミング

こんにちは、ソリューション開発部の瀧口です。最近ダムが気になります。

先日ダムの観光放流に行ったのですが、そのスケールに圧倒されました。山の中に突然出てくる、まさに「そびえたつ」という言葉そのままの存在感。放流が始まるときの「ドドドドド」という音、雨ガッパがいるくらいの容赦なさで降り注ぐ水しぶき。あらためて、人間ってすごいモノ作るんだなーと実感しました。

ちなみに、その時ジムに置いてきたポケモンが未だに帰ってきません。今シーズンの観光放流ももう終わるのに・・・ 誰か私のカイリューを解放してあげて!!

さて、私のカイリューはジムを守っていますが、Webアプリケーションを守るといえば、そう Spring Security ですね。そんなSpring Securityですが、11月28日に5.0.0がリリースされています。新機能として、OAuth 2.0 / OpenID Connectへの対応が入っていたので、さっそくOpenID Connectでの認証を試してみました。

Googleアカウントでログイン

Spring SecurityのOAuth 2.0 / OpenID Connectクライアント実装である spring-security-oauth2-client では、Google / GitHub / Facebook / Okta の設定が提供されています。この4つ以外でも、自前で設定を用意することで対応可能ですが、ここでは最初から提供されているGoogleを使ってみます。

クライアントの登録

Google DeveloperのOpenID Connectページに沿って、OAuth クライアントIDを作成します。承認済みのリダイレクト URIには http://localhost:8080/login/oauth2/code/google を設定しておきます。クライアントIDクライアントシークレットは、後で設定するので控えておきましょう。

Spring Bootプロジェクトの作成

実際に認証を行うアプリケーションを作成します。Spring Security 5.0.0にはSpring Bootの2.0.0.M7から対応しています。

pom.xml

spring-boot-starter-security に加え、spring-security-oauth2-clientとspring-security-oauth2-joseを追加することで、AutoConfigureが有効になります。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.0.M7</version>
	</parent>

	<groupId>jp.co.arksystems</groupId>
	<artifactId>security-oidc</artifactId>
	<version>1.0-SNAPSHOT</version>
	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.7.0</version>
				<configuration>
					<source>9</source>
					<target>9</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<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>
	</dependencies>

	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/libs-milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
</project>

application.yml

Googleにクライアントを作成したときに控えておいたクライアントIDとシークレットを、application.ymlに設定します。CommonOAuth2Provider で事前設定がされているので、最低限の設定で済みます。

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: {クライアントID}
            client-secret: {クライアントシークレット}

メインクラス

Spring Bootのメインクラスを用意します。ここでは、ID TokenやUserInfo Requestで取得できる属性値をJSONで出力するハンドラを追加してみます。

@SpringBootApplication
@RestController
public class OidcLoginApplication {
    public static void main(String[] args) {
        SpringApplication.run(OidcLoginApplication.class, args);
    }

    @GetMapping("/")
    public Map<?, ?> index(Principal principal) {
        if (principal instanceof OAuth2AuthenticationToken) {
            final OAuth2AuthenticationToken auth = (OAuth2AuthenticationToken) principal;
            return auth.getPrincipal().getAttributes();
        }
        return Map.of("name", principal.getName());
    }
}

動作例

たったこれだけで、Googleを使ったOpenID Connect認証が実現できています。Spring Bootアプリケーションを実行し、ブラウザで http://localhost:8080 にアクセスしてみます。

すると画像のように、認証プロバイダを選択する画面が表示されます。今回はGoogleしか設定していないので1つですが、FacebookやGitHubの設定も行うと、この画面に追加されます。

Login with OAuth 2.0

Googleを選択すると、実際にGoogleアカウントでのログイン画面にリダイレクトされます。

Googleアカウントでのログイン画面にリダイレクトされる。

ログインに成功すると、アプリケーション側にリダイレクトされ、以下のようなJSONが取得できます。

{  
  "at_hash":"XXX",
  "sub":"XXX",
  "email_verified":true,
  "gender":"male",
  "profile":"https://plus.google.com/+XXX",
  "iss":"https://accounts.google.com",
  "given_name":"Toshio",
  "locale":"ja",
  "picture":"https://lh4.googleusercontent.com/XXX/photo.jpg",
  "aud":[  
    "XXX.apps.googleusercontent.com"
  ],
  "azp":"XXX.apps.googleusercontent.com",
  "name":"Toshio Takiguchi",
  "exp":"2017-11-29T08:42:43.000+0000",
  "family_name":"Takiguchi",
  "iat":"2017-11-29T07:42:43.000+0000",
  "email":"xxx@gmail.com"
}

無事にOpenID Connectで認証に成功し、アプリケーションにログインすることができました!

まとめ

OAuth2やOpenID Connectは、GoogleやFacebookのようなソーシャルサービスだけでなく、Windows Server 2016のAD FSやAzure ADも対応しており、今後エンタープライズ系でも普及が加速していくと考えられます。Spring Securityを使えば、今回ご紹介したように、簡単にOpenID Connectによる認証に対応できますので、検討してみてはいかがでしょうか。

最後に1つだけ。

いつまでパスワード変更画面の実装で消耗してるの?

  • Zabbix Enterprise Appliance
  • 低コスト・短納期で提供するまるごとおまかせZabbix