web-dev-qa-db-ja.com

アクセストークンの認証コードを交換するときに、無効なトークンの応答が返されるのはなぜですか? (スプリングブート、oauth2、Azure)

oauthをアプリケーションに追加していますが、次のエラーが発生しています:

[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized: [no body]

プロジェクトには、Spring BootバックエンドとEclipse rcpフロントエンドがあります。 Azure Active Directoryを承認サーバーとして使用して認証を試みています。これまでのところ、Eclipseアプリケーションの起動時にブラウザーウィジェットを起動し、ブラウザーに http:// localhost:8080/oauth2/authorization/Azure を指定することで、認証コード要求を正常に完了することができます。 =。認証コードのリクエストが完了すると、ブラウザは http:// localhost:8080/login?error にリダイレクトされ、上記のエラーが表示されます。

Pom.xmlからの依存関係

Spring Bootを使用して構築され、次の関連する依存関係があります。

  • spring-boot-starter-web v2.2.4
  • Azure-active-directory-spring-boot-starter v2.2.1
  • spring-security-oauth2-client v5.2.1
  • spring-security-oauth2-jose v5.2.1
  • spring-security-oauth2-resource-server v5.2.1

Application.ymlからの設定

複数の承認サーバーをサポートしています。これは、完全に構成されたAzureクライアントです。

spring:
  security:
    oauth2:
      client:
        Azure:
          client-id: XXX
          client-secret: XXX
          client-name: Microsoft
          scope: openid, https://graph.Microsoft.com/user.read, profile
          authorization-grant-type: authorization_code
          redirect-uri: http://localhost:8080/login/oauth2/code/Azure
          client-authentication-method: basic
          authentication-method: post
      provider:
        authorization-uri: https://login.microsoftonline.com/XXX/oauth2/v2.0/authorize
        token-uri: https://login.microsoftonline.com/XXX/oauth2/v2.0/token
        user-info-uri: https://graph.Microsoft.com/oidc/userinfo
        jwt-set-uri: https://login.microsoftonline.com/dXXX/discovery/v2.0/keys

Azure:
   activedirectory:
      tenant-id: XXX
      active-directory-groups: XXX
      allow-telemetry: false

websecurityconfig.Java

@Configuration
@EnableConfigurationProperties
@EnableWebSecurity
@Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                    [...]
                    .anyRequest().authenticated()
                    .and()
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .oauth2Login();
    }

    [...]
}

春の丸太

これは、Azure ADユーザーの資格情報で認証しようとした瞬間の完全なスタックトレースです(体長の要件に合わせて短縮され、承認コードcofedofcで承認されました)。

2020-02-19 16:10:33.925 DEBUG 19564 --- [qtp148813381-16] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@2dd6e039
2020-02-19 16:10:33.925 DEBUG 19564 --- [qtp148813381-16] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-02-19 16:10:33.925 DEBUG 19564 --- [qtp148813381-16] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2020-02-19 16:10:33.928 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 1 of 16 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 2 of 16 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] w.c.HttpSessionSecurityContextRepository : HttpSession returned null object for SPRING_SECURITY_CONTEXT
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] w.c.HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: Session@3a690b15{id=node01xqnw7l82ne041bil2flqsn3vr0,x=node01xqnw7l82ne041bil2flqsn3vr0.node0,req=1,res=true}. A new one will be created.
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 3 of 16 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 4 of 16 in additional filter chain; firing Filter: 'LogoutFilter'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', GET]
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/Azure'; against '/logout'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', POST]
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/oauth2/code/Azure' doesn't match 'POST /logout'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', PUT]
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/oauth2/code/Azure' doesn't match 'PUT /logout'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', DELETE]
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'GET /login/oauth2/code/Azure' doesn't match 'DELETE /logout'
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2020-02-19 16:10:33.929 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 5 of 16 in additional filter chain; firing Filter: 'OAuth2AuthorizationRequestRedirectFilter'
2020-02-19 16:10:33.930 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/Azure'; against '/oauth2/authorization/{registrationId}'
2020-02-19 16:10:33.930 DEBUG 19564 --- [qtp148813381-20] o.s.security.web.FilterChainProxy        : /login/oauth2/code/azure?code=CODE&state=nqsFqxkkNzHJE5knQVdqFLjoPxg1MT_bcn7KzjKSFfU%3d&session_state=3ebe517e-d450-4d49-b8db-8afafe1fa37e at position 6 of 16 in additional filter chain; firing Filter: 'OAuth2LoginAuthenticationFilter'
2020-02-19 16:10:33.930 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/login/oauth2/code/Azure'; against '/login/oauth2/code/*'
2020-02-19 16:10:33.930 DEBUG 19564 --- [qtp148813381-20] .s.o.c.w.OAuth2LoginAuthenticationFilter : Request is to process authentication
2020-02-19 16:10:33.930 DEBUG 19564 --- [qtp148813381-20] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider
2020-02-19 16:10:33.931 DEBUG 19564 --- [qtp148813381-20] o.s.s.authentication.ProviderManager     : Authentication attempt using org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider
2020-02-19 16:10:34.273 DEBUG 19564 --- [qtp148813381-20] .s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.oauth2.core.OAuth2AuthenticationException
2020-02-19 16:10:34.275 DEBUG 19564 --- [qtp148813381-20] .s.o.c.w.OAuth2LoginAuthenticationFilter : Authentication request failed: org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized: [no body]

org.springframework.security.oauth2.core.OAuth2AuthenticationException: [invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: 401 Unauthorized: [no body]
    at org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeAuthenticationProvider.authenticate(OidcAuthorizationCodeAuthenticationProvider.Java:148) ~[spring-security-o

2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] .s.o.c.w.OAuth2LoginAuthenticationFilter : Updated SecurityContextHolder to contain null Authentication
2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] .s.o.c.w.OAuth2LoginAuthenticationFilter : Delegating to authentication failure handler org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler@2b0d857b
2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] .a.SimpleUrlAuthenticationFailureHandler : Redirecting to /login?error
2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] o.s.s.web.DefaultRedirectStrategy        : Redirecting to '/login?error'
2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@2dd6e039
2020-02-19 16:10:34.277 DEBUG 19564 --- [qtp148813381-20] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2020-02-19 16:10:34.278 DEBUG 19564 --- [qtp148813381-20] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
[...]

このエラーを修正しようとします

私はこの未解決の問題からすべてのソリューションを試しました: https://github.com/Microsoft/Azure-spring-boot/issues/526 、Azureポータルマニフェストでoauth2AllowImplicitFlowを有効にすることを含む、 無駄に。

Eclipseブラウザーから認証コードを印刷し、Azure ADへのトークンリクエストを作成すると( Azure postman collection を使用して)、無記名トークンで正常に応答します。

それでは、トークン要求を行うときになぜ401 Unauthorizedを取得するのですか?

この問題にどのように取り組むかについての提案をいただければ幸いです。私は必死に解決策を探しています。次のステップは、Springトークンリクエストをログに記録するか、wiresharkで検査することです(Azureのエンドポイントはhttpsであるため、TLS接続を復号化する必要があります)。

ここまで読んだならありがとうございます:)

2
phil

@Jim Xuの回答に関するコメントで述べたように、Azureエンドポイントをv2からv1に変更することでこの問題を解決しました。これは、エンドポイントを変更することで行われます。 v1とv2の比較 に示されているように、http://login.Microsoft.com/common/oauth2/v2.0/authorizehttp://login.Microsoft.com/common/oauth2/authorizeになります。

V1の詳細については、 docs を参照してください

0
phil

私のテストによれば、次のコードを使用できます

私の設定ファイル

spring:
  security:
    oauth2:
      client:
        registration:
           Azure:
             client-id: xxx
             client-secret: xxx
             client-name: Azure
             client-authentication-method: basic
             provider: Azure-oauth-provider
             scope: openid, https://graph.Microsoft.com/user.read, profile
             redirect-uri: http://localhost:8080/login/oauth2/code/Azure
             authorization-grant-type: authorization_code

        provider:
            Azure-oauth-provider:
              authorization-uri: https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/authorize
              user-info-uri: https://graph.Microsoft.com/oidc/userinfo 
              token-uri: https://login.microsoftonline.com/<tenant id>/oauth2/v2.0/token
              jwk-set-uri: https://login.microsoftonline.com/<tenant id>/v2.0/keys
              user-name-attribute: name

Azure:
  activedirectory:
    tenant-id: xxx
    active-directory-groups: ***

WebSecurityConfig.Java

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .anyRequest().authenticated()
            .and()
            .oauth2Login()
            .userInfoEndpoint()
            .oidcUserService(oidcUserService);
    }
}

enter image description here

enter image description here

0
Jim Xu