Azure / azure-sdk-for-java

This repository is for active development of the Azure SDK for Java. For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/java/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-java.
MIT License
2.35k stars 1.99k forks source link

Exception when following Azure AD tutorial[BUG] #13061

Closed harry12345678910 closed 4 years ago

harry12345678910 commented 4 years ago

Describe the bug I get the following exeption when using the example Authenticate stateless APIs using AAD app roles

Exception or Stack Trace

com.nimbusds.jose.proc.BadJOSEException: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
 com.nimbusds.jwt.proc.DefaultJWTProcessor.<clinit>(DefaultJWTProcessor.java:99)
 com.microsoft.azure.spring.autoconfigure.aad.UserPrincipalManager.getAadJwtTokenValidator(UserPrincipalManager.java:153)
 com.microsoft.azure.spring.autoconfigure.aad.UserPrincipalManager.buildUserPrincipal(UserPrincipalManager.java:126)
 com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter.verifyToken(AADAppRoleStatelessAuthenticationFilter.java:76)
 com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter.doFilterInternal(AADAppRoleStatelessAuthenticationFilter.java:56)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
 org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
 org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
 org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
 org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
 org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
 java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
 java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
 org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 java.base/java.lang.Thread.run(Thread.java:832)\r\n",
    "message": "Signed JWT rejected: Another algorithm expected, or no matching key(s) found",
    "path": "/api/products"

To Reproduce setup: POM:

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-active-directory-spring-boot-starter</artifactId>
    <version>2.3.2</version>
</dependency>
azure.activedirectory.client-id=36fa87ac-27cc-43fa-ab4a-02151effb2c4
azure.activedirectory.client-secret=XXXXXXXXXXXX-
azure.activedirectory.session-stateless=true
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AADAppRoleStatelessAuthenticationFilter appRoleAuthFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(appRoleAuthFilter, UsernamePasswordAuthenticationFilter.class);
    }

}

Code Snippet Add the code snippet that causes the issue.

Expected behavior verify token and grant access to api

Setup (please complete the following information):

Additional context Add any other context about the problem here.

Information Checklist Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

saragluna commented 4 years ago

Thanks for reaching out. Which kind token are you passing to the AADAppRoleStatelessAuthenticationFilter? How is the token retrieved?

harry12345678910 commented 4 years ago

Hi, thanks for your support. The tokens look like this: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjFMVE16YWtpaGlSbGFfOHoyQkVKVlhlV01xbyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFNV3hmNUJ3UWdkS0NOSEVrQi1tZGVNIiwiYXVkIjoiMzZmYTg3YWMtMjdjYy00M2ZhLWFiNGEtMDIxNTFlZmZiMmM0IiwiZXhwIjoxNTk0NTkwMTQ0LCJpYXQiOjE1OTQ1ODYyNDQsIm5iZiI6MTU5NDU4NjI0NCwibmFtZSI6IkhhcmFsZCBCYXllciIsInByZWZlcnJlZF91c2VybmFtZSI6ImguYmF5ZXJAcGhvZW5peGdyb3VwLmV1Iiwib2lkIjoiMDAwMDAwMDAtMDAwMC0wMDAwLWY0M2ItNmJkOWNkNWRlZTczIiwidGlkIjoiOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkIiwiYXpwIjoiOTk4NDc5YjMtOGQ5Yy00NTM5LWFhZTEtZGVjZjgxZjIxMzI3Iiwic2NwIjoiYXBpLWFjY2VzcyIsImF6cGFjciI6IjEiLCJhaW8iOiJEWEswdExpNFRrNGEyT1lIeGNkd3VzZnZkRnFzNWdPck0halRIUlppMjNFdDhSNUF4UW5mRyExWFF0UlR2Q08qUGUzWjV5WmNyRENsQ1BTU09kMkgwdDIxdHRkWWJtZ3hGWkpTbks2aHNqSUpSVnVZcWpZYk5tS0JweUtiN1F4Z1U2ZnRzdVIqbHRXazN2cEhSQU1scndRJCJ9.n4k0L1uxeqq_FLl3PhTjVa7nYiJTVZPgdEJ1XQVtDeI1MfwDXD9xmyyrhtSd7r-WlXaHgI4YUCZy3r4T_bBr_w--u_daWJgwxOwPyb7WukZV3_KbGcKMARXGlJd-I_RboZ7AeM_da6gxstSqiuLQtA_hM9ff5AcAOr7oYFxZHW16gUI_jYKZWs6vYrOt-9ULK197PK8vF-BbXGsYmjfs6tYil60ovV02MuIiu3Qyg9Ovh0oXST310-X52OwfdtWJA1DxhY1USfXqu-W1udcT01WT58OFWQZNTTkxNaLapFar6BggMD7JNbh5PX0iR0UHifuL43M1ZS_xQ6CtkPxsww

or eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjFMVE16YWtpaGlSbGFfOHoyQkVKVlhlV01xbyJ9.eyJ2ZXIiOiIyLjAiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkL3YyLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFNV3hmNUJ3UWdkS0NOSEVrQi1tZGVNIiwiYXVkIjoiMzZmYTg3YWMtMjdjYy00M2ZhLWFiNGEtMDIxNTFlZmZiMmM0IiwiZXhwIjoxNTk0NjI2NDcwLCJpYXQiOjE1OTQ2MjI1NzAsIm5iZiI6MTU5NDYyMjU3MCwibmFtZSI6IkhhcmFsZCBCYXllciIsInByZWZlcnJlZF91c2VybmFtZSI6ImguYmF5ZXJAcGhvZW5peGdyb3VwLmV1Iiwib2lkIjoiMDAwMDAwMDAtMDAwMC0wMDAwLWY0M2ItNmJkOWNkNWRlZTczIiwidGlkIjoiOTE4ODA0MGQtNmM2Ny00YzViLWIxMTItMzZhMzA0YjY2ZGFkIiwiYXpwIjoiOTk4NDc5YjMtOGQ5Yy00NTM5LWFhZTEtZGVjZjgxZjIxMzI3Iiwic2NwIjoiYXBpLWFjY2VzcyIsImF6cGFjciI6IjEiLCJhaW8iOiJEYjgwUXB3c05ydGpnRXB6Q25TVnBiZ1VpYU1CanJmNmxqQ1pnT0kqU3lBIUdiZWFzOHdWR3pDOUlwOG56VlRKUlVhdmt2NXlscEtOVTUzdmEzajQhNmNoYmYqWDIzUGFxRCFDYnJ5TlZ2QjlnVGRydFlyVmhpZ2c1anQ2Z0ltKmpabm94bnZhTTdaZDQzcG10MkJMTkpnJCJ9.17Bu-cft31YcXGkOkkwSMrY0PRUSVMtbhahHs9aa-7dIJSIpO90OghM7n5_8SwRyuhsRRo-ZWSRAD3bj8IvgbJ08owf1W4dcE4W7GhahJIZAdLFqAsSDqkT5nOhykR5oCORY0S0uu2H1EXHHx-At_MMh7MWN514-IRQlTrO6at_hH6C8LUufazA-rlG2MUvQrEBoJspTfbp--qbfkLsu8j7ZXfYUPSqq0iYOdrh0iJ-5iS4-EvCi58xZGhaHh4O3Zp-iVvxFV7sWlsQ72HOJEuTW25u8HqDQnQvan0oZR0qabJzXpKeMfCD0lBWmm2Y5ULlS6FFVCRDun5gux1CIoQ

They are retrieved using postman. I tried both implicit flow and authorization code. But get the same exception with both.

harry12345678910 commented 4 years ago

In Postman it looks like that: image

harry12345678910 commented 4 years ago

The backend manifest:

{
    "id": "eeffbaa9-346a-4240-b02f-1276b1368b29",
    "acceptMappedClaims": null,
    "accessTokenAcceptedVersion": 2,
    "addIns": [],
    "allowPublicClient": null,
    "appId": "36fa87ac-27cc-43fa-ab4a-02151effb2c4",
    "appRoles": [
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "My demo role.",
            "displayName": "My demo",
            "id": "6791d636-113c-43e9-81d3-c4867e931390",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "reader"
        }
    ],
    "oauth2AllowUrlPathMatching": false,
    "createdDateTime": "2020-07-09T11:46:54Z",
    "groupMembershipClaims": "All, ApplicationGroup",
    "identifierUris": [
        "api://36fa87ac-27cc-43fa-ab4a-02151effb2c4"
    ],
    "informationalUrls": {
        "termsOfService": null,
        "support": null,
        "privacy": null,
        "marketing": null
    },
    "keyCredentials": [],
    "knownClientApplications": [],
    "logoUrl": null,
    "logoutUrl": null,
    "name": "spring boot backend",
    "oauth2AllowIdTokenImplicitFlow": true,
    "oauth2AllowImplicitFlow": true,
    "oauth2Permissions": [
        {
            "adminConsentDescription": "allow the demo api to be used",
            "adminConsentDisplayName": "consent api access",
            "id": "1641dbfb-cee9-4dda-b7da-6baef4d6c185",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "type": "Admin",
            "userConsentDescription": null,
            "userConsentDisplayName": null,
            "value": "api-access"
        }
    ],
    "oauth2RequirePostResponse": false,
    "optionalClaims": {
        "idToken": [
            {
                "name": "groups",
                "source": null,
                "essential": false,
                "additionalProperties": []
            }
        ],
        "accessToken": [
            {
                "name": "groups",
                "source": null,
                "essential": false,
                "additionalProperties": []
            }
        ],
        "saml2Token": []
    },
    "orgRestrictions": [],
    "parentalControlSettings": {
        "countriesBlockedForMinors": [],
        "legalAgeGroupRule": "Allow"
    },
    "passwordCredentials": [
        {
            "customKeyIdentifier": null,
            "endDate": "2299-12-30T23:00:00Z",
            "keyId": "402fab83-6704-4b05-a95d-540c35d7578b",
            "startDate": "2020-07-09T12:45:26.91Z",
            "value": null,
            "createdOn": "2020-07-09T12:45:28.8726536Z",
            "hint": "Nk-",
            "displayName": "Password uploaded on Thu Jul 09 2020"
        }
    ],
    "preAuthorizedApplications": [
        {
            "appId": "998479b3-8d9c-4539-aae1-decf81f21327",
            "permissionIds": [
                "1641dbfb-cee9-4dda-b7da-6baef4d6c185"
            ]
        },
        {
            "appId": "c607918f-57a3-4fb0-a9a8-57e632320f66",
            "permissionIds": [
                "1641dbfb-cee9-4dda-b7da-6baef4d6c185"
            ]
        }
    ],
    "publisherDomain": "hbayerphoenixgroup.onmicrosoft.com",
    "replyUrlsWithType": [],
    "requiredResourceAccess": [
        {
            "resourceAppId": "00000003-0000-0000-c000-000000000000",
            "resourceAccess": [
                {
                    "id": "0e263e50-5827-48a4-b97c-d940288653c7",
                    "type": "Scope"
                },
                {
                    "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
                    "type": "Scope"
                }
            ]
        }
    ],
    "samlMetadataUrl": null,
    "signInUrl": null,
    "signInAudience": "AzureADandPersonalMicrosoftAccount",
    "tags": [
        "webApi",
        "notApiConsumer"
    ],
    "tokenEncryptionKeyId": null,
    "verifiedPublisher": {
        "displayName": null,
        "verifiedPublisherId": null,
        "addedDateTime": null
    }
}

The postman manifest:

{
    "id": "f950f2d7-c008-4541-91ba-cc8d783068a3",
    "acceptMappedClaims": null,
    "accessTokenAcceptedVersion": 2,
    "addIns": [],
    "allowPublicClient": null,
    "appId": "998479b3-8d9c-4539-aae1-decf81f21327",
    "appRoles": [],
    "oauth2AllowUrlPathMatching": false,
    "createdDateTime": "2020-07-12T17:03:24Z",
    "groupMembershipClaims": "All, ApplicationGroup",
    "identifierUris": [],
    "informationalUrls": {
        "termsOfService": null,
        "support": null,
        "privacy": null,
        "marketing": null
    },
    "keyCredentials": [],
    "knownClientApplications": [],
    "logoUrl": null,
    "logoutUrl": null,
    "name": "Postman SpringBoot",
    "oauth2AllowIdTokenImplicitFlow": true,
    "oauth2AllowImplicitFlow": true,
    "oauth2Permissions": [],
    "oauth2RequirePostResponse": false,
    "optionalClaims": {
        "idToken": [
            {
                "name": "groups",
                "source": null,
                "essential": false,
                "additionalProperties": []
            }
        ],
        "accessToken": [
            {
                "name": "groups",
                "source": null,
                "essential": false,
                "additionalProperties": []
            }
        ],
        "saml2Token": []
    },
    "orgRestrictions": [],
    "parentalControlSettings": {
        "countriesBlockedForMinors": [],
        "legalAgeGroupRule": "Allow"
    },
    "passwordCredentials": [
        {
            "customKeyIdentifier": null,
            "endDate": "2299-12-30T23:00:00Z",
            "keyId": "2b151c7f-5137-4235-9dc2-c44f3e5028a6",
            "startDate": "2020-07-12T17:03:37.001Z",
            "value": null,
            "createdOn": "2020-07-12T17:03:41.8594762Z",
            "hint": "0o.",
            "displayName": "Password uploaded on Sun Jul 12 2020"
        }
    ],
    "preAuthorizedApplications": [],
    "publisherDomain": "hbayerphoenixgroup.onmicrosoft.com",
    "replyUrlsWithType": [
        {
            "url": "http://localhost",
            "type": "Web"
        }
    ],
    "requiredResourceAccess": [
        {
            "resourceAppId": "36fa87ac-27cc-43fa-ab4a-02151effb2c4",
            "resourceAccess": [
                {
                    "id": "1641dbfb-cee9-4dda-b7da-6baef4d6c185",
                    "type": "Scope"
                }
            ]
        },
        {
            "resourceAppId": "00000003-0000-0000-c000-000000000000",
            "resourceAccess": [
                {
                    "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
                    "type": "Scope"
                }
            ]
        }
    ],
    "samlMetadataUrl": null,
    "signInUrl": null,
    "signInAudience": "AzureADandPersonalMicrosoftAccount",
    "tags": [],
    "tokenEncryptionKeyId": null,
    "verifiedPublisher": {
        "displayName": null,
        "verifiedPublisherId": null,
        "addedDateTime": null
    }
}
saragluna commented 4 years ago

Thanks for the detailed info, this error was caused by the discovery-key-uri configuration is not one of the v2.0 endpoints. It should be https://login.microsoftonline.com/common/discovery/v2.0/keys/. You could check a whole set of endpoints here https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration.

One possible solution is to create a copy of this file (https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/spring/azure-spring-boot/src/main/resources/serviceEndpoints.properties) under your classpath and add these entries in it:

azure.service.endpoints.global.aadSigninUri=https://login.microsoftonline.com/
azure.service.endpoints.global.aadGraphApiUri=https://graph.windows.net/
azure.service.endpoints.global.aadKeyDiscoveryUri=https://login.microsoftonline.com/common/discovery/v2.0/keys/
azure.service.endpoints.global.aadMembershipRestUri=https://graph.windows.net/me/memberOf?api-version=1.6

And I didn't see roles claim in your JWT, did you assign the role to your user? You could check the token here https://jwt.ms/.

harry12345678910 commented 4 years ago

It is working now. Thanks a lot for your support!! I have to figure out the roles functionality now.

harry12345678910 commented 4 years ago

It is working now. Thanks a lot for your support!! I have to figure out the roles functionality now.