JIRA-Atlassian-Connect-App-Django
Tag: Ruby
Tag: Rails
Category: jekyll
Category: update
Category: git
Category: database
Category: PostgreSQL
Category: websocket
Category: ruby
Category: projects
Category: Redis
Category: mysql
Category: Mac
Category: Node
Category: NPM
Category: PM2
Category: nodejs
Category: Meteor
Category: Nginx
Category: gitLab
Category: Rails
- Why Ruby on Rails is better than Python Django?
- How to use Hotwire turbo in Rails 6 with Webpacker?
- Rails 6 Credentials (master.key and credentials.yml.enc)
- Rails Console
- JIRA-Atlassian-Connect-App-Django
- Rails 4 5.0 Session Cookie AuthenticityToken
- Rails Active Storage
- Rails 5 Source code Research
- 微信支付
- Rails零星笔记
Category: Homebrew
Category: CentOS
Category: FreeSwitch
Category: Ruby
- Ruby on Rails 8
- RESTful API
- Ruby on Rails 7
- Study from Ruby official website
- Ruby-Metaprogramming
- Ruby连数据库的问题
- rbenv使用
Category: Vim
Category: javascript
Category: React-Native
Category: Wechat
Category: homeland
Category: JavaScript
Category: Docker
Category: RubyMine
Category: Authorization
Category: RESTful-API
Category: Proxy
Category: Deploy
Category: Devise
Category: Bootstrap
Category: Active_Storage
Category: github
Category: Android
Category: cloud
Category: ssh
Category: python
Category: reactjs
Category: markdown
Category: ShadowSocks
Category: Code
Category: rails
Category: code
Category: Django
Category: Python
Category: DRF
Category: Fish
Category: Yarn
Category: Material-UI
Category: CSS
Category: aws
Category: uwsgi
Category: nginx
Category: docker
Category: React
Category: Enzyme
Category: Jira
Category: Interview
Category: JetBrain
Category: PyCharm
Category: ESLint
Category: Rails6
Category: NVM
Category: ssl
Category: tencent
Category: CI
Category: jenkins
Category: GitHub
Category: Credentials
Category: master.key
Category: Webpacker
Category: Turbo
Category: Hotwire
Category: Bootstrap5
Category: Flutter
Category: Clash
Category: Tor
Category: proxy
Category: Build
Category: SwitchyOmega
Category: Chrome-extension
Category: SQLAlchemy
Category: Algorithm
Category: Rails7
Category: Data
Category: Structure
Category: CPP
Category: Languages
Category: Golang
Category: Typescript
Category: Rails 8
Django
For Atlassian connect app, we would better use Django instead of Django rest framework.
Our first step is to build a local Django app server as a Atlassian connect app and install it.
Django app server as a Atlassian connect app
So please create a Django app (it was named as jira_app
for this example) first.
base_settings.py
```python ROOT_DIR = environ.Path(file) - 3
TEMPLATES = [ { ‘DIRS’: [os.path.join(ROOT_DIR, ‘jira_app’, ‘templates’)], } ]
ATLASSIAN_CONNECT_BASE_URL = env(‘ATLASSIAN_CONNECT_BASE_URL’)
* `mysite/urls.py`
```python
urlpatterns = [
path('jira/', include('jira_app.urls')),
]
jira_app/views.py
```python from django.conf import settings from django.http import JsonResponse from django.shortcuts import render from django.views.decorators.clickjacking import xframe_options_exempt
def atlassian_connect(request): base_url = settings.ATLASSIAN_CONNECT_BASE_URL name = f”my jira test {None if settings.ENVIRONMENT == ‘prod’ else ‘ ‘ + settings.ENVIRONMENT}”
return JsonResponse({
'baseUrl': base_url,
'key': f'my jira test-app-{settings.ENVIRONMENT}',
'authentication': {
'type': 'none'
},
'name': name,
'description': f'my jira test {settings.ENVIRONMENT}',
'links': {
'self': f'{base_url}/jira/atlassian-connect.json'
},
'scopes': [
'read',
'write'
],
'apiVersion': 1,
'modules': {
'generalPages': [
{
'url': '/jira/hello.html',
'key': 'hello',
'location': 'system.top.navigation.bar',
'name': {
'value': 'hello'
}
}
]
}
})
@xframe_options_exempt def hello(request): return render(request, ‘jira_app/hello.html’)
* `jira_app/urls.py`
```python
from django.urls import path
from . import views
urlpatterns = [
path('atlassian-connect.json', views.atlassian_connect, name='atlassian-connect'),
path('hello.html', views.hello, name='hello'),
]
jira_app/templates/jira_app/hello.html
```html <!DOCTYPE html>
Hello
## Install this app in Jira
Visit https://your-project.atlassian.net/secure/BrowseProjects.jspa
Then click `Apps -> Manage your apps`.
Then click `upload app` (should click `Settings -> Enable development mode` first).
Then input `From this URL` with the Ngrok url of your app like `https://544119900028.ngrok.io/jira/atlassian-connect.json`.
# JWT
## Get the install json and sharedSecret
```python
import json
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def installed(request):
print('======== request.body: ', request.body)
body = json.loads(request.body)
sharedSecret = body['sharedSecret']
print('======== sharedSecret: ', sharedSecret)
return HttpResponse("You posted to /jira/installed.")
This is what I get from request.body
when installing an app:
{
"key": "some-app",
"clientKey": "d388d673-a684-3f88-a3e1-7646d7a27058",
"publicKey": "MIGfMA0GCSq4SIb3DQEBAQUAA4GNADCBiQKBgQC4MfoLPnyiKXPeGR+PD+Qj1Puyzi/jRInJShzfu89mQddLpoIS8SjAmzETCfH86MtHUI4BmP7qgUEIXuHggSyd6Okpi1X4v/W+zYjCzrl5uWql88qbKksHhoovbjcZtVCE/4zUSJ7s8smyW7Xc80KhAFlhqbesbwOQhbvQdLk9uQIDAQAf",
"sharedSecret": "WkvYYm5PawgaOgt6hFacPOTFZrRlk/8pZWmZi8TgnW9irP4HRVuACocB6b7+rlKTemgyJlZP3sdCd5RTlSDrdg",
"serverVersion": "100150",
"pluginsVersion": "1001.0.0.SNAPSHOT",
"baseUrl": "https://some-domain.atlassian.net",
"productType": "jira",
"description": "Atlassian JIRA at https://team-1605254797493.atlassian.net ",
"eventType": "installed"
}
Other
- I guess an connect app can be installed in many clients (different from the
subdomain
name).
For example Like:
https://some-subdomain.atlassian.net/secure/BrowseProjects.jspa?selectedProjectType=software
https://other-people-subdomain.atlassian.net/secure/BrowseProjects.jspa?selectedProjectType=software
The install callback
will be invoked when a some-subdomain.atlassian.net
admin installs your app.
https://developer.atlassian.com/cloud/jira/platform/security-for-connect-apps/#signed-installation-callback-requests
So the sharedSecret
of all the users under the same some-subdomain.atlassian.net
will be always the same.
Use https://github.com/jpadilla/pyjwt to decode.
- Once user uninstalled an app and reinstall again, in the
install
callback, theAuthorization
will be in theheaders
and thesharedSecret
will still be the old one to ensure that our Python code could decode it.
But by body = json.loads(request.body); sharedSecret = body['sharedSecret']
, you can get a new sharedSecret
.
And the old sharedSecret
which you have just used will become stale in the future.
So you have to update the sharedSecret
for this client.
-
According to https://blog.developer.atlassian.com/understanding-jwt/ , the
clientKey
distinguished the client (e.g:your-subdomain.atlassian.net
has clientKeyd388d675-a684-3f88-a3e1-7646d8227059
his-subdomain.atlassian.net
has clientKey932fb277-c58c-3b4b-aae4-03634313c7bf
) -
At this moment, I think you may want to save the
clientKey
and thesharedSecret
into database.
Then, when a request arrives, you can decode it with sharedSecret
. But which sharedSecret
should you use?
The tip is that in every request, there is a parameter xdm_e': 'https://thegreatworld.atlassian.net'
which is the same as the baseUrl
in installation request json
we can use to determine which clientKey
is because we will save records in databases like:
your-subdomain.atlassian.net d388d675-a684-3f88-a3e1-7646d8227059 sharedSecret1345
his-subdomain.atlassian.net 932fb277-c58c-3b4b-aae4-03634313c7bf sharedSecret2824
...
https://pypi.org/project/atlassian-jwt/