31
June 3-5, 2014 | Berlin, Germany

AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Embed Size (px)

DESCRIPTION

Atlassian provides two easy-to-use frameworks for getting a Connect add-on up and running quickly – atlassian-connect-express and ac-play. But what if these frameworks don't quite fit your bill? What does it mean to build a Connect add-on with your own stack? What components do you need to write? And how does it all fit together? Attending this talk will give you enough background information to implement an add-on in the language and technology stack of your choice.

Citation preview

Page 1: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

June 3-5, 2014 | Berlin, Germany

Page 2: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Patrick Streule, Architect, Atlassian

Build a Connect Add-on with Your Own Stack

Page 3: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Atlassian Connect Express: node.js/express

• Atlassian Connect Play: Java/Play

• ACE and AC-Play provide:

• Authentication handling (both directions)

• Lifecycle handling

• Persistence

ACE/AC-Play vs Your Own

Page 4: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• You have an existing service that will host the add-on

• Development in your company happens on a different stack

• Connect does not prescribe a stack at all

ACE/AC-Play vs Your Own

Page 5: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Overview

Page 6: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Product

Overview

WEBHOOKS

REST API

REST API

HTTP

Add-On

Page 7: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Serve descriptor and add-on UI ☑ Web server / web framework ☑ SSL certificate

Handle add-on installation ☑ Persistent store

Handle add-on requests ☑ JWT token handler ☑ Crypto library ☑ JSON and HttpClient libs

Checklist

Page 8: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

The Minimum Viable Add-On

Page 9: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Description of the Add-On

• Where does it show up?

• Where are the add-on endpoints?

• General Metadata

The Descriptor{!

"key": "atlas-camp",!

"name": "AtlasCamp",!

"baseUrl": “https://addon.example.com”,!

"authentication": {!

"type": "none"!

},!

"modules": {!

"generalPages": [!

{!

"url": "/intro.html",!

"key": "intro-page",!

"name": {!

"value": "Atlas Camp"!

}!

}!

]!

}!

}

Page 10: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

The Content<!DOCTYPE html>!

<html>!

<head>!

<title>Atlas Camp</title>!

<script src=“https://someinstance.jira.com/atlassian-connect/all.js”></script>!

! <style>body { text-align: center; padding-top: 50px; }</style>!

</head>!

<body>!

<div class=“ac-content”>!

<a href=“https://www.atlassian.com/atlascamp/2014">!

! <img src=“img/atlas-camp.png"/>!

</a>!

</div>!

</body>!

</html>

Page 11: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

The Result

Page 12: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• HTTPS in production, HTTP for development only

• Include all.js from the host:

The Important Bits

var hostBaseUrl = getUrlParameter("xdm_e");!

var contextPath = getUrlParameter("cp");!

loadScript(hostBaseUrl + contextPath + "/atlassian-connect/all.js");

Page 13: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Adding Authentication: Installation Event

Page 14: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Authentication type: JWT

• Installed Lifecycle hook is required.

• Will be called during installation

• Other hooks:

• Uninstalled, Enabled, Disabled

!

Setting it up{!

"key": "atlas-camp",!

"name": "AtlasCamp",!

"baseUrl": “https://addon.example.com”,!

"authentication": {!

"type": "jwt"!

},!

"lifecycle": {!

"installed": "/installed",!

"uninstalled": "/uninstalled"!

}!

}

Page 15: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Installation event• clientKey

Identifies the tenant

• sharedSecretThe key for signing and verifying JWT tokens

• baseUrlThe host and context path of the product

Page 16: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Adding Authentication: JWT

Page 17: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Authenticity

• Parties are who they claim to be

• Integrity

• The request was not tampered with

• Authorization (special case in Connect)

• User has access to the pages and issues referenced by URL parameters

JWT

Page 18: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

JWT: Anatomy of a token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MDEwODEwMzgsInN1YiI6ImZmODA4MTgxNDBjMDcyOWEwMTQwY2Q0NWE5MWQwMDBkIiwiaXNzIjoiQ29uZmx1ZW5jZTowNzA3MjM3MjM2IiwicXNoIjoiMjU5YzZkNjU1NjEwYzgyNzE3MDMxNWEwMTM1ZGI0OTAwODYxZjkxYzA5NDdlM2I2NjY2NjgyZTkzMDU1NWFiNCIsImlhdCI6MTQwMTA4MDg1OH0.iSmtl3ukm8EohrCwO94MF7sXeEFtIRQ-aBggghjlE0E

Page 19: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

JWT: Anatomy of a token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MDEwODEwMzgsInN1YiI6ImZmODA4MTgxNDBjMDcyOWEwMTQwY2Q0NWE5MWQwMDBkIiwiaXNzIjoiQ29uZmx1ZW5jZTowNzA3MjM3MjM2IiwicXNoIjoiMjU5YzZkNjU1NjEwYzgyNzE3MDMxNWEwMTM1ZGI0OTAwODYxZjkxYzA5NDdlM2I2NjY2NjgyZTkzMDU1NWFiNCIsImlhdCI6MTQwMTA4MDg1OH0.iSmtl3ukm8EohrCwO94MF7sXeEFtIRQ-aBggghjlE0E

Header

Payload, Claims

Signature

Page 20: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

JWT: Anatomy of a token

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MDEwODEwMzgsInN1YiI6ImZmODA4MTgxNDBjMDcyOWEwMTQwY2Q0NWE5MWQwMDBkIiwiaXNzIjoiQ29uZmx1ZW5jZTowNzA3MjM3MjM2IiwicXNoIjoiMjU5YzZkNjU1NjEwYzgyNzE3MDMxNWEwMTM1ZGI0OTAwODYxZjkxYzA5NDdlM2I2NjY2NjgyZTkzMDU1NWFiNCIsImlhdCI6MTQwMTA4MDg1OH0.iSmtl3ukm8EohrCwO94MF7sXeEFtIRQ-aBggghjlE0E

{"alg":"HS256","typ":"JWT"}

{! "exp": 1401081038,! "sub": “ff808…d000d”,! "iss": "Confluence:070789",! "qsh": “259c6…55ab4”,! "iat": 1401080858!}

HMAC using SHA-256

Expires at

Subject

Issuer

Query String Hash Issued

at

BTW: Never rely on this prefix!

Page 21: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

JWT Verification: Step 1base64url(sign(‘eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MDEwODEwMzgsInN1YiI6ImZmODA4MTgxNDBjMDcyOWEwMTQwY2Q0NWE5MWQwMDBkIiwiaXNzIjoiQ29uZmx1ZW5jZTowNzA3MjM3MjM2IiwicXNoIjoiMjU5YzZkNjU1NjEwYzgyNzE3MDMxNWEwMTM1ZGI0OTAwODYxZjkxYzA5NDdlM2I2NjY2NjgyZTkzMDU1NWFiNCIsImlhdCI6MTQwMTA4MDg1OH0’, header.alg, tenants[claims.iss].sharedSecret))!!== iSmtl3ukm8EohrCwO94MF7sXeEFtIRQ-aBggghjlE0E ?

Page 22: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

JWT Verification: Step 2

a=5,7&lic=none&page.id=19809&user_id=pstreule

{! "baseUrl": “https://addon.example.com/base”,…!}

GET /base/render?page.id=19809&a=7&a=5&user_id=pstreule&lic=none&jwt=eY…

"qsh": “259c6…55ab4”

hex(sha256(‘GET&…’))

remove context path remove ‘jwt’, order keys and values, apply OAuth1 encoding rulesuppercase

/renderGET &&

Page 23: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Characters in the unreserved character set MUST NOT be encoded: (ALPHA, DIGIT, "-", ".", "_", "~")

• All other characters MUST be encoded

• The two hexadecimal characters used to represent encoded characters MUST be uppercase.

Pitfalls

Raw Encoded

SPACE %20

* %2A

! %21

' %27

( %28

) %29

Page 24: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• JWT tokens used on incoming and outgoing requests

• URL Parameter: jwt=eY…

• HTTP header: Authorization: JWT eY…

• Find more information

• http://go.atlassian.com/ac-docs

• http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html

JWT Summary

Page 25: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Adding Authentication: Add-On to Add-On

Page 26: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Do not use session cookies

• Cookies set by the iframe are third-party cookies

• Many browsers don’t accept them by default

Pitfalls

Page 27: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• How to handle authentication for intra-add-on Ajax calls and links.

Your own requests

Page 28: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

• Create a JWT token for the tenant and user

• QSH is optional, depending on the parameter data

Reuse JWT

{! "exp": 1401081038,! "sub": “ff808…d000d”,! "iss": "Confluence:070789",! "iat": 1401080858!}

Page 29: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Dev Speed

Page 30: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

Quick descriptor deploymentcurl -i -X HEAD -u admin:admin http://localhost:2990/jira/rest/plugins/1.0/

HTTP/1.1 200 OK!upm-token: 7864481825707347853

curl -i -X POST -u admin:admin ! -H "Content-type: application/vnd.atl.plugins.remote.install+json" -d '{"pluginUri":"http://localhost:3000/atlassian-connect.json"}'! http://localhost:2990/jira/rest/plugins/1.0/?token=7864481825707347853

Page 31: AtlasCamp 2014: Building a Connect Add-on With Your Own Stack

We’re here to helphttp://go.atlassian.com/ac-dev