26.6K Views
May 26, 22
スライド概要
JJUG CCC 2020 Fallでの講演資料です。Spring SecurityのOAuth 2.0機能について解説しています。OAuth 2.0自体は理解している前提の、中級者向け資料です。
Java、Spring、IntelliJ IDEA
#jjug_ccc OAuth 2.0 with Spring Security (株)カサレアル 多田真敏 2020年11月7日 JJUG CCC 2020 Fall1 (C) CASAREAL, Inc. All rights reserved.
#jjug_ccc このセッションについて ▸ Spring SecurityのOAuth 2.0関連機能を、 仕組みも含めて分かりやすく解説します ▸ サンプルコード ▸ https://github.com/MasatoshiTada/oauth2-withspring-security (C) CASAREAL, Inc. All rights reserved. 2
#jjug_ccc 必要な前提知識 ▸ このセッションは【中級者向け】です ▸ 以下の前提知識が必要です ▸ Authorization Code Grant Flowを説明できる ▸ Spring Securityを使ったことがある ▸ OAuth 2.0機能でなくてもOK (C) CASAREAL, Inc. All rights reserved. 3
#jjug_ccc 先に結論 ▸ Spring Security内部のRestTemplateには、 タイムアウトが設定されていないことが ほとんど →ちゃんとタイムアウトを設定しましょう (C) CASAREAL, Inc. All rights reserved. 4
#jjug_ccc OAuth 2.0の基礎を知りたい方は… https://www.slideshare.net/masatoshitada7/oauth-20spring-security-51-121418814 (C) CASAREAL, Inc. All rights reserved. 5
#jjug_ccc Spring Securityのアーキテクチャを知りたい方は… https://www.slideshare.net/masatoshitada7/spring-security-meetup (C) CASAREAL, Inc. All rights reserved. 6
#jjug_ccc 自己紹介 ▸ 多田真敏(@suke̲masa) ▸ 研修トレーナー@カサレアル ▸ Java / Golang / Microservices / Kubernetes / Python / 機械学習 ▸ VMware認定講師 ▸ 日本Springユーザ会スタッフ (C) CASAREAL, Inc. All rights reserved. 7
#jjug_ccc 先にお詫びしておきます🙇 ▸ 娘氏(9ヶ月)の声がところどころ入るかも しれません😅 (C) CASAREAL, Inc. All rights reserved. 8
#jjug_ccc 株式会社カサレアル ▸ 他社には無い色々なプログラミング言語の NEW!! 研修を提供しています! (C) CASAREAL, Inc. All rights reserved. 9
#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
#jjug_ccc 🎉新規コースリリース🎉 Go言語による クラウドネイティブアプリケーション開発 -基本文法、Webアプリケーション、マイクロサービス- Python入門 -基本文法、ライブラリの利用、Webスクレイピング- Pythonによる機械学習入門(仮) (C) CASAREAL, Inc. All rights reserved. 11
#jjug_ccc オンライン研修、はじめました ▸ 「学習効果は通常と変わらない」 と好評です! 受講者様 講師 (C) CASAREAL, Inc. All rights reserved. 12
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 13
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 14
#jjug_ccc OAuth 2.0とは ▸ 認可の流れを規定したプロトコル ▸ RFC 6749 (日本語版もある) ▸ OAuth 1.0とは別物 ▸ Struts 1とStruts 2くらい違う ▸ 認証プロトコルOpenID Connect のベースになっている (C) CASAREAL, Inc. All rights reserved. 15
#jjug_ccc OAuth 2.0の登場人物 ① リソースオーナー (Resource Owner) ▸ 情報の持ち主。多くのケースでは人間。 ② リソースサーバー (Resource Server) ▸ 情報を保持するサーバー。 ③ クライアント (Client) ▸ リソースサーバーからもらった情報を扱うアプリケーション。 ④ 認可サーバー (Authorization Server) ▸ アクセストークンを発行するサーバー。 (C) CASAREAL, Inc. All rights reserved. 16
#jjug_ccc Twitterの例で登場人物まとめ クライアント リソース アクセス 認可サーバー トークン 付与 オーナー 認可 twitter.com アクセス トークン リソースサーバー こんにちは! 楽しみだなー つぶやき ※本当はTwitterはOAuth 1.0を使っています (C) CASAREAL, Inc. All rights reserved. 17
#jjug_ccc グラントタイプ(アクセストークンの取得方法) ① 認可コード ▸ 主にサーバーサイドWebアプリケーション ② インプリシット(非推奨) ▸ 主にクライアントサイドWebアプリケーション ③ リソースオーナーパスワードクレデンシャル(非推奨) ▸ 主に公式のスマホアプリなど ④ クライアントクレデンシャル ▸ クライアント自身の情報取得 (C) CASAREAL, Inc. All rights reserved. 18
#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
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 20
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 21
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 22
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 23
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 24
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト ⑥認可コード クライアント ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 25
#jjug_ccc 認可コードによるアクセストークン取得 リソース オーナー 認可サーバー Web ブラウザ※ ②認可エンドポイントにリダイレクト ③認可画面 ④認可 ①初回アクセス ⑤認可コード発行+リダイレクト ⑥認可コード クライアント ⑦アクセストークン ※Webブラウザは、仕様書では「ユーザーエージェント」と記載されています (C) CASAREAL, Inc. All rights reserved. 26
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ①リクエスト リソース サーバー クライアント 請求書作成 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 27
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ①リクエスト リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 28
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 29
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ (C) CASAREAL, Inc. All rights reserved. 30
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 31
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 ⑥レスポンス Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 32
#jjug_ccc アクセストークンを利用したリソースアクセス 認可サーバー リソース オーナー ③アクセス トークン 検証 ①リクエスト ④検証結果を返す リソース サーバー クライアント ⑦レスポンス ②リソースにアクセス 請求書作成 with アクセストークン 資料郵送 ⑥レスポンス Web ブラウザ ⑤検証結果を 確認 (C) CASAREAL, Inc. All rights reserved. 33
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 34
#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
#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
#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
#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
#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 認可エンドポイントに リダイレクトする OAuth2AuthorizationRequestRedirectFilter OAuth2LoginAuthenticationFilter ExceptionTranslationFilter 認証を行う FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 39
#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
#jjug_ccc OAuth2LoginAuthenticationFilter内での処理 ①認可コードを受け取る ⑧SecurityContextに Authenticationを保存 OAuth2LoginAuthenticationFilter ②認可コードを持った Authenticationを渡す ⑦Authenticationを返す ProviderManager ③認可コードを持った Authenticationを渡す ⑥JWTからAuthorityを抽出 →Authenticationを返す OidcAuthorizationCodeAuthenticationProvider ④呼び出し ⑤OAuth2AccessToken Responseを返す DefaultAuthoriaztionCodeTokenResponseClient (C) CASAREAL, Inc. All rights reserved. 41
#jjug_ccc DefaultAuthorizationCodeTokenResponseClient ▸ RestTemplateで認可サーバーに アクセスして、アクセストークンの取得を行う ▸ このRestTemplateには、デフォルトでは タイムアウトが設定されていない (C) CASAREAL, Inc. All rights reserved. 42
#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
#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
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 45
#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
#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
#jjug_ccc WebClientに移行すべきか? ▸ まだ暫くはRestTemplateでよい(多田個人の意見) ▸ アプリケーションやSpring本体などへの影響が非常に大きい ため、RestTemplateがすぐに削除されるとは思えない ▸ WebClientを使うと、どうしてもFlux/Monoを使った リアクティブプログラミングを意識しなければならないため、 難易度が上がる ▸ この節ではあくまで「WebClientを使うとこうなるよ」 という例を紹介 (C) CASAREAL, Inc. All rights reserved. 48
#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
#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
#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
#jjug_ccc ServletOAuth2AuthorizedClient ExchangeFilterFunctionは何をしてくれるか ▸ WebClientからのリクエスト時に Authorization: Bearer アクセストークン をヘッダーに追加してくれる ▸ アクセストークンの有効期限が切れていたら リフレッシュしてくれる (C) CASAREAL, Inc. All rights reserved. 52
#jjug_ccc リフレッシュの仕組み ServletOAuth2AuthorizedClientExchangeFilterFunction 呼び出し DefaultOAuth2AuthorizedClientManager 呼び出し DelegatingOAuth2AuthorizedClientProvider 呼び出し RefreshTokenOAuth2AuthorizedClientProvider 呼び出し DefaultRefreshTokenTokenResponseClient (C) CASAREAL, Inc. All rights reserved. 53
#jjug_ccc DefaultRefreshTokenTokenResponseClient ▸ RestTemplateで認可サーバーにアクセスして、 アクセストークンのリフレッシュを行う ▸ 詳細は下記の記事参照 ▸ Spring Security 5.xでOAuth2アクセストークンを リフレッシュする https://qiita.com/suke̲masa/items/ fb065443975f7ceb801e (C) CASAREAL, Inc. All rights reserved. 54
#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
#jjug_ccc ServletOAuth2AuthorizedClient ExchangeFilterFunctionにタイムアウトを設定 ServletOAuth2AuthorizedClientExchangeFilterFunction 代入 DefaultOAuth2AuthorizedClientManager 代入 OAuth2AuthorizedClientProvider 代入 DefaultRefreshTokenTokenResponseClient 代入 RestTemplate(タイムアウト設定済み) (C) CASAREAL, Inc. All rights reserved. 56
#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
#jjug_ccc Issue立てました ▸ 是非「いいね」ください ▸ https://github.com/spring-projects/spring-security/ issues/9114 (C) CASAREAL, Inc. All rights reserved. 58
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 59
#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
#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
#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
#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 受信したJWTを使って 認証する BearerTokenAuthenticationFilter ExceptionTranslationFilter FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 63
#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
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 65
#jjug_ccc JWT形式アクセストークンの問題点 ▸ JWTに含まれていない情報は取得できない ▸ JWTに含む情報が多すぎると トークン自体が大きくなってしまう ▸ 認可サーバー側で アクセストークンを無効化できない (C) CASAREAL, Inc. All rights reserved. 66
#jjug_ccc そこでToken Introspection! ▸ RFC7662 ▸ https://tools.ietf.org/html/rfc7662 ▸ リソースサーバーが認可サーバーに アクセストークンを送信することで、 ①アクセストークン自体に含まれていない情報を 取得できる ②アクセストークンの有効性をチェックできる (C) CASAREAL, Inc. All rights reserved. 67
#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
#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
#jjug_ccc リソースサーバーの認証方法 ▸ 具体的な方法は、仕様では定まっていない ▸ Spring SecurityのデフォルトはBasic認証 ▸ NimbusOpaqueTokenIntospectorが RestTemplateを使って実行 ▸ 他の方法にカスタマイズ可能(後述) (C) CASAREAL, Inc. All rights reserved. 70
#jjug_ccc application.yml spring.security.oauth2.resourceserver.opaquetoken: client-id: リソースサーバーのID client-secret: リソースサーバーのパスワード introspection-uri: 認可サーバーの イントロスペクションエンドポイント (C) CASAREAL, Inc. All rights reserved. 71
#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
#jjug_ccc Spring Security Filter Chain リクエスト SecurityContextPersistenceFilter LogoutFilter 受信したアクセストークンを 使って認証する BearerTokenAuthenticationFilter ExceptionTranslationFilter FilterSecurityInterceptor (C) CASAREAL, Inc. All rights reserved. 73
#jjug_ccc BearerTokenAuthenticationFilter内での処理 ①リクエストヘッダーで アクセストークンを受け取る ⑧SecurityContextに Authenticationを保存 BearerTokenAuthenticationFilter ②アクセストークンを持った Authenticationを渡す ⑦Authenticationを返す ProviderManager ③アクセストークンを持った Authenticationを渡す ⑥Authenticationを返す OpaqueTokenAuthenticationProvider ④アクセストークンを渡す ⑤Token Introspection実行 →OAuth2Authentication Principalを返す NimbusOpaqueTokenIntrospector (C) CASAREAL, Inc. All rights reserved. 検証失敗時は 例外発生 74
#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
#jjug_ccc カスタマイズ例 ▸ NimbusOpaqueTokenIntospector内の RestTemplateにタイムアウトを設定 ▸ デフォルトではタイムアウト無しなので、 設定したほうがよい (C) CASAREAL, Inc. All rights reserved. 76
#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
#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
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 79
#jjug_ccc Token Propagationとは ▸ 中間のマイクロサービスは、 自分が受け取ったアクセストークンを そのまま下流のマイクロサービスに渡す アクセス トークン Client アクセス トークン API Gateway (C) CASAREAL, Inc. All rights reserved. Resource Server 80
#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
#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
#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
#jjug_ccc 目次 ▸ OAuth 2.0をザッと復習 ▸ クライアントの基本機能と構造 ▸ クライアントでのWebClientの利用 ▸ リソースサーバーの基本機能と構造 ▸ Token Introspection ▸ Token Propagation ▸ まとめ (C) CASAREAL, Inc. All rights reserved. 84
#jjug_ccc まとめ ▸ タイムアウト設定、大事。 (C) CASAREAL, Inc. All rights reserved. 85
#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
#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
#jjug_ccc OAuth 2.0関連書籍 (C) CASAREAL, Inc. All rights reserved. 88
#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
#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
#jjug_ccc ご清聴ありがとうございました! (C) CASAREAL, Inc. All rights reserved. 91