atlassian-jwt 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 95822a295a203005eef8ab806c8271e186e79e60
4
+ data.tar.gz: d86ec07e14e5ac7b4e1328b94026e38f84520e95
5
+ SHA512:
6
+ metadata.gz: 5ca63e222c259304cbfd59a9bdc93c7748afbfe7f99ccff349044a64ce28625e5c2fbb95329db43803118613e211d350e8e508942f3bc4daf4ed9ee5a9d67826
7
+ data.tar.gz: a7596769f75d9f03d904c47fbb75ef5db2080b5ead8a395b26d5289f2be4e2e574a2b4cccba6b69d9352aa245eb5c42a33db2c72fc640d9b06bb9868477454ae
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.ruby-*
11
+ /atlassian-jwt-*.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in atlassian-jwt.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # Atlassian::Jwt
2
+
3
+ This gem provides helpers for generating Atlassian specific JWT
4
+ claims. It also exposes the [ruby-jwt](https://github.com/jwt/ruby-jwt)
5
+ gem's `encode` and `decode` methods.
6
+
7
+ [![build-status](https://bitbucket-badges.useast.atlassian.io/badge/atlassian/atlassian-jwt-ruby.svg)](https://bitbucket.org/atlassian/atlassian-jwt-ruby/addon/pipelines/home)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'atlassian-jwt'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install atlassian-jwt
24
+
25
+ ## Usage
26
+
27
+ In order to access the
28
+ [Atlassian Connect REST APIs](https://developer.atlassian.com/static/connect/docs/latest/rest-apis/)
29
+ an add-on authenticates using a JSON Web Token (JWT). The token is
30
+ generated using the add-on's secret key and contains a *claim* which
31
+ includes the add-on's key and a hashed version of the API URL the
32
+ add-on is accessing. This gem simplifies generating the claim.
33
+
34
+ ### Generating a JWT Token
35
+
36
+ ```ruby
37
+ require 'atlassian/jwt'
38
+
39
+ # The URL of the API call, must include the query string, if any
40
+ url = 'https://jira.atlassian.com/rest/api/latest/issue/JRA-9'
41
+ # The key of the add-on as defined in the add-on description
42
+ issuer = 'com.atlassian.example'
43
+ http_method = 'get' # The HTTP Method (GET, POST, etc) of the API call
44
+ shared_secret = '...' # "sharedSecret", returned when the add-on is installed.
45
+
46
+ claim = Atlassian::Jwt.build_claims(issuer,url,http_method)
47
+ jwt = JWT.encode(claim,shared_secret)
48
+ ```
49
+
50
+ If the base URL of the API is not at the root of the site,
51
+ i.e. *https://site.atlassian.net/jira/rest/api*, you will need to pass
52
+ in the base URL to `#.build_claims`:
53
+
54
+ ```
55
+ url = 'https://site.atlassian.net/jira/rest/api/latest/issue/JRA-9'
56
+ base_url = 'https://site.atlassian.net'
57
+
58
+ claim = Atlassian::Jwt.build_claims(issuer, url, http_method, base_url)
59
+ ```
60
+
61
+ The generated JWT can then be passed in an 'Authentication' header or
62
+ in the query string:
63
+
64
+ ```ruby
65
+ # Header
66
+ uri = URI('https://site.atlassian.net/rest/api/latest/issue/JRA-9')
67
+ http = Net::HTTP.new(uri.host, uri.port)
68
+ request = Net::HTTP::Get.new(uri.request_uri)
69
+ request.initialize_http_header({'Authentication' => "JWT #{jwt}"})
70
+ response = http.request(request)
71
+ ```
72
+
73
+ ```ruby
74
+ # Query String
75
+ uri = URI("https://site.atlassian.net/rest/api/latest/issue/JRA-9?jwt=#{jwt}")
76
+ http = Net::HTTP.new(uri.host, uri.port)
77
+ request = Net::HTTP::Get.new(uri.request_uri)
78
+ response = http.request(request)
79
+ ```
80
+
81
+ By default the issue time of the claim is now and the expiration is 60
82
+ seconds in the future, these can be overridden:
83
+
84
+ ```ruby
85
+ claim = Atlassian::Jwt.build_claims(
86
+ issuer,
87
+ url,
88
+ http_method,
89
+ base_url,
90
+ Time.now - 60.seconds
91
+ Time.now + 1.day
92
+ )
93
+ ```
94
+
95
+ ### Decoding a JWT token
96
+
97
+ The JWT from the server is usually returned a param. The underlying
98
+ Ruby JWT gem returns an array with the first element being the claim
99
+ and the second being the JWT header, which contains information about
100
+ how the JWT was encoded.
101
+
102
+ ```ruby
103
+ claims, jwt_header = Atlassian::Jwt.decode(params[:jwt], shared_secret)
104
+ ```
105
+
106
+ By default, the JWT gem verifies that the JWT is properly signed with
107
+ the shared secret and raises an error if it's not. However, sometimes
108
+ is necessary to read the JWT first to determine which shared secret is
109
+ needed. In this case, use nil for the shared secret and follow it with
110
+ `false` to tell the gem to to verify the signature.
111
+
112
+ ```ruby
113
+ claims, jwt_header = Atlassian::Jwt.decode(params[:jwt], nil, false)
114
+ ```
115
+
116
+ See the [ruby-jwt doc](https://github.com/jwt/ruby-jwt) for additional
117
+ details.
118
+
119
+ ## Development
120
+
121
+ After checking out the repo, run `bin/setup` to install dependencies. Then,
122
+ run `rake spec` to run the tests. You can also run `bin/console` for an
123
+ interactive prompt that will allow you to experiment.
124
+
125
+ To install this gem onto your local machine, run `bundle exec rake install`.
126
+ To release a new version, update the version number in `version.rb`, and
127
+ then run `bundle exec rake release`, which will create a git tag for the
128
+ version, push git commits and tags, and push the `.gem` file to
129
+ [rubygems.org](https://rubygems.org).
130
+
131
+ ## Contributing
132
+
133
+ Bug reports and pull requests are welcome on Bitbucket at
134
+ https://bitbucket.org/atlassian/atlassian-jwt-ruby.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'atlassian/jwt/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "atlassian-jwt"
8
+ spec.version = Atlassian::Jwt::VERSION
9
+ spec.authors = ["Spike Ilacqua", "Seb Ruiz"]
10
+ spec.email = ["spike@6kites.com", "sruiz@atlassian.com"]
11
+
12
+ spec.summary = %q{Encode and decode JWT tokens for use with the Atlassian Connect REST APIs.}
13
+ spec.description = %q{This gem simplifies generating the claims need to authenticate with the Atlassian Connect REST APIs.}
14
+ spec.homepage = "https://bitbucket.org/atlassian/atlassian-jwt-ruby"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency 'jwt', '~> 1.5'
22
+ spec.add_development_dependency 'json', '~> 1.8'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.11"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "atlassian/jwt"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,14 @@
1
+ # This is a sample build configuration for Ruby.
2
+ # Only use spaces to indent your .yml configuration.
3
+ # -----
4
+ # You can specify a custom docker image from Dockerhub as your build environment.
5
+ image: ruby:2.3.0
6
+
7
+ pipelines:
8
+ default:
9
+ - step:
10
+ script: # Modify the commands below to build your repository.
11
+ - ruby --version
12
+ - bundler --version
13
+ - bundle install
14
+ - rake
@@ -0,0 +1,76 @@
1
+ require 'atlassian/jwt/version'
2
+ require 'jwt'
3
+ require 'uri'
4
+ require 'cgi'
5
+
6
+ module Atlassian
7
+ module Jwt
8
+ class << self
9
+ CANONICAL_QUERY_SEPARATOR = '&'
10
+ ESCAPED_CANONICAL_QUERY_SEPARATOR = '%26'
11
+
12
+ def decode(token,secret, validate = true, options = {})
13
+ options = { :algorithm => 'HS256' }.merge(options)
14
+ ::JWT.decode token, secret, validate, options
15
+ end
16
+
17
+ def encode(payload, secret, algorithm = 'HS256', header_fields = {})
18
+ ::JWT.encode payload, secret, algorithm, header_fields
19
+ end
20
+
21
+ def create_query_string_hash(uri, http_method, base_uri)
22
+ Digest::SHA256.hexdigest(
23
+ create_canonical_request(uri, http_method, base_uri)
24
+ )
25
+ end
26
+
27
+ def create_canonical_request(uri, http_method, base_uri)
28
+ uri = URI.parse(uri) unless uri.kind_of? URI
29
+ base_uri = URI.parse(base_uri) unless base_uri.kind_of? URI
30
+
31
+ path = canonicalize_uri(uri, base_uri)
32
+
33
+ [http_method.upcase,
34
+ canonicalize_uri(uri, base_uri),
35
+ canonicalize_query_string(uri.query)
36
+ ].join(CANONICAL_QUERY_SEPARATOR)
37
+ end
38
+
39
+ def build_claims(issuer,url,http_method,base_url='',issued_at=nil,expires=nil,attributes={})
40
+ issued_at ||= Time.now.to_i
41
+ expires ||= issued_at + 60
42
+ qsh = Digest::SHA256.hexdigest(
43
+ Atlassian::Jwt.create_canonical_request(url,http_method,base_url)
44
+ )
45
+
46
+ {
47
+ iss: issuer,
48
+ iat: issued_at,
49
+ exp: expires,
50
+ qsh: qsh
51
+ }.merge(attributes)
52
+ end
53
+
54
+ def canonicalize_uri(uri, base_uri)
55
+ path = uri.path.sub(/^#{base_uri.path}/,'')
56
+ path = '/' if path.nil? || path.empty?
57
+ path = '/' + path unless path.start_with? '/'
58
+ path.chomp!('/') if path.length > 1
59
+ path.gsub(CANONICAL_QUERY_SEPARATOR, ESCAPED_CANONICAL_QUERY_SEPARATOR)
60
+ end
61
+
62
+ def canonicalize_query_string(query)
63
+ return '' if query.nil? || query.empty?
64
+ query = CGI::parse(query)
65
+ query.delete('jwt')
66
+ query.each do |k, v|
67
+ query[k] = v.map {|a| CGI.escape a }.join(',') if v.is_a? Array
68
+ query[k].gsub!('+','%20') # Use %20, not CGI.escape default of "+"
69
+ query[k].gsub!('%7E','~') # Unescape "~" per JS tests
70
+ end
71
+ query = Hash[query.sort]
72
+ query.map {|k,v| "#{CGI.escape k}=#{v}" }.join('&')
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ module Atlassian
2
+ module Jwt
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: atlassian-jwt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Spike Ilacqua
8
+ - Seb Ruiz
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2016-08-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: jwt
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: '1.5'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: '1.5'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '1.8'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '1.8'
42
+ - !ruby/object:Gem::Dependency
43
+ name: bundler
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: '1.11'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.11'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '10.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '10.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '3.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '3.0'
84
+ description: This gem simplifies generating the claims need to authenticate with the
85
+ Atlassian Connect REST APIs.
86
+ email:
87
+ - spike@6kites.com
88
+ - sruiz@atlassian.com
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - .gitignore
94
+ - .rspec
95
+ - Gemfile
96
+ - README.md
97
+ - Rakefile
98
+ - atlassian-jwt.gemspec
99
+ - bin/console
100
+ - bin/setup
101
+ - bitbucket-pipelines.yml
102
+ - lib/atlassian/jwt.rb
103
+ - lib/atlassian/jwt/version.rb
104
+ homepage: https://bitbucket.org/atlassian/atlassian-jwt-ruby
105
+ licenses: []
106
+ metadata: {}
107
+ post_install_message:
108
+ rdoc_options: []
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 2.0.14.1
124
+ signing_key:
125
+ specification_version: 4
126
+ summary: Encode and decode JWT tokens for use with the Atlassian Connect REST APIs.
127
+ test_files: []