JWT authentication fails


we changed our plugin to use the atlassian-connect-spring-boot dependency in version 2.0.1 and expected it to handle the GDPR related changes to authentication transparently.

Our connect plugin app is calling Jira in the ACT_AS_USER scope to retrieve info about an issue. The connect.json specifies the authentication/type as jwt.

I see in the logs the call:

2020-10-13 21:58:08,382 http-nio-8443-exec-10 DEBUG c.x.jira.xstudio.helper.JiraHelper getJiraValue [XQUAL JH  ] GET from URL=https://xqual-dev-local.atlassian.net/rest/api/2/issue/PROJ-1?fields=id,summary,priority,issuetype,status,description
2020-10-13 21:58:08,383 http-nio-8443-exec-10 DEBUG c.a.c.s.i.r.o.JwtBearerAccessTokenProvider obtainAccessToken Requesting OAuth 2.0 access token using urn:ietf:params:oauth:grant-type:jwt-bearer
2020-10-13 21:58:08,384 http-nio-8443-exec-10 DEBUG c.a.c.s.i.r.o.OAuth2JwtAssertionGenerator getAssertionString Created OAuth 2.0 JWT assertion: {"sub":"urn:atlassian:connect:userkey:557058:9b03f379-659a-4302-8713-f1843af7397c","aud":"https:\/\/auth.atlassian.io","iss":"urn:atlassian:connect:clientid:eyJob3N0S2V5IjoiN2I5NDUyOGUtMWE1Yy0zYzlkLWI5MTAtOGUwMWE1MWU3

and a little later that:

2020-10-13 21:58:09,186 http-nio-8443-exec-10 DEBUG org.apache.http.wire wire http-outgoing-1 << "{"error":"invalid_grant","error_description":"Subject claim prefix urn:atlassian:connect:userkey: is no longer allowed"}"
2020-10-13 21:58:09,186 http-nio-8443-exec-10 DEBUG org.apache.http.headers onResponseReceived http-outgoing-1 << HTTP/1.1 400 Bad Request

It seems like the atlassian-connect-spring-boot framework adds the userkey property and later on complains about it.

Can anybody please enlighten me what goes wrong here?


1 Like

@matthias1, that sounds strange.

Which of the two AtlassianHostRestClients methods are you calling to obtain a OAuth2RestTemplate?

If authenticatedAsHostActor(), how is the security context being set: are you making the Jira API request as part of handling an incoming authenticated request?

Hi @epehrson, thanks for having a look.

I’m using the authenticatedAsHostActor() method in an issue-tab controller to show the logged-in user the content from our application which runs on a different server. For this I need first to request the issue details from Jira to be able to request the other details later on.

The code looks like this:

    @RequestMapping(value = "/issuetab", method = RequestMethod.GET)
    public String getIssueTabContent(@AuthenticationPrincipal AtlassianHostUser hostUser,
                                     Model model,
                                     String issuekey) {
        String hostBaseUrl = hostUser.getHost().getBaseUrl();
        config = JiraHelper.getProperty(getRestTemplate(), hostBaseUrl, JiraHelper.PROPERTYNAME_ADDONCONFIG, AddonConfig.class);
        if (null == config) {
            LOG.warn(LOG_PREFIX + "Plugin config could not be read.");
        LOG.debug(LOG_PREFIX + "Test property value is: {}", config.toString());

        String fields = "id,summary,priority,issuetype,status,description";
        issue = JiraHelper.getIssue(atlassianHostRestClients.authenticatedAsHostActor(), hostBaseUrl, issuekey, fields);

The getProperty() call (using atlassianHostRestClients.authenticatedAsAddon()) succeeds while the
getIssue() call (using the user-auth) fails.

Hm. If you enable debug logging for com.atlassian.connect.spring, you should see a Parsed JWT log line from JwtAuthenticationProvider. atlassian-connect-spring-boot should only fall back to using the user key if the account ID is not present.

Hi, here’s the log of the ‘Parsed JWT’ part - had to leave the rest of it out, b/o length restrictions. Let me know if you need to see more or where to send the whole request-log to.

2020-10-14 19:32:19,138 http-nio-8443-exec-6 DEBUG o.s.security.web.FilterChainProxy doFilterInternal /issuetab?issuekey=PROJ-1&xdm_e=https%3A%2F%2Fxqual-dev-local.atlassian.net&xdm_c=channel-com.xqual.jira.jira-xstudio-connect-plugin__xstudio-integration-issue-tab&cp=&xdm_deprecated_addon_key_do_not_use=com.xqual.jira.jira-xstudio-connect-plugin&lic=none&cv=1001.0.0-SNAPSHOT&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1NTcwNTg6OWIwM2YzNzktNjU5YS00MzAyLTg3MTMtZjE4NDNhZjczOTdjIiwicXNoIjoiYWZlMDk4NzVjOWU0YmI2MzU2OGEzY2M1MDAzNDc0ZjhkNTM5Y2JkZjYzM2I4Y2IxNTcyMmFiM2FhODA5NTEwNSIsImlzcyI6IjdiOTQ1MjhlLTFhNWMtM2M5ZC1iOTEwLThlMDFhNTFlNzljNyIsImNvbnRleHQiOnt9LCJleHAiOjE2MDI3MDQ4MzUsImlhdCI6MTYwMjcwMzkzNX0.V8nGSNkzxRjpsMlhbZGC2nwErFfRJiMeVOvhD_IsuN0 has no matching filters 
2020-10-14 19:32:19,139 http-nio-8443-exec-6 DEBUG c.a.c.s.i.a.j.JwtAuthenticationFilter createJwtAuthenticationToken Retrieved JWT from request 
2020-10-14 19:32:19,139 http-nio-8443-exec-6 DEBUG o.s.s.authentication.ProviderManager authenticate Authentication attempt using com.atlassian.connect.spring.internal.auth.jwt.JwtAuthenticationProvider 
2020-10-14 19:32:19,139 http-nio-8443-exec-6 DEBUG c.a.c.s.i.a.j.JwtAuthenticationProvider authenticate Parsed JWT: JWTClaimsSet [iss=7b94528e-1a5c-3c9d-b910-8e01a51e79c7, sub=557058:9b03f379-659a-4302-8713-f1843af7397c, aud=null, exp=Wed Oct 14 19:47:15 UTC 2020, nbf=null, iat=Wed Oct 14 19:32:15 UTC 2020, jti=null, typ=null, customClaims={qsh=afe09875c9e4bb63568a3cc5003474f8d539cbdf633b8cb15722ab3aa8095105, context={}}] 

So, the context claim of the JWT is empty, and you are using atlassian-connect-spring-boot:2.0.1, which will then interpret the JWT sub as an account ID. The user key of the security context is never set.

I don’t really have any ideas at this point. Can you set this up locally and debug through it to see where the user key is set on the AtlassianHostUser?

Should the user key be set by atlassian-connect-spring-boot or by Spring? I just saw that we’re using an older version of spring-boot (1.4.7.RELEASE) because we need the Velocity support which was removed in newer versions.

@matthias1 but if you’re using Spring Boot 1, you are surely using atlassian-connect-spring-boot 1. And I have to strongly encourage you to upgrade to Spring Boot 2 and the latest atlassian-connect-spring-boot. Per the CHANGELOG, we have fixed a number of security issues, as well as migrated away from several deprecated APIs, for which the deprecation period has already expired.

1 Like

@epehrson, yes, I already feared that we’d have to do a major upgrade of our plugin. Now switched to Spring Boot 2 and it seems to authenticate Ok now:

2020-10-25 10:27:26,098 http-nio-8080-exec-1 DEBUG c.a.c.s.i.a.j.JwtAuthenticationProvider authenticate Parsed JWT: {"sub":"557058:64c7f919-ee3b-4cf3-8d69-00d92030b2ea","qsh":"75367934b7844d9b02f94359c182095a99c75918894a1856c36d620b812405c6","iss":"a15c2049-7630-3590-9d20-0e1781aa4590","context":{},"exp":1603618920,"iat":1603618020} 
2020-10-25 10:27:26,266 http-nio-8080-exec-1 DEBUG c.a.c.s.i.a.j.JwtAuthenticationProvider computeQueryStringHash Canonical request for incoming JWT: [CanonicalHttpServletRequest@756a08c0 method = 'GET', relativePath = '/issuetab', parameterMap = '[issuekey -> (TEST-1),xdm_e -> (https://kuespert-dev-1.atlassian.net),xdm_c -> (channel-com.xqual.jira.jira-xstudio-connect-plugin__xstudio-integration-issue-tab),cp -> (),xdm_deprecated_addon_key_do_not_use -> (com.xqual.jira.jira-xstudio-connect-plugin),lic -> (none),cv -> (1001.0.0-SNAPSHOT),jwt -> (eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1NTcwNTg6NjRjN2Y5MTktZWUzYi00Y2YzLThkNjktMDBkOTIwMzBiMmVhIiwicXNoIjoiNzUzNjc5MzRiNzg0NGQ5YjAyZjk0MzU5YzE4MjA5NWE5OWM3NTkxODg5NGExODU2YzM2ZDYyMGI4MTI0MDVjNiIsImlzcyI6ImExNWMyMDQ5LTc2MzAtMzU5MC05ZDIwLTBlMTc4MWFhNDU5MCIsImNvbnRleHQiOnt9LCJleHAiOjE2MDM2MTg5MjAsImlhdCI6MTYwMzYxODAyMH0.FUPE9Zuw6UyJlNogUWz8JHncu7mbLOxOX1gsaGYbBLM),]'] 
2020-10-25 10:27:26,358 http-nio-8080-exec-1 DEBUG c.a.c.s.i.a.j.JwtAuthenticationProvider verifyToken Verified JWT for host https://kuespert-dev-1.atlassian.net (a15c2049-7630-3590-9d20-0e1781aa4590)  

Thanks a lot for your support!

1 Like