Action Required - Atlassian Connect installation lifecycle security improvements

Hi @rohan this change applies to install and uninstall lifecycle only.
enabled and disabled lifecycle will remain unchanged, which includes the symmetric JWT
that needs to be verified using a sharedSecret.

2 Likes

Hi @ErkkiLepre , Thank you for your patience with reciprocating issues you are finding. request.context is restored for authenticateInstall middleware in v7.4.3.
For your information, hostBaseUrl in request.context comes from the request body if it is a very first installation for a host, and from the db storage for subsequent install callbacks(upgrades). Which is expected to be eventually consistent as hostBaseUrl should be stored in database during postInstallation step.

Updated: wrong version was mentioned, corrected it to v7.4.3

2 Likes

Hi @HanjooSong, isn’t the setting atlassian.connect.allow-symmetric-auth-install-callback now?

When I set it to false, I get an error

java.lang.ClassNotFoundException: org.springframework.boot.web.error.ErrorAttributeOptions
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_292]
at java.lang.ClassLoader.loadClass(ClassLoader.java:418) ~[na:1.8.0_292]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352) ~[na:1.8.0_292]
at java.lang.ClassLoader.loadClass(ClassLoader.java:351) ~[na:1.8.0_292]
at com.atlassian.connect.spring.internal.AtlassianConnectErrorController.error(AtlassianConnectErrorController.java:44) ~[atlassian-connect-spring-boot-core-2.2.2.jar:na]

it it ok?

Hi @palbecki , I will have a look at the error you’ve reported. In the mean time it is not required to set atlassian.connect.allow-symmetric-auth-install-callback to false.

Hi @HanjooSong @HeyJoe

Could you clarify what this means for this site-import workaround we have implemented in our custom logic? Currently, if we get an install-hook for an instance we know by baseUrl, we reject this with 401, which leads to Atlassian retrying with a signed install hook with the old secret. How does this work together with the signed JWTS that are now always present? Should we just get rid of the custom logic?

Thanks
Tobias

@HanjooSong

I have implemented a new signature method and published it on the production. The app descriptor is updated and the new version is published. I have tested fresh app installation on a freshly created new Jira instance and it worked fine.

But now I got an error while one of my leads was trying to install the app. For some reason, Jira was calling installation webhook with old symmetrical signature for https://cloudadoptionsolutions.atlassian.net. Maybe that was a call from the Atlassian script, not the client manual action.

And I have found something really weird, Jira started calling installation webhook multiple times on different days for this specific Jira instance without calling uninstallation webhooks. That happens at the same time. And this call with the old symmetric signature was part of this weird webhook sequence.

And these calls are not from your security bot (I also get many calls from bot). The calls on the screenshot have regular user-agent and all other headers, like for real app installation.

Looks like there is some bug on the Atlassian side. So I had to roll back forcing using the new signature method in my script. And now I need to support both methods in my code :frowning:

App key is io.helloclerk.invoices

Can you please check this?
Thanks!

1 Like

@HanjooSong @ekaukonen I have found many instances with such weird multiple install webhooks, I can send their URLs if needed.

Hi @tobias.viehweger , yes you are correct. The retry sequence is no longer needed with the new install callback change, and there won’t be any retries sent even if we receive 4xx from the app.

1 Like

Hi @anton2 , apologies for not following up with your previous request to rotate your app secret. I believe this is due to 2 different jobs interfering each other and both trying to install(rotate key) + upgrade your app. I have now closed the secretKey rotation process so that you won’t be getting the key rotation callbacks over and over again.

@HanjooSong Thanks!

Hi @HanjooSong, I am using Atlassian Connect Spring Boot 2.2.3 I Just added “signed-install: true” to apiMigrations. Also, I am using :

@EventListener
	public void processAddonInstalledEvent(AddonInstalledEvent event) {

to handle the Install addon event.
The addon works fine after updating the Atlassian Spring boot to 2.2.3 and adding signed-install: true to Atlassian-connect.json.
My question is if I am using @EventListener to handle the Install event do I need to upgrade Atlassian Spring boot to 2.2.3 and adding signed-install: true?

Am i understanding correctly that when i upgrade from ACS 6.xxx to ACS 7.4.x, in order to comply with this breaking change, i only need to update the ACS package? No need to implement the jwt verification itself, right?

And Is it necessary to add

“apiMigrations”: {
“gdpr”: true,
“signed-install”: true
},

to the descriptor, or not?

Thanks

1 Like

Hi @phil yes you are right. For ACE and ACSB framework based apps, “signed-install”: true is the only configuration needed.

Hi @HusseinFares , @EventListener process will be triggered when installed hook authentication is successful.
So yes, you still need signed-install: true configured so that ACSB app will authenticate properly and fire those events.

Thanks @HanjooSong for the Reply.

One more thing:

  • So we update our atlassian-connect to singed-install = true. This will create a new version of our app, right?
  • We do not make a change to config.json
  • How can we check if everything works properly? I installed the app on a test instance, but when I inspect the decoded jwt token inside an /installed or /uninstalled hook, i cannot find the “kid” property… So i guess, currently, the jwt is not asymmetrically decoded? Or does the ACE middleware remove this property from the object during processing?
1 Like

Hi @phil ,

  • Yes, update to the descriptor file with singed-install: true will create a new version.
  • Correct, you don’t need to do anything in config.json, although it does pretty much the same, it was a bad idea in the beginning to have it in config.json.
  • I suppose the JWT token should already have the kid in the header. Could you make sure you have inspected the JWT header instead of the body? JWT header should look contain kid, alg and typ like below.
{
  "kid": "kid_for_public_key",
  "typ": "JWT",
  "alg": "RS256", // This should be RS256 instead of HS256 after you opted in. 
}

Please let me know if you still see the new JWT token.

@HanjooSong , thank you. You are right, i was inspecting the body, not the header. Seems to work!

In regards to your statement that updating config.json does the same thing, is it compliant to not to update atlassian-connect.json but config.json instead with signed-install=true in order to prevent the app from being versioned up?

Are Jira Data Centre addons affected by this security vulnerability?

Hi @HanjooSong,
I’m using ACE 7.4.4 and have “signed-install”: true set in the atlassian-connect.json. Installation works fine in the old Confluence instances. Today a created a new Confluence instance and tried to install the app, but it fails with the following error:
Authentication verification error (401): JWT claim did not contain the correct audience (aud) claim
Looks like some our customers already failed to install the app because of this issue.
Also, could you update the post with the info about addon.authenticateInstall() for /installed and /uninstalled callbacks?

I’m currently implementing this change for our custom jwt auth. handling. Works good so far. I stumbled across that the Atlassian backend now sends a new sharedSecret for every subsequent installation. This is new isn’t it? Actually pretty cool because this allows to recover from lost sharedSecrets in dev-mode. Can you confirm that @HanjooSong ?