Configuration of Microsoft Graph OAuth2 authentication in Spring Security - Error AADSTS90014

usr-local-ΕΨΗΕΛΩΝ

I am writing an SSO provider for MS Graph APIs Azure AD v2 endpoint leveraging Spring OAuth2.

I am progressing with the implementation and constant testing but I stumbled upon an error returned by AAD which is puzzling me. After all, this should all be plain standard OAuth 2 flow.

I successfully configured my application on MS dev portal, providing a localhost redirect URL (which, for the record, is the only supporting the http scheme. Kudos to MS). So when I invoke http://localhost/myapp/auth/office365 Spring security successfully intercepts the invocation, provides a correct redirect to my browser with client ID to https://login.microsoftonline.com/common/oauth2/v2.0/authorize with expected parameters.

Microsoft shows a consent screen to me, after which I get redirected back to my Spring Security application via HTTP GET with expected authorization code parameter.

The problem is that when the application tries to negotiate the given authorization code for a bearer token headaches start. Spring Security invokes a POST to https://login.microsoftonline.com/common/oauth2/v2.0/token but ends in 401 error.

Here is the stack trace

error="invalid_request", error_description="AADSTS90014: The request body must contain the following parameter: 'client_id'.
Trace ID: 9acd2a10-1cfb-443f-9c57-78d608c00c00
Correlation ID: bf063914-8926-4e8f-b102-7522d0e3b0af
Timestamp: 2017-10-09 15:51:44Z", correlation_id="bf063914-8926-4e8f-b102-7522d0e3b0af", error_codes="[90014]", timestamp="2017-10-09 15:51:44Z", trace_id="9acd2a10-1cfb-443f-9c57-78d608c00c00"
    at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:100)
    at org.springframework.security.oauth2.common.exceptions.OAuth2ExceptionJackson2Deserializer.deserialize(OAuth2ExceptionJackson2Deserializer.java:33)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:235)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readInternal(AbstractJackson2HttpMessageConverter.java:215)
    at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:193)
    at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:235)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:621)
    at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:137)
    at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:209)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:148)
    at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:121)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
    at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
    at org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:105)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)

I have looked into Spring security implementation to find the cause,.

It happens that the error message error="invalid_request", error_description="AADSTS90014: The request body must contain the following parameter: 'client_id'. is self explanatory: MS Graph wants the client ID (which is still supplied by the basic authentication header) in the request body. Stop for a moment. I want to use plain old Spring Security and not third-party specific jars in order not to pollute my classpath.

Looking into Java source code of Spring OAuth 2 the problem is damn clear. Spring uses the client ID only in getParametersForAuthorizeRequest, which is used to generate the redirect URL. When it comes to getParametersForTokenRequest the client ID is not specified in the form.

Question: who is right here? How do I tell Spring that MS wants the client id in the token request after an authorization code has been obtained?

Marc LaFleur

Just to clarify, you're not actually authenticating with or against Microsoft Graph. You're actually authenticating against Azure Active Directory. The Microsoft Graph API accepts the bearer token you'll end up with but it doesn't issue the access token itself.

It isn't clear which endpoint you're using for the Authorization Code flow, AAD has two of them: v1 and v2. The primary difference being that v2 uses a central registration and can authenticate both work/school and personal accounts.

Regardless of the endpoint, you do need to supply the clientid in the request body when you're requesting an access token. There are actually several values you need to provide in the body. Also note that these need to be provided as application/x-www-form-urlencoded.

For the v1 endpoint you provide (line breaks for readability only):

grant_type=authorization_code
&client_id={client-id}
&code={authoization-code}
&redirect_uri={redirect-uri}
&client_secret={client-secret}
&resource={resource-uri}

The v2 endpoint is almost identical but uses scope instead of resource:

grant_type=authorization_code
&client_id={client-id}
&code={authoization-code}
&redirect_uri={redirect-uri}
&client_secret={client-secret}
&scope={scopes}

OP's edit

Now, back to Spring Security. Spring by default uses an HTTP basic authentication scheme against Azure AD. In that scheme, the client ID and secret are encoded into the HTTP Authorization header, then the form only contains the authorization code and state parameter, so here is why I (the OP, ndr) was puzzled about why AAD refused the authorization.

In order to pass client ID and secret into the form, we can tell Spring Security to use a different supported authentication scheme. The form authentication scheme will push the client ID and secret into the form. The below code works and retrieves the access token.

<oauth2:resource
  id="msAdAuthenticationSource"
  client-id="${oauth.appId}"
  client-secret="${oauth.appSecret}"
  type="authorization_code"
  authentication-scheme="form"
  client-authentication-scheme="form"
  use-current-uri="true"
  user-authorization-uri="${oauth.authorizationUri}"
  access-token-uri="${oauth.accessTokenUri}"
  scope="${oauth.scopes}"
  pre-established-redirect-uri="${oauth.redirectUri}" />

Please note the two

authentication-scheme="form"
client-authentication-scheme="form"

Problem solved, a lot more to come!

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Where is an Example Spring Security OAuth2 Client Configuration using XML for Authorization Code?

分類Dev

Spring Security OAuth2 | InsufficientAuthenticationException

分類Dev

Spring Security OAuth2:InsufficientAuthenticationException

分類Dev

Spring Boot Security OAuth2:WebSecurityConfigurerAdapter:302 / errorにリダイレクト

分類Dev

Migrating from Spring Boot Oauth2 to Spring Security 5

分類Dev

Spring boot 2.0.3 + Security + Oauth2 autoconfigure

分類Dev

Incremental authorization for Google OAuth2 Sign in with Spring Security

分類Dev

Spring Security LDAP Configuration

分類Dev

How to enable /oauth/check_token with Spring Security Oauth2 using XML

分類Dev

Spring Security OAuth2: how to add multiple Security Filter Chain of type ResourceServerConfigurer?

分類Dev

Authentication failing spring security wildfly

分類Dev

Microsoft Graph API Authentication_MissingOrMalformed

分類Dev

Using Azure Active Directory as an OAUTH2 Authentication service for a Spring-boot REST service

分類Dev

Using Azure Active Directory as an OAUTH2 Authentication service for a Spring-boot REST service

分類Dev

Spring Security OAuth2はJSONを受け入れる

分類Dev

Spring Security OAuth2ピュアリソースサーバー

分類Dev

GoogleでのSpring Security OAuth2ログイン

分類Dev

Spring Boot Security OAuth2 Get Access_token from Cookie

分類Dev

NoClassDefFoundError:javax / xml / bind / UnmarshalException-Spring Security oauth2

分類Dev

NoClassDefFoundError:javax / xml / bind / UnmarshalException-Spring Security oauth2

分類Dev

How to use Spring Security 5 and OAuth2 Client to get refresh tokens and make API calls?

分類Dev

How to use Spring Security 5 and OAuth2 Client to get refresh tokens and make API calls?

分類Dev

Spring Security - oAuth2 実装のための UserDetailsService?

分類Dev

Spring Security 5.1.1Spring-security-oauth2認証サーバーに接続するOAuth2クライアント

分類Dev

Spring Security OAuth2実装で成功したOAuth2認証にCookieを設定する

分類Dev

Getting error from spring-security.xml in case of multi-tenacy with Oauth,SAML, and spring-security

分類Dev

Using both LDAP and DB authentication with Spring Security

分類Dev

Removing a log from Spring Security authentication logging

分類Dev

spring-security force "http" authentication

Related 関連記事

  1. 1

    Where is an Example Spring Security OAuth2 Client Configuration using XML for Authorization Code?

  2. 2

    Spring Security OAuth2 | InsufficientAuthenticationException

  3. 3

    Spring Security OAuth2:InsufficientAuthenticationException

  4. 4

    Spring Boot Security OAuth2:WebSecurityConfigurerAdapter:302 / errorにリダイレクト

  5. 5

    Migrating from Spring Boot Oauth2 to Spring Security 5

  6. 6

    Spring boot 2.0.3 + Security + Oauth2 autoconfigure

  7. 7

    Incremental authorization for Google OAuth2 Sign in with Spring Security

  8. 8

    Spring Security LDAP Configuration

  9. 9

    How to enable /oauth/check_token with Spring Security Oauth2 using XML

  10. 10

    Spring Security OAuth2: how to add multiple Security Filter Chain of type ResourceServerConfigurer?

  11. 11

    Authentication failing spring security wildfly

  12. 12

    Microsoft Graph API Authentication_MissingOrMalformed

  13. 13

    Using Azure Active Directory as an OAUTH2 Authentication service for a Spring-boot REST service

  14. 14

    Using Azure Active Directory as an OAUTH2 Authentication service for a Spring-boot REST service

  15. 15

    Spring Security OAuth2はJSONを受け入れる

  16. 16

    Spring Security OAuth2ピュアリソースサーバー

  17. 17

    GoogleでのSpring Security OAuth2ログイン

  18. 18

    Spring Boot Security OAuth2 Get Access_token from Cookie

  19. 19

    NoClassDefFoundError:javax / xml / bind / UnmarshalException-Spring Security oauth2

  20. 20

    NoClassDefFoundError:javax / xml / bind / UnmarshalException-Spring Security oauth2

  21. 21

    How to use Spring Security 5 and OAuth2 Client to get refresh tokens and make API calls?

  22. 22

    How to use Spring Security 5 and OAuth2 Client to get refresh tokens and make API calls?

  23. 23

    Spring Security - oAuth2 実装のための UserDetailsService?

  24. 24

    Spring Security 5.1.1Spring-security-oauth2認証サーバーに接続するOAuth2クライアント

  25. 25

    Spring Security OAuth2実装で成功したOAuth2認証にCookieを設定する

  26. 26

    Getting error from spring-security.xml in case of multi-tenacy with Oauth,SAML, and spring-security

  27. 27

    Using both LDAP and DB authentication with Spring Security

  28. 28

    Removing a log from Spring Security authentication logging

  29. 29

    spring-security force "http" authentication

ホットタグ

アーカイブ