Action Required - Atlassian Connect installation lifecycle security improvements

You’re right, I guess the CDN’s website certificate should be prove enough that the keys are valid.
Thanks for the clarification :slight_smile:

I have 500 error after upgrading ACSP to 2.2.0 and enabled asymmetric install hook.

java.lang.IllegalArgumentException: Illegal base64 character a
	at java.util.Base64$Decoder.decode0(Base64.java:714) ~[na:1.8.0_241]
	at java.util.Base64$Decoder.decode(Base64.java:526) ~[na:1.8.0_241]
	at java.util.Base64$Decoder.decode(Base64.java:549) ~[na:1.8.0_241]
	at com.atlassian.connect.spring.internal.jwt.RsaJwtReader.fromPEMEncodedKey(RsaJwtReader.java:68) ~[atlassian-connect-spring-boot-jwt-2.2.0.jar:na]

I started my app with ngrok, and set baseUrl:ngrok path. Can it break something?

{
  "key": "api-key-example",
  "baseUrl": "https://0cf8af0f628d.ngrok.io",
  "apiVersion": 8,
  "name": "name",
  "description": "desc.",
  "vendor": {
    "name": "Vendor",
  },
  "enableLicensing": true,
  "authentication": {
    "type": "jwt"
  },
  "apiMigrations": {
    "context-qsh": true,
    "signed-install": true
  }
1 Like

It appears that atlassian-jwt does not support asymmetrically signed token validation, passing in a public RSA key, is this correct? Is that the reason for an external lib being specified in example?

Hi @mike1 ,

While that version of atlassian-jwt is open source, it’s at the moment only being used by our server products. But yes, it not supporting asymmetric signatures one of the reasons why we the examples use a third party library.

If you’re after a more complete example, you could take a look at Atlassian Connect Spring boot (https://bitbucket.org/atlassian/atlassian-connect-spring-boot/pull-requests/150).

3 Likes

What about the enabled and disabled lifecycle webhooks? Will they continue to be signed symmetrically?

Also, would somebody explain why the uninstall webhooks are included in this? Surely the issue was with Atlassian securely sharing the secret with the app which was fixed by having asymmetrically signed install events, but uninstall events must come after install hence the secret will have already been shared.

I understand the change and welcome the commitment from Atlassian to address security issues, but with this change, we’re introducing more complexity for Connect and I was wondering if there are any plans to get rid of the shared secret at all in the future? As somebody mentioned earlier, not all partners use the ACE or the Spring Boot implementation provided by Atlassian and such changes only add more to the pile of things we have to consider.

5 Likes

In ACE I have the install hook:

app.post("/installed", function(req, res, next) {

Do I need to check authentication now?

app.post("/installed", addon.authenticate(), function(req, res, next) {

@HanjooSong
When we use

  "validateDescriptor": true,

in atlassian-connect.json in ACE, we get the warning:

Error validating app descriptor: [[
  {
    "type": "warning",
    "message": "Unexpected attributes: The descriptor is valid, but double-check for typos and elements in the wrong place",
    "validationResults": [
      {
        "module": "Root",
        "description": "additionalProperty \"signed-install\" exists in instance when not allowed"
      }
    ]
  }
]] . Please check and resolve the problem/s. The app will still continue to run but there might be problems installing this

Can you check the validator?

EDIT: It seems in your first post you write we should change the app descriptor:

However in the ACE repository, it shows that config.json is changed. Can you clarify?

Hi @remie ,

I believe the caching of public key was discussed in another post was discussed in another topic, but let me just reiterate here that mentioning it in the post was probably a mistake from our side. The CDN should be very reliable, the same CDN is used for the frontend assets of the actual products so if the CDN is down the products themselves will be broken and nobody will be able to install apps anyways.

Apologies in advance as this is going to be a long reply. The TL/DR is that we actually have not decided not to expose a single shared secret on app management, the current signed install was introduced as a quick fix to provide better security while we move Connect over to our new internal platform.

There’s a couple of reasons why exposing the secret in is not as simple as it might seem. First of them is historical reasons. The Atlassian cloud was originally implemented as multiple independent virtual machines, which were completely separated from each other. In reality behind the scenes you don’t actually have a single app, every single installation of the app is completely separate and they just happen to share the same descriptor. We’re working on moving to a more centralized system, but it will take some time.

Another reason is that you can also install apps that are not listed on marketplace. If we wanted to have a solution for single shared it would also have to work for the apps that are not on marketplace, so it couldn’t be implemented there. We would have to use some other system, like the app management you use for 3LO and Forge apps in developer.atlassian.com. Again in order for this work we will need to move Connect apps to our new platform.

The good news is that moving Connect apps to the new platform is actually going to happen as part of the Connect-Forge harmonization project (more information here: Introducing alpha support for adding Forge to your existing Connect app). We are at the moment internally discussing how authentication should work for Connect apps that have moved over to the new platform (ie. harmonized) and also how Forge remote compute (a way for Forge apps to integrate with services running outside Atlassian infrastructure) should work. A single shared secret is definitely one of the options we are considering, at least for some subset of apps.

We’re likely to share some early thoughts around the topic with the vendors to get some feedback soon, and would be happy to include you in the discussion.

Let me know if you have any further questions around this.

4 Likes

Really appreciate the explanation.
At least for me it is important to know there are better concepts coming and accept this as a short term fix.
Would love to see more of these plans and challenges shared - especially for connect apps.

2 Likes

That goes back to my original question (which was not answered). CDNs work on caching. And every once in a while a node goes bad and starts serving back broken stuff. (Or depending on how you have things configured - if it caches the wrong thing at the wrong time). CDN usage for this seems also a bit odd to me since if you rotate a key - and the CDN is caching thing (which I’m assuming it is) - we’ll get a stale key…

So back to my question - what is the customer experience when we reject an installation because the key we have is not correct/available etc?

Also - (and I’m not trying to be a pain here) - is there actual monitoring (not integration testing) which is driving installation and uninstallation of apps outside of the Atlassian AWS infrastructure (that way you would be picking up on CDN funkiness)?

3 Likes

@HanjooSong / @ekaukonen We are currently testing the changes to the /uninstall lifecycle endpoint in an ACE add-on.
When we use

 app.post('/uninstalled', addon.authenticate(),
           asyncHandler(async function(req, res, next) {
             hlogger.info("uninstall called");
             console.log('headers', JSON.stringify(req.headers));
             console.log('req.context', req.context);
             let clientKey = req.context.clientKey;
             console.log('clientKey', clientKey);
             //....
             res.sendStatus(204);
           }));

We get:

::1 - - [23/Jun/2021:13:27:04 +0000] "POST /installed HTTP/1.1" 204 - "-" "Atlassian HttpClient unknown / Confluence-1000.0.0-9f44da3d8b62 (6452) / Atlassian-Connect/1.1013.0"
{} Authentication verification error (401):  Invalid JWT: Algorithm from the header "RS256" does not match
::1 - - [23/Jun/2021:13:27:18 +0000] "POST /uninstalled HTTP/1.1" 401 71 "-" "Atlassian HttpClient unknown / Confluence-1000.0.0-9f44da3d8b62 (6452) / Atlassian-Connect/1.1013.0"

So it seems the call to addon.authenticate() does not handle the new JWT?
What should we do to verify the uninstall lifecycle endpoint?

1 Like

Hi,
I am using spring connect v2.2.0 and I added the migration as :

"apiMigrations": {
    "context-qsh": true,
    "signed-install": true
  }

I used the following payload through Postman :

{
  "key": "abc",
  "clientKey": "123",
  "publicKey": "XYZ",
  "sharedSecret": "ABC",
  "serverVersion": "100157",
  "pluginsVersion": "1001.0.0.SNAPSHOT",
  "baseUrl": "https://test-test.atlassian.net",
  "productType": "jira",
  "description": "Atlassian JIRA at https://team-1600938579218.atlassian.net ",
  "eventType": "installed"
}

In the logs I see

021-06-23 16:49:44.250  INFO 10132 --- [nio-8080-exec-5] c.s.i.a.a.AsymmetricAuthenticationFilter : Failed to authenticate request due to missing asymmetric JWT token, falling back to unsigned install
2021-06-23 16:49:44.281  INFO 10132 --- [         task-6] c.a.c.s.i.lifecycle.LifecycleController  : Saved installation for host https://test-test.atlassian.net (123)

And I see the fake organization was added to the DB, which can lead to DoS attack on the DB.
Please advise

+1,
I also get this error when I try to install the plugin with ACSP version 2.2.0

1 Like

To answer my own question, you can secure the /uninstalled route with

addon.authenticateInstall(),

instead of addon.authenticate().
@HanjooSong Can we safely use addon.authenticateInstall()? It is not documented.

1 Like

Yes @marc, addon.authenticateInstall() was intended for custom install/uninstall callback authentication. I will add the missing documentation.

Hi, for ACE framework configuring "signed-install": "enabled" in the root of config.json file will be enough. You do not need to add them to the descriptor file. The validator error means that it might have been added to the descriptor file instead.

Hi @OfirNir, you can disable the legacy authentication in ACSB by setting below property.

atlassian.connect.fallback-install-hook-enabled=false

@HanjooSong ,
Setting atlassian.connect.allow-symmetric-auth-install-callback=false solved the payload issue,
However I can not migrate it to production yet since the exception

2021-06-24 09:54:27.729 ERROR 17584 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.IllegalArgumentException: Illegal base64 character a

Is still presented

Out of curiosity: we’ve been accepting non-signed install requests since 2013. Why would you invest time & resources of both Atlassian and vendors to implement a quick fix now knowing that you will migrate Connect within 12-18 months anyway?

Would love to participate, and I think there are many other vendors that actually have a lot of security/systems architecture knowledge that they can bring to the table.

2 Likes

I’ve been watching this discussion and I’ve got a few thoughts and concerns. All I’m really doing here is restating concerns that others have raised.

This feels like a sticking plaster implementation to fix a problem that we’ve been shouting about for about as long as Connect has existed. I’m pleased to see signed install and uninstall hooks but I feel that it would make much more sense to have it for all web hooks. We were promised the single shared secret and it never materialised. I now have a database of tenants where the vast majority have the same shared secret, but some don’t so i have to maintain an implementation that assumes that they are unique. What i’m getting at here is that trust that investment in Connect will continue is low to non-existent and this sticking plaster implementation will be carried on into the forever future unless an app jumps on the harmonisation path.

As Daniel points out this introduces a new failure point. I think that assuming that CDN is reliable everywhere in the world at the same time time is a nonsense. It would be quite possible for the CDN to be serving assets in the US (where the user is) but completely failing in Europe (where the app is running) for example. The error reporting back to users doesn’t have much detail and it can be hard to track down installation errors.

From a customer perspective, in all likelihood the majority of apps won’t update in-time for this change, which is probably fine (as initial install hooks were not expected to be verified) but may well break on uninstall and reinstall. It will be the apps that end up corrupt not Atlassian’s data but the shared customer will be impacted (if this is the case). If this announcement is the only communications of this breaking change then expect to find many apps caught out.

We would be more than happy to participate in any feedback sessions on auth and connect in general.

12 Likes