OAuth 2.0 with Spring Security #jjug_ccc #jjug_ccc_b

22.7K Views

May 26, 22

スライド概要

JJUG CCC 2020 Fallでの講演資料です。Spring SecurityのOAuth 2.0機能について解説しています。OAuth 2.0自体は理解している前提の、中級者向け資料です。

profile-image

Java、Spring、IntelliJ IDEA

シェア

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

#jjug_ccc OAuth 2.0 with Spring Security (株)カサレアル 多田真敏 2020年11月7日 JJUG CCC 2020 Fall1 (C) CASAREAL, Inc. All rights reserved.

2.

#jjug_ccc このセッションについて ▸ Spring SecurityのOAuth 2.0関連機能を、 仕組みも含めて分かりやすく解説します ▸ サンプルコード ▸ https://github.com/MasatoshiTada/oauth2-withspring-security (C) CASAREAL, Inc. All rights reserved. 2

3.

#jjug_ccc 必要な前提知識 ▸ このセッションは【中級者向け】です ▸ 以下の前提知識が必要です ▸ Authorization Code Grant Flowを説明できる ▸ Spring Securityを使ったことがある ▸ OAuth 2.0機能でなくてもOK (C) CASAREAL, Inc. All rights reserved. 3

4.

#jjug_ccc 先に結論 ▸ Spring Security内部のRestTemplateには、 タイムアウトが設定されていないことが ほとんど →ちゃんとタイムアウトを設定しましょう (C) CASAREAL, Inc. All rights reserved. 4

5.

#jjug_ccc OAuth 2.0の基礎を知りたい方は… https://www.slideshare.net/masatoshitada7/oauth-20spring-security-51-121418814 (C) CASAREAL, Inc. All rights reserved. 5

6.

#jjug_ccc Spring Securityのアーキテクチャを知りたい方は… https://www.slideshare.net/masatoshitada7/spring-security-meetup (C) CASAREAL, Inc. All rights reserved. 6

7.

#jjug_ccc 自己紹介 ▸ 多田真敏(@suke̲masa) ▸ 研修トレーナー@カサレアル ▸ Java / Golang / Microservices / Kubernetes / Python / 機械学習 ▸ VMware認定講師 ▸ 日本Springユーザ会スタッフ (C) CASAREAL, Inc. All rights reserved. 7

8.

#jjug_ccc 先にお詫びしておきます🙇 ▸ 娘氏(9ヶ月)の声がところどころ入るかも しれません😅 (C) CASAREAL, Inc. All rights reserved. 8

9.

#jjug_ccc 株式会社カサレアル ▸ 他社には無い色々なプログラミング言語の NEW!! 研修を提供しています! (C) CASAREAL, Inc. All rights reserved. 9

10.

#jjug_ccc Spring系コース ▸ 基礎からのSpring Bootによる Webアプリケーション開発(2日間) ▸ VMware Tanzu認定 Spring: Core Training(4日間) ▸ VMware Tanzu認定 Spring Cloud: Developer(3日間) ▸ 基礎からのSpring Security(1日間) ▸ 基礎からのSpring Batch(1日間) (C) CASAREAL, Inc. All rights reserved. 10

11.

#jjug_ccc 🎉新規コースリリース🎉 Go言語による クラウドネイティブアプリケーション開発 -基本文法、Webアプリケーション、マイクロサービス- Python入門 -基本文法、ライブラリの利用、Webスクレイピング- Pythonによる機械学習入門(仮) (C) CASAREAL, Inc. All rights reserved. 11

12.

#jjug_ccc オンライン研修、はじめました ▸ 「学習効果は通常と変わらない」 と好評です! 受講者様 講師 (C) CASAREAL, Inc. All rights reserved. 12

13.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 13

14.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 14

15.

#jjug_ccc OAuth 2.0とは ▸ 認可の流れを規定したプロトコル ▸ RFC 6749 (日本語版もある) ▸ OAuth 1.0とは別物 ▸ Struts 1とStruts 2くらい違う ▸ 認証プロトコルOpenID Connect のベースになっている (C) CASAREAL, Inc. All rights reserved. 15

16.

#jjug_ccc OAuth 2.0の登場人物 ① リソースオーナー (Resource Owner) ▸ 情報の持ち主。多くのケースでは人間。 ② リソースサーバー (Resource Server) ▸ 情報を保持するサーバー。 ③ クライアント (Client) ▸ リソースサーバーからもらった情報を扱うアプリケーション。 ④ 認可サーバー (Authorization Server) ▸ アクセストークンを発行するサーバー。 (C) CASAREAL, Inc. All rights reserved. 16

17.

#jjug_ccc Twitterの例で登場人物まとめ クライアント リソース アクセス 認可サーバー トークン 付与 オーナー 認可 twitter.com アクセス トークン リソースサーバー こんにちは! 楽しみだなー つぶやき ※本当はTwitterはOAuth 1.0を使っています (C) CASAREAL, Inc. All rights reserved. 17

18.

#jjug_ccc グラントタイプ(アクセストークンの取得方法) ① 認可コード ▸ 主にサーバーサイドWebアプリケーション ② インプリシット(非推奨) ▸ 主にクライアントサイドWebアプリケーション ③ リソースオーナーパスワードクレデンシャル(非推奨) ▸ 主に公式のスマホアプリなど ④ クライアントクレデンシャル ▸ クライアント自身の情報取得 (C) CASAREAL, Inc. All rights reserved. 18

19.

#jjug_ccc [参考] OAuth 2.1の仕様策定が進行中 ▸ OAuth 2.0の仕様+その他を再整理したもの → 既に非推奨となっている機能が削除される ▸ インプリシット ▸ リソースオーナーパスワードクレデンシャル ▸ 詳細はこちらの記事へ ▸ OAuth 2.1 の標準化が進められています https://qiita.com/flano̲yuki/items/bf6ae2eeb5e6447edcc1 ▸ Spring SecurityのOAuth 2.1対応予定は、現時点では不明 (C) CASAREAL, Inc. All rights reserved. 19

20.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 20

21.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 21

22.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 22

23.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 23

24.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 24

25.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト ⑥認可コード クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 25

26.

#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト ⑥認可コード クライアント ⑦アクセストークン ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 26

27.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ①リクエスト リソース サーバー クライアント 請求書作成 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 27

28.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ①リクエスト リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 28

29.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 29

30.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 30

31.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 31

32.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 ⑥レスポンス Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 32

33.

#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ⑦レスポンス ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 ⑥レスポンス Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 33

34.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 34

35.

#jjug_ccc 依存性 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-oauth2-client </artifactId> </dependency> • spring-security-config • spring-security-oauth2-client などが含まれている (C) CASAREAL, Inc. All rights reserved. 35

36.

#jjug_ccc application.yml spring.security.oauth2.client.registration.todo: provider: 任意の名前(.registrationの後にも指定する) client-id: クライアントID client-secret: クライアントシークレット client-name: 任意の名前(画面表示で使われる) client-authentication-method: クライアント認証方法 authorization-grant-type: グラントタイプ redirect-uri: リダイレクトエンドポイントのURL scope: このアプリのスコープをカンマ区切りで指定 ※スペースの都合上でYAML形式で書いていますが、個人的にはproperties派です (C) CASAREAL, Inc. All rights reserved. 36

37.

#jjug_ccc application.yml(続き) spring.security.oauth2.client.provider.todo: authorization-uri: 認可エンドポイントのURL token-uri: トークンエンドポイントのURL user-info-uri: ユーザー情報のJSONが返ってくるURL user-name-attribute: JSONの中のユーザー名を表す属性名 user-info-authentication-method: ユーザー情報取得時の認証方式 jwk-set-uri: JWK Setが返ってくるURL issuer-uri: 認可サーバーのIssuer Identifier ※Keycloakの場合、issuer-uriを指定すれば他のプロパティは指定不要(user-name-attributeは任意) (C) CASAREAL, Inc. All rights reserved. 37

38.

#jjug_ccc Java Config @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2Login() .loginPage("/login") .permitAll(); ログインに関する設定 ... } } (C) CASAREAL, Inc. All rights reserved. 38

39.

#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 認可エンドポイントに リダイレクトする OAuth2AuthorizationRequestRedirectFilter OAuth2LoginAuthenticationFilter ExceptionTranslationFilter 認証を行う FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 39

40.
[beta]
#jjug_ccc
OAuth2AuthorizationRequestRedirectFilter

▸ 認可が必要な場合、認可サーバーの
認可エンドポイントにリダイレクトしている
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
OAuth2AuthorizationRequest authorizationRequest =
this.authorizationRequestResolver.resolve(request);
if (authorizationRequest != null) {

this.sendRedirectForAuthorization(
}
...

request, response, authorizationRequest);
return;
https://github.com/spring-projects/spring-security/blob/master/oauth2/
oauth2-client/src/main/java/org/springframework/security/oauth2/
client/web/OAuth2AuthorizationRequestRedirectFilter.java#L164
(C) CASAREAL, Inc. All rights reserved.

40

41.

#jjug_ccc OAuth2LoginAuthenticationFilter内での処理 ①認可コードを受け取る ⑧SecurityContextに Authenticationを保存 OAuth2LoginAuthenticationFilter ②認可コードを持った Authenticationを渡す ⑦Authenticationを返す ProviderManager ③認可コードを持った Authenticationを渡す ⑥JWTからAuthorityを抽出 →Authenticationを返す OidcAuthorizationCodeAuthenticationProvider ④呼び出し ⑤OAuth2AccessToken Responseを返す DefaultAuthoriaztionCodeTokenResponseClient (C) CASAREAL, Inc. All rights reserved. 41

42.

#jjug_ccc DefaultAuthorizationCodeTokenResponseClient ▸ RestTemplateで認可サーバーに アクセスして、アクセストークンの取得を行う ▸ このRestTemplateには、デフォルトでは タイムアウトが設定されていない (C) CASAREAL, Inc. All rights reserved. 42

43.

#jjug_ccc Java Configに設定を追加 private DefaultAuthorizationCodeTokenResponseClient client() { RestTemplate restTemplate = restTemplateBuilder // タイムアウトを設定 .setConnectTimeout(Duration.ofMillis(1000)) .setReadTimeout(Duration.ofMillis(1000)) ... .build(); DefaultAuthorizationCodeTokenResponseClient client = new DefaultAuthorizationCodeTokenResponseClient(); // タイムアウト設定済みのRestTemplateを設定 client.setRestOperations(restTemplate); return client; } (C) CASAREAL, Inc. All rights reserved. 43

44.

#jjug_ccc Java Configの設定を変更 @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2Login(oauth2 -> oauth2 // タイムアウト設定済みのTokenResponseClientを指定 .tokenEndpoint(token -> token .accessTokenResponseClient(client()) ) ... .loginPage("/login") .permitAll() ).authorizeRequests(auth -> auth ... ※スライドではスペースの都合上割愛していますが、OAuth2UserServiceや OidcUserServiceにも同様の設定が必要です(詳細はGitHub参照) (C) CASAREAL, Inc. All rights reserved. 44

45.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 45

46.
[beta]
#jjug_ccc

WebClientとは?
▸ Spring WebFluxに含まれている、
リアクティブなHTTPクライアント
▸ ReactorのFlux/Monoを活用
▸ 流れるようなAPI

public List<Todo> findAll() {
return webClient.get()
.uri("/todos")
.retrieve()
.bodyToFlux(Todo.class)
.collectList()
.block();
}

(C) CASAREAL, Inc. All rights reserved.

46

47.

#jjug_ccc RestTemplateのJavadocより ・5.0以降ではメンテナンスモードやで ・代わりにWebClientの利用を検討してや https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/ RestTemplate.html (C) CASAREAL, Inc. All rights reserved. 47

48.

#jjug_ccc WebClientに移行すべきか? ▸ まだ暫くはRestTemplateでよい(多田個人の意見) ▸ アプリケーションやSpring本体などへの影響が非常に大きい ため、RestTemplateがすぐに削除されるとは思えない ▸ WebClientを使うと、どうしてもFlux/Monoを使った リアクティブプログラミングを意識しなければならないため、 難易度が上がる ▸ この節ではあくまで「WebClientを使うとこうなるよ」 という例を紹介 (C) CASAREAL, Inc. All rights reserved. 48

49.

#jjug_ccc WebClientをSpring MVC上で使う ▸ spring-boot-starter-web (MVC)と spring-boot-starter-webflux (WebFlux)の両方を 依存性に含めると、Spring MVCが優先される ▸ https://docs.spring.io/spring-boot/docs/current/reference/ htmlsingle/#boot-features-web-environment <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> (C) CASAREAL, Inc. All rights reserved. 49

50.
[beta]
#jjug_ccc

WebClientのBean定義
@Bean
public WebClient webClient(...) {
// タイムアウトを設定

タイムアウト設定を忘れずに!

Function<? super TcpClient, ? extends TcpClient> tcpMapper =
tcpClient -> {
// Connect Timeoutを設定
return tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
.doOnConnected(conn -> conn
// Read Timeoutを設定
.addHandlerLast(
new ReadTimeoutHandler(1000, TimeUnit.MILLISECONDS))
// Write Timeoutを設定

);

.addHandlerLast(
new WriteTimeoutHandler(1000, TimeUnit.MILLISECONDS))

};
// 次ページに続く

(C) CASAREAL, Inc. All rights reserved.

50

51.

#jjug_ccc WebClientのBean定義(続き) // 前ページからの続き HttpClient httpClient = HttpClient.create().tcpConfiguration(tcpMapper); // OAuth2関連の設定 ServletOAuth2AuthorizedClientExchangeFilterFunction oAuth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction( clientRegistrationRepository, authorizedClientRepository); return builder.baseUrl(resourceServerUri) // 作成したHttpClientを追加 .clientConnector(new ReactorClientHttpConnector(httpClient)) // OAuth2設定を追加 } .apply(oAuth2Client.oauth2Configuration()) ... .build(); (C) CASAREAL, Inc. All rights reserved. 51

52.

#jjug_ccc ServletOAuth2AuthorizedClient ExchangeFilterFunctionは何をしてくれるか ▸ WebClientからのリクエスト時に Authorization: Bearer アクセストークン をヘッダーに追加してくれる ▸ アクセストークンの有効期限が切れていたら リフレッシュしてくれる (C) CASAREAL, Inc. All rights reserved. 52

53.

#jjug_ccc リフレッシュの仕組み ServletOAuth2AuthorizedClientExchangeFilterFunction 呼び出し DefaultOAuth2AuthorizedClientManager 呼び出し DelegatingOAuth2AuthorizedClientProvider 呼び出し RefreshTokenOAuth2AuthorizedClientProvider 呼び出し DefaultRefreshTokenTokenResponseClient (C) CASAREAL, Inc. All rights reserved. 53

54.

#jjug_ccc DefaultRefreshTokenTokenResponseClient ▸ RestTemplateで認可サーバーにアクセスして、 アクセストークンのリフレッシュを行う ▸ 詳細は下記の記事参照 ▸ Spring Security 5.xでOAuth2アクセストークンを リフレッシュする https://qiita.com/suke̲masa/items/ fb065443975f7ceb801e (C) CASAREAL, Inc. All rights reserved. 54

55.

#jjug_ccc DefaultRefreshTokenTokenResponseClient の注意点 ▸ デフォルトでは、 内部で使っているRestTemplateに タイムアウトが設定されていない → 下記のように設定 DefaultRefreshTokenTokenResponseClient tokenResponseClient = new DefaultRefreshTokenTokenResponseClient(); RestTemplate restTemplate = restTemplateBuilder .setConnectTimeout(Duration.ofMillis(1000)) .setReadTimeout(Duration.ofMillis(1000)) ... .build(); tokenResponseClient.setRestOperations(restTemplate); (C) CASAREAL, Inc. All rights reserved. 55

56.

#jjug_ccc ServletOAuth2AuthorizedClient ExchangeFilterFunctionにタイムアウトを設定 ServletOAuth2AuthorizedClientExchangeFilterFunction 代入 DefaultOAuth2AuthorizedClientManager 代入 OAuth2AuthorizedClientProvider 代入 DefaultRefreshTokenTokenResponseClient 代入 RestTemplate(タイムアウト設定済み) (C) CASAREAL, Inc. All rights reserved. 56

57.

#jjug_ccc ServletOAuth2AuthorizedClient ExchangeFilterFunctionにタイムアウトを設定 ▸ 具体的なコードはメチャ長いのでGitHub参照 ▸ https://github.com/MasatoshiTada/oauth2-withspring-security/blob/master/client-jwt/src/main/ java/com/example/clientjwt/ ClientJwtApplication.java#L78 (C) CASAREAL, Inc. All rights reserved. 57

58.

#jjug_ccc Issue立てました ▸ 是非「いいね」ください ▸ https://github.com/spring-projects/spring-security/ issues/9114 (C) CASAREAL, Inc. All rights reserved. 58

59.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 59

60.

#jjug_ccc 依存性 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-oauth2-resource-server </artifactId> </dependency> • spring-security-config • spring-security-oauth2-resource-server • spring-security-oauth2-jose などが含まれている (C) CASAREAL, Inc. All rights reserved. 60

61.

#jjug_ccc application.yml spring.security.oauth2.resourceserver.jwt: jwk-set-uri: JWK Setが返ってくるURL issuer-uri: 認可サーバーのIssuer Identifier ※Keycloakの場合、issuer-uriを指定すればjwk-set-uriは指定不要 (C) CASAREAL, Inc. All rights reserved. 61

62.

#jjug_ccc Java Config @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { ... http.authorizeRequests() .mvcMatchers("保護対象のURL") .hasAuthority("SCOPE_スコープ名") ...; http.oauth2ResourceServer() .jwt(); ... } } (C) CASAREAL, Inc. All rights reserved. 62

63.

#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 受信したJWTを使って 認証する BearerTokenAuthenticationFilter ExceptionTranslationFilter FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 63

64.

#jjug_ccc BearerTokenAuthenticationFilter内での処理 ①リクエストヘッダーで JWT文字列を受け取る ⑧SecurityContextに Authenticationを保存 BearerTokenAuthenticationFilter ②JWT文字列を持った Authenticationを渡す ⑦Authenticationを返す ProviderManager ③JWT文字列を持った Authenticationを渡す ⑥JwtからAuthorityを抽出 →Authenticationを返す JwtAuthenticationProvider ④JWT文字列を渡す ⑤JWT文字列を検証後、 Jwtオブジェクトに変換 NimbusJwtDecoder (C) CASAREAL, Inc. All rights reserved. 検証失敗時は 例外発生 64

65.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 65

66.

#jjug_ccc JWT形式アクセストークンの問題点 ▸ JWTに含まれていない情報は取得できない ▸ JWTに含む情報が多すぎると トークン自体が大きくなってしまう ▸ 認可サーバー側で アクセストークンを無効化できない (C) CASAREAL, Inc. All rights reserved. 66

67.

#jjug_ccc そこでToken Introspection! ▸ RFC7662 ▸ https://tools.ietf.org/html/rfc7662 ▸ リソースサーバーが認可サーバーに アクセストークンを送信することで、 ①アクセストークン自体に含まれていない情報を 取得できる ②アクセストークンの有効性をチェックできる (C) CASAREAL, Inc. All rights reserved. 67

68.

#jjug_ccc リクエスト POST /introspect HTTP/1.1 Host: keycloak.example.com Accept: application/json Content-Type: application/x-www-form-urlencoded 請求書作成 資料郵送 Authorization: Basic dXNlcjpwYXNzd29yZAo= token=アクセストークン リソース サーバー 認可 サーバー (C) CASAREAL, Inc. All rights reserved. 68

69.
[beta]
#jjug_ccc

レスポンス
請求書作成
資料郵送

HTTP/1.1 200 OK
Content-Type: application/json

リソース
サーバー

{

"active": trueまたはfalse,

認可
サーバー

"client_id": "クライアントのID",
"username": "リソースオーナーのユーザー名",
"scope": "スコープ",
...
}
(C) CASAREAL, Inc. All rights reserved.

69

70.

#jjug_ccc リソースサーバーの認証方法 ▸ 具体的な方法は、仕様では定まっていない ▸ Spring SecurityのデフォルトはBasic認証 ▸ NimbusOpaqueTokenIntospectorが RestTemplateを使って実行 ▸ 他の方法にカスタマイズ可能(後述) (C) CASAREAL, Inc. All rights reserved. 70

71.

#jjug_ccc application.yml spring.security.oauth2.resourceserver.opaquetoken: client-id: リソースサーバーのID client-secret: リソースサーバーのパスワード introspection-uri: 認可サーバーの イントロスペクションエンドポイント (C) CASAREAL, Inc. All rights reserved. 71

72.

#jjug_ccc Java Config @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2ResourceServer() .opaqueToken(); } } (C) CASAREAL, Inc. All rights reserved. 72

73.

#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 受信したアクセストークンを 使って認証する BearerTokenAuthenticationFilter ExceptionTranslationFilter FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 73

74.

#jjug_ccc BearerTokenAuthenticationFilter内での処理 ①リクエストヘッダーで アクセストークンを受け取る ⑧SecurityContextに Authenticationを保存 BearerTokenAuthenticationFilter ②アクセストークンを持った Authenticationを渡す ⑦Authenticationを返す ProviderManager ③アクセストークンを持った Authenticationを渡す ⑥Authenticationを返す OpaqueTokenAuthenticationProvider ④アクセストークンを渡す ⑤Token Introspection実行 →OAuth2Authentication Principalを返す NimbusOpaqueTokenIntrospector (C) CASAREAL, Inc. All rights reserved. 検証失敗時は 例外発生 74

75.

#jjug_ccc 認証方法のカスタマイズ public class MyIntrospector implements OpaqueTokenIntrospector { ... } @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2ResourceServer() .opaqueToken() .introspector(new MyIntrospector()); } } (C) CASAREAL, Inc. All rights reserved. 75

76.

#jjug_ccc カスタマイズ例 ▸ NimbusOpaqueTokenIntospector内の RestTemplateにタイムアウトを設定 ▸ デフォルトではタイムアウト無しなので、 設定したほうがよい (C) CASAREAL, Inc. All rights reserved. 76

77.

#jjug_ccc カスタマイズ例 タイムアウト設定済みの RestTemplateを利用する NimbusOpaqueToken IntrospectorをBean定義 @Configuration public class IntrospectorConfig { @Bean public NimbusOpaqueTokenIntrospector introspector( RestTemplateBuilder builder, OAuth2ResourceServerProperties prop) { OAuth2ResourceServerProperties.Opaquetoken opaquetoken = prop.getOpaquetoken(); RestTemplate rest = builder .setReadTimeout(Duration.ofMillis(1000)) .setConnectTimeout(Duration.ofMillis(1000)) .basicAuthentication(opaquetoken.getClientId(), opaquetoken.getClientSecret()) .build(); return new NimbusOpaqueTokenIntrospector( opaquetoken.getOpaquetoken().getIntrospectionUri(), rest); } } (C) CASAREAL, Inc. All rights reserved. 77

78.

#jjug_ccc カスタマイズ例 @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired OpaqueTokenIntrospector introspector; @Override protected void configure(HttpSecurity http) throws Exception { http.oauth2ResourceServer() .opaqueToken() .introspector(introspector); } カスタマイズした NimbusOpaqueTokenIntrospector のBeanを指定 (C) CASAREAL, Inc. All rights reserved. 78

79.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 79

80.

#jjug_ccc Token Propagationとは ▸ 中間のマイクロサービスは、 自分が受け取ったアクセストークンを そのまま下流のマイクロサービスに渡す アクセス トークン Client アクセス トークン API Gateway (C) CASAREAL, Inc. All rights reserved. Resource Server 80

81.

#jjug_ccc Token Propagationの設定 ▸ WebClientに ServletBearerExchangeFilterFunction を追加 @Bean public WebClient webClient(...) { ... return builder.baseUrl(resourceServerUri) .clientConnector(new ReactorClientHttpConnector(httpClient)) .filter(new ServletBearerExchangeFilterFunction()) } ... .build(); (C) CASAREAL, Inc. All rights reserved. 81

82.

#jjug_ccc Token Propagationの仕組み ▸ リクエスト送信前に ① Authenticationからアクセストークンを取得 ② Authorizationヘッダーにアクセストークンを追加 ‣ 詳細はここらへんのコード参照 ‣ https://github.com/spring-projects/spring-security/blob/ master/oauth2/oauth2-resource-server/src/main/java/org/ springframework/security/oauth2/server/resource/web/ reactive/function/client/ ServletBearerExchangeFilterFunction.java#L68 (C) CASAREAL, Inc. All rights reserved. 82

83.

#jjug_ccc RestTemplateを使いたい場合 ▸ 同等の機能を自分で作る必要がある ▸ コード例はリファレンス参照 https://docs.spring.io/spring-security/site/docs/ 5.3.4.RELEASE/reference/html5/#resttemplatesupport (C) CASAREAL, Inc. All rights reserved. 83

84.

#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 84

85.

#jjug_ccc まとめ ▸ タイムアウト設定、大事。 (C) CASAREAL, Inc. All rights reserved. 85

86.

#jjug_ccc 認可サーバーは? ▸ Spring Authorization Serverが開発進行中 https://spring.io/blog/2020/08/21/get-the-very-first-bits-of-spring-authorization-server-0-0-1 (C) CASAREAL, Inc. All rights reserved. 86

87.

#jjug_ccc Spring Securityリファレンス ▸ 今回紹介していない機能や、様々なカスタマイズ 方法が紹介されています ▸ https://docs.spring.io/spring-security/site/ docs/5.3.4.RELEASE/reference/html5/ #oauth2 (C) CASAREAL, Inc. All rights reserved. 87

88.

#jjug_ccc OAuth 2.0関連書籍 (C) CASAREAL, Inc. All rights reserved. 88

89.

#jjug_ccc OAuth 2.0仕様書 ▸ RFC 6749 The OAuth 2.0 Authorization Framework ▸ https://tools.ietf.org/html/rfc6749 ▸ RFC 7662 OAuth 2.0 Token Introspection ▸ https://tools.ietf.org/html/rfc7662 (C) CASAREAL, Inc. All rights reserved. 89

90.

#jjug_ccc [R.I.P.] 都元さんの資料 ▸ マイクロサービス時代の認証と認可 ▸ https://www.slideshare.net/daisuke̲m/ ss-121478137 ▸ 基礎からのOAuth 2.0 ▸ https://www.slideshare.net/daisuke̲m/oauth-20developersio-2017-20170701 (C) CASAREAL, Inc. All rights reserved. 90

91.

#jjug_ccc ご清聴ありがとうございました! (C) CASAREAL, Inc. All rights reserved. 91