jira-ruby 1.6.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +3 -2
- data/README.md +40 -11
- data/Rakefile +2 -2
- data/example.rb +8 -0
- data/jira-ruby.gemspec +1 -2
- data/lib/jira/base.rb +1 -1
- data/lib/jira/client.rb +85 -12
- data/lib/jira/http_client.rb +29 -13
- data/lib/jira/http_error.rb +1 -1
- data/lib/jira/jwt_client.rb +67 -0
- data/lib/jira/oauth_client.rb +18 -6
- data/lib/jira/request_client.rb +15 -3
- data/lib/jira/resource/attachment.rb +19 -14
- data/lib/jira/resource/board.rb +8 -1
- data/lib/jira/resource/board_configuration.rb +9 -0
- data/lib/jira/resource/issue_picker_suggestions.rb +24 -0
- data/lib/jira/resource/issue_picker_suggestions_issue.rb +10 -0
- data/lib/jira/resource/sprint.rb +12 -8
- data/lib/jira/resource/suggested_issue.rb +9 -0
- data/lib/jira/resource/user.rb +1 -1
- data/lib/jira/resource/watcher.rb +7 -0
- data/lib/jira/version.rb +1 -1
- data/lib/jira-ruby.rb +6 -0
- data/spec/integration/user_spec.rb +3 -3
- data/spec/integration/watcher_spec.rb +15 -6
- data/spec/jira/base_spec.rb +12 -0
- data/spec/jira/client_spec.rb +70 -0
- data/spec/jira/http_client_spec.rb +137 -8
- data/spec/jira/jwt_uri_builder_spec.rb +59 -0
- data/spec/jira/oauth_client_spec.rb +47 -10
- data/spec/jira/request_client_spec.rb +37 -10
- data/spec/jira/resource/attachment_spec.rb +79 -22
- data/spec/jira/resource/board_spec.rb +50 -1
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +79 -0
- data/spec/jira/resource/issue_spec.rb +1 -1
- data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +18 -0
- data/spec/jira/resource/sprint_spec.rb +23 -11
- metadata +32 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 113ad755633d6eb87e63d7a97d3228f6649828547c01dee1ae1900ef0d575e2d
|
4
|
+
data.tar.gz: d59620f52976814ee7db58df10213bdb512f042a8b8214789ed07288f2899b65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e523698732b5cef8a220259ccf5c42c568ac7eea435ee2ed2f2018cdd25959597d23337a67fac037e00be85a8838d9d32a2c79a156da008380699d2c9529cb03
|
7
|
+
data.tar.gz: cefe63455cb070951d73420dc1144b0c0a4651836427f507d218d3eb0780936e6a740842f6f2df8f68b14be8034bb196b4f5069d21ac0c3cd9e2a4292e43b456
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -50,7 +50,7 @@ rake jira:generate_public_cert
|
|
50
50
|
|
51
51
|
On Mac OS,
|
52
52
|
|
53
|
-
* Follow the instructions under "Mac OSX Installer" here: https://developer.atlassian.com/
|
53
|
+
* Follow the instructions under "Mac OSX Installer" here: https://developer.atlassian.com/server/framework/atlassian-sdk/install-the-atlassian-sdk-on-a-linux-or-mac-system
|
54
54
|
* From within the archive directory, run:
|
55
55
|
|
56
56
|
```shell
|
@@ -99,7 +99,7 @@ defaults to HTTP Basic Auth.
|
|
99
99
|
|
100
100
|
Jira supports cookie based authentication whereby user credentials are passed
|
101
101
|
to JIRA via a JIRA REST API call. This call returns a session cookie which must
|
102
|
-
then be sent to all following JIRA REST API calls.
|
102
|
+
then be sent to all following JIRA REST API calls.
|
103
103
|
|
104
104
|
To enable cookie based authentication, set `:auth_type` to `:cookie`,
|
105
105
|
set `:use_cookies` to `true` and set `:username` and `:password` accordingly.
|
@@ -114,7 +114,7 @@ options = {
|
|
114
114
|
:context_path => '',
|
115
115
|
:auth_type => :cookie, # Set cookie based authentication
|
116
116
|
:use_cookies => true, # Send cookies with each request
|
117
|
-
:additional_cookies => ['AUTH=vV7uzixt0SScJKg7'] # Optional cookies to send
|
117
|
+
:additional_cookies => ['AUTH=vV7uzixt0SScJKg7'] # Optional cookies to send
|
118
118
|
# with each request
|
119
119
|
}
|
120
120
|
|
@@ -134,15 +134,40 @@ cookie to add to the request.
|
|
134
134
|
|
135
135
|
Some authentication schemes that require additional cookies ignore the username
|
136
136
|
and password sent in the JIRA REST API call. For those use cases, `:username`
|
137
|
-
and `:password` may be omitted from `options`.
|
137
|
+
and `:password` may be omitted from `options`.
|
138
138
|
|
139
|
+
## Configuring JIRA to use Personal Access Tokens Auth
|
140
|
+
If your JIRA system is configured to support Personal Access Token authorization, minor modifications are needed in how credentials are communicated to the server. Specifically, the paremeters `:username` and `:password` are not needed. Also, the parameter `:default_headers` is needed to contain the api_token, which can be obtained following the official documentation from [Atlassian](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html). Please note that the Personal Access Token can only be used as it is. If it is encoded (with base64 or any other encoding method) then the token will not work correctly and authentication will fail.
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
require 'jira-ruby'
|
144
|
+
|
145
|
+
# NOTE: the token should not be encoded
|
146
|
+
api_token = API_TOKEN_OBTAINED_FROM_JIRA_UI
|
147
|
+
|
148
|
+
options = {
|
149
|
+
:site => 'http://mydomain.atlassian.net:443/',
|
150
|
+
:context_path => '',
|
151
|
+
:username => '<the email you sign-in to Jira>',
|
152
|
+
:password => api_token,
|
153
|
+
:auth_type => :basic
|
154
|
+
}
|
155
|
+
|
156
|
+
client = JIRA::Client.new(options)
|
157
|
+
|
158
|
+
project = client.Project.find('SAMPLEPROJECT')
|
159
|
+
|
160
|
+
project.issues.each do |issue|
|
161
|
+
puts "#{issue.id} - #{issue.summary}"
|
162
|
+
end
|
163
|
+
```
|
139
164
|
## Using the API Gem in a command line application
|
140
165
|
|
141
166
|
Using HTTP Basic Authentication, configure and connect a client to your instance
|
142
167
|
of JIRA.
|
143
168
|
|
144
169
|
Note: If your Jira install is hosted on [atlassian.net](atlassian.net), it will have no context
|
145
|
-
path by default. If you're having issues connecting, try setting context_path
|
170
|
+
path by default. If you're having issues connecting, try setting context_path
|
146
171
|
to an empty string in the options hash.
|
147
172
|
|
148
173
|
```ruby
|
@@ -153,14 +178,18 @@ require 'jira-ruby'
|
|
153
178
|
# Consider the use of :use_ssl and :ssl_verify_mode options if running locally
|
154
179
|
# for tests.
|
155
180
|
|
181
|
+
# NOTE basic auth no longer works with Jira, you must generate an API token, to do so you must have jira instance access rights. You can generate a token here: https://id.atlassian.com/manage/api-tokens
|
182
|
+
|
183
|
+
# You will see JIRA::HTTPError (JIRA::HTTPError) if you attempt to use basic auth with your user's password
|
184
|
+
|
156
185
|
username = "myremoteuser"
|
157
|
-
|
186
|
+
api_token = "myApiToken"
|
158
187
|
|
159
188
|
options = {
|
160
189
|
:username => username,
|
161
|
-
:password =>
|
162
|
-
:site => 'http://localhost:8080/',
|
163
|
-
:context_path => '/myjira',
|
190
|
+
:password => api_token,
|
191
|
+
:site => 'http://localhost:8080/', # or 'https://<your_subdomain>.atlassian.net/'
|
192
|
+
:context_path => '/myjira', # often blank
|
164
193
|
:auth_type => :basic,
|
165
194
|
:read_timeout => 120
|
166
195
|
}
|
@@ -303,7 +332,7 @@ class App < Sinatra::Base
|
|
303
332
|
# site uri, and the request token, access token, and authorize paths
|
304
333
|
before do
|
305
334
|
options = {
|
306
|
-
:site => 'http://localhost:2990',
|
335
|
+
:site => 'http://localhost:2990/',
|
307
336
|
:context_path => '/jira',
|
308
337
|
:signature_method => 'RSA-SHA1',
|
309
338
|
:request_token_path => "/plugins/servlet/oauth/request-token",
|
@@ -401,7 +430,7 @@ require 'pp'
|
|
401
430
|
require 'jira-ruby'
|
402
431
|
|
403
432
|
options = {
|
404
|
-
:site => 'http://localhost:2990',
|
433
|
+
:site => 'http://localhost:2990/',
|
405
434
|
:context_path => '/jira',
|
406
435
|
:signature_method => 'RSA-SHA1',
|
407
436
|
:private_key_file => "rsakey.pem",
|
data/Rakefile
CHANGED
@@ -14,13 +14,13 @@ desc 'Prepare and run rspec tests'
|
|
14
14
|
task :prepare do
|
15
15
|
rsa_key = File.expand_path('rsakey.pem')
|
16
16
|
unless File.exist?(rsa_key)
|
17
|
-
|
17
|
+
Rake::Task['jira:generate_public_cert'].invoke
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
desc 'Run RSpec tests'
|
22
22
|
# RSpec::Core::RakeTask.new(:spec)
|
23
|
-
RSpec::Core::RakeTask.new(:spec) do |task|
|
23
|
+
RSpec::Core::RakeTask.new(:spec, [] => [:prepare]) do |task|
|
24
24
|
task.rspec_opts = ['--color', '--format', 'doc']
|
25
25
|
end
|
26
26
|
|
data/example.rb
CHANGED
@@ -166,6 +166,14 @@ client.Issue.jql(a_normal_jql_search, max_results: 500)
|
|
166
166
|
# # --------------------------
|
167
167
|
# issue.comments.first.save({"body" => "an updated comment frome example.rb"})
|
168
168
|
|
169
|
+
|
170
|
+
# # Add attachment to Issue
|
171
|
+
# # ------------------------
|
172
|
+
# issue = client.Issue.find('PROJ-1')
|
173
|
+
# attachment = issue.attachments.build
|
174
|
+
# attachment.save('file': '/path/to/file')
|
175
|
+
#
|
176
|
+
|
169
177
|
# List all available link types
|
170
178
|
# ------------------------------
|
171
179
|
pp client.Issuelinktype.all
|
data/jira-ruby.gemspec
CHANGED
@@ -13,8 +13,6 @@ Gem::Specification.new do |s|
|
|
13
13
|
|
14
14
|
s.required_ruby_version = '>= 1.9.3'
|
15
15
|
|
16
|
-
s.rubyforge_project = 'jira-ruby'
|
17
|
-
|
18
16
|
s.files = `git ls-files`.split("\n")
|
19
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
@@ -22,6 +20,7 @@ Gem::Specification.new do |s|
|
|
22
20
|
|
23
21
|
# Runtime Dependencies
|
24
22
|
s.add_runtime_dependency 'activesupport'
|
23
|
+
s.add_runtime_dependency 'atlassian-jwt'
|
25
24
|
s.add_runtime_dependency 'multipart-post'
|
26
25
|
s.add_runtime_dependency 'oauth', '~> 0.5', '>= 0.5.0'
|
27
26
|
|
data/lib/jira/base.rb
CHANGED
@@ -424,7 +424,7 @@ module JIRA
|
|
424
424
|
end
|
425
425
|
if @attrs['self']
|
426
426
|
the_url = @attrs['self']
|
427
|
-
the_url = the_url.sub(@client.options[:site], '') if @client.options[:site]
|
427
|
+
the_url = the_url.sub(@client.options[:site].chomp('/'), '') if @client.options[:site]
|
428
428
|
the_url
|
429
429
|
elsif key_value
|
430
430
|
self.class.singular_path(client, key_value.to_s, prefix)
|
data/lib/jira/client.rb
CHANGED
@@ -6,7 +6,7 @@ module JIRA
|
|
6
6
|
# This class is the main access point for all JIRA::Resource instances.
|
7
7
|
#
|
8
8
|
# The client must be initialized with an options hash containing
|
9
|
-
# configuration options.
|
9
|
+
# configuration options. The available options are:
|
10
10
|
#
|
11
11
|
# :site => 'http://localhost:2990',
|
12
12
|
# :context_path => '/jira',
|
@@ -14,18 +14,33 @@ module JIRA
|
|
14
14
|
# :request_token_path => "/plugins/servlet/oauth/request-token",
|
15
15
|
# :authorize_path => "/plugins/servlet/oauth/authorize",
|
16
16
|
# :access_token_path => "/plugins/servlet/oauth/access-token",
|
17
|
+
# :private_key => nil,
|
17
18
|
# :private_key_file => "rsakey.pem",
|
18
19
|
# :rest_base_path => "/rest/api/2",
|
19
20
|
# :consumer_key => nil,
|
20
21
|
# :consumer_secret => nil,
|
21
22
|
# :ssl_verify_mode => OpenSSL::SSL::VERIFY_PEER,
|
23
|
+
# :ssl_version => nil,
|
22
24
|
# :use_ssl => true,
|
23
25
|
# :username => nil,
|
24
26
|
# :password => nil,
|
25
27
|
# :auth_type => :oauth,
|
26
28
|
# :proxy_address => nil,
|
27
29
|
# :proxy_port => nil,
|
28
|
-
# :
|
30
|
+
# :proxy_username => nil,
|
31
|
+
# :proxy_password => nil,
|
32
|
+
# :use_cookies => nil,
|
33
|
+
# :additional_cookies => nil,
|
34
|
+
# :default_headers => {},
|
35
|
+
# :use_client_cert => false,
|
36
|
+
# :read_timeout => nil,
|
37
|
+
# :http_debug => false,
|
38
|
+
# :shared_secret => nil,
|
39
|
+
# :cert_path => nil,
|
40
|
+
# :key_path => nil,
|
41
|
+
# :ssl_client_cert => nil,
|
42
|
+
# :ssl_client_key => nil
|
43
|
+
# :ca_file => nil
|
29
44
|
#
|
30
45
|
# See the JIRA::Base class methods for all of the available methods on these accessor
|
31
46
|
# objects.
|
@@ -44,6 +59,43 @@ module JIRA
|
|
44
59
|
|
45
60
|
def_delegators :@request_client, :init_access_token, :set_access_token, :set_request_token, :request_token, :access_token, :authenticated?
|
46
61
|
|
62
|
+
DEFINED_OPTIONS = [
|
63
|
+
:site,
|
64
|
+
:context_path,
|
65
|
+
:signature_method,
|
66
|
+
:request_token_path,
|
67
|
+
:authorize_path,
|
68
|
+
:access_token_path,
|
69
|
+
:private_key,
|
70
|
+
:private_key_file,
|
71
|
+
:rest_base_path,
|
72
|
+
:consumer_key,
|
73
|
+
:consumer_secret,
|
74
|
+
:ssl_verify_mode,
|
75
|
+
:ssl_version,
|
76
|
+
:use_ssl,
|
77
|
+
:username,
|
78
|
+
:password,
|
79
|
+
:auth_type,
|
80
|
+
:proxy_address,
|
81
|
+
:proxy_port,
|
82
|
+
:proxy_username,
|
83
|
+
:proxy_password,
|
84
|
+
:use_cookies,
|
85
|
+
:additional_cookies,
|
86
|
+
:default_headers,
|
87
|
+
:use_client_cert,
|
88
|
+
:read_timeout,
|
89
|
+
:http_debug,
|
90
|
+
:issuer,
|
91
|
+
:base_url,
|
92
|
+
:shared_secret,
|
93
|
+
:cert_path,
|
94
|
+
:key_path,
|
95
|
+
:ssl_client_cert,
|
96
|
+
:ssl_client_key
|
97
|
+
].freeze
|
98
|
+
|
47
99
|
DEFAULT_OPTIONS = {
|
48
100
|
site: 'http://localhost:2990',
|
49
101
|
context_path: '/jira',
|
@@ -52,7 +104,8 @@ module JIRA
|
|
52
104
|
use_ssl: true,
|
53
105
|
use_client_cert: false,
|
54
106
|
auth_type: :oauth,
|
55
|
-
http_debug: false
|
107
|
+
http_debug: false,
|
108
|
+
default_headers: {}
|
56
109
|
}.freeze
|
57
110
|
|
58
111
|
def initialize(options = {})
|
@@ -60,17 +113,23 @@ module JIRA
|
|
60
113
|
@options = options
|
61
114
|
@options[:rest_base_path] = @options[:context_path] + @options[:rest_base_path]
|
62
115
|
|
116
|
+
unknown_options = options.keys.reject { |o| DEFINED_OPTIONS.include?(o) }
|
117
|
+
raise ArgumentError, "Unknown option(s) given: #{unknown_options}" unless unknown_options.empty?
|
118
|
+
|
63
119
|
if options[:use_client_cert]
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
120
|
+
@options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(File.read(@options[:cert_path])) if @options[:cert_path]
|
121
|
+
@options[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(@options[:key_path])) if @options[:key_path]
|
122
|
+
|
123
|
+
raise ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true' unless @options[:ssl_client_cert]
|
124
|
+
raise ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true' unless @options[:ssl_client_key]
|
68
125
|
end
|
69
126
|
|
70
127
|
case options[:auth_type]
|
71
128
|
when :oauth, :oauth_2legged
|
72
129
|
@request_client = OauthClient.new(@options)
|
73
130
|
@consumer = @request_client.consumer
|
131
|
+
when :jwt
|
132
|
+
@request_client = JwtClient.new(@options)
|
74
133
|
when :basic
|
75
134
|
@request_client = HttpClient.new(@options)
|
76
135
|
when :cookie
|
@@ -155,6 +214,10 @@ module JIRA
|
|
155
214
|
JIRA::Resource::BoardFactory.new(self)
|
156
215
|
end
|
157
216
|
|
217
|
+
def BoardConfiguration
|
218
|
+
JIRA::Resource::BoardConfigurationFactory.new(self)
|
219
|
+
end
|
220
|
+
|
158
221
|
def RapidView
|
159
222
|
JIRA::Resource::RapidViewFactory.new(self)
|
160
223
|
end
|
@@ -195,12 +258,12 @@ module JIRA
|
|
195
258
|
JIRA::Resource::IssuelinktypeFactory.new(self)
|
196
259
|
end
|
197
260
|
|
198
|
-
def
|
199
|
-
JIRA::Resource::
|
261
|
+
def IssuePickerSuggestions
|
262
|
+
JIRA::Resource::IssuePickerSuggestionsFactory.new(self)
|
200
263
|
end
|
201
264
|
|
202
|
-
def
|
203
|
-
JIRA::Resource::
|
265
|
+
def Remotelink
|
266
|
+
JIRA::Resource::RemotelinkFactory.new(self)
|
204
267
|
end
|
205
268
|
|
206
269
|
def Agile
|
@@ -226,6 +289,11 @@ module JIRA
|
|
226
289
|
request(:post, path, body, merge_default_headers(headers))
|
227
290
|
end
|
228
291
|
|
292
|
+
def post_multipart(path, file, headers = {})
|
293
|
+
puts "post multipart: #{path} - [#{file}]" if @http_debug
|
294
|
+
@request_client.request_multipart(path, file, headers)
|
295
|
+
end
|
296
|
+
|
229
297
|
def put(path, body = '', headers = {})
|
230
298
|
headers = { 'Content-Type' => 'application/json' }.merge(headers)
|
231
299
|
request(:put, path, body, merge_default_headers(headers))
|
@@ -238,10 +306,15 @@ module JIRA
|
|
238
306
|
@request_client.request(http_method, path, body, headers)
|
239
307
|
end
|
240
308
|
|
309
|
+
# Stops sensitive client information from being displayed in logs
|
310
|
+
def inspect
|
311
|
+
"#<JIRA::Client:#{object_id}>"
|
312
|
+
end
|
313
|
+
|
241
314
|
protected
|
242
315
|
|
243
316
|
def merge_default_headers(headers)
|
244
|
-
{ 'Accept' => 'application/json' }.merge(headers)
|
317
|
+
{ 'Accept' => 'application/json' }.merge(@options[:default_headers]).merge(headers)
|
245
318
|
end
|
246
319
|
end
|
247
320
|
end
|
data/lib/jira/http_client.rb
CHANGED
@@ -6,8 +6,8 @@ require 'uri'
|
|
6
6
|
module JIRA
|
7
7
|
class HttpClient < RequestClient
|
8
8
|
DEFAULT_OPTIONS = {
|
9
|
-
username:
|
10
|
-
password:
|
9
|
+
username: nil,
|
10
|
+
password: nil
|
11
11
|
}.freeze
|
12
12
|
|
13
13
|
attr_reader :options
|
@@ -18,7 +18,7 @@ module JIRA
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def make_cookie_auth_request
|
21
|
-
body = { username: @options[:username], password: @options[:password] }.to_json
|
21
|
+
body = { username: @options[:username].to_s, password: @options[:password].to_s }.to_json
|
22
22
|
@options.delete(:username)
|
23
23
|
@options.delete(:password)
|
24
24
|
make_request(:post, @options[:context_path] + '/rest/auth/1/session', body, 'Content-Type' => 'application/json')
|
@@ -29,12 +29,15 @@ module JIRA
|
|
29
29
|
path = request_path(url)
|
30
30
|
request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers)
|
31
31
|
request.body = body unless body.nil?
|
32
|
-
|
33
|
-
request
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
|
33
|
+
execute_request(request)
|
34
|
+
end
|
35
|
+
|
36
|
+
def make_multipart_request(url, body, headers = {})
|
37
|
+
path = request_path(url)
|
38
|
+
request = Net::HTTP::Post::Multipart.new(path, body, headers)
|
39
|
+
|
40
|
+
execute_request(request)
|
38
41
|
end
|
39
42
|
|
40
43
|
def basic_auth_http_conn
|
@@ -43,23 +46,25 @@ module JIRA
|
|
43
46
|
|
44
47
|
def http_conn(uri)
|
45
48
|
if @options[:proxy_address]
|
46
|
-
http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] || 80)
|
49
|
+
http_class = Net::HTTP::Proxy(@options[:proxy_address], @options[:proxy_port] || 80, @options[:proxy_username], @options[:proxy_password])
|
47
50
|
else
|
48
51
|
http_class = Net::HTTP
|
49
52
|
end
|
50
53
|
http_conn = http_class.new(uri.host, uri.port)
|
51
54
|
http_conn.use_ssl = @options[:use_ssl]
|
52
55
|
if @options[:use_client_cert]
|
53
|
-
http_conn.cert = @options[:
|
54
|
-
http_conn.key = @options[:
|
56
|
+
http_conn.cert = @options[:ssl_client_cert]
|
57
|
+
http_conn.key = @options[:ssl_client_key]
|
55
58
|
end
|
56
59
|
http_conn.verify_mode = @options[:ssl_verify_mode]
|
60
|
+
http_conn.ssl_version = @options[:ssl_version] if @options[:ssl_version]
|
57
61
|
http_conn.read_timeout = @options[:read_timeout]
|
62
|
+
http_conn.ca_file = @options[:ca_file] if @options[:ca_file]
|
58
63
|
http_conn
|
59
64
|
end
|
60
65
|
|
61
66
|
def uri
|
62
|
-
|
67
|
+
URI.parse(@options[:site])
|
63
68
|
end
|
64
69
|
|
65
70
|
def authenticated?
|
@@ -68,6 +73,17 @@ module JIRA
|
|
68
73
|
|
69
74
|
private
|
70
75
|
|
76
|
+
def execute_request(request)
|
77
|
+
add_cookies(request) if options[:use_cookies]
|
78
|
+
request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password]
|
79
|
+
|
80
|
+
response = basic_auth_http_conn.request(request)
|
81
|
+
@authenticated = response.is_a? Net::HTTPOK
|
82
|
+
store_cookies(response) if options[:use_cookies]
|
83
|
+
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
71
87
|
def request_path(url)
|
72
88
|
parsed_uri = URI(url)
|
73
89
|
|
data/lib/jira/http_error.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'atlassian/jwt'
|
2
|
+
|
3
|
+
module JIRA
|
4
|
+
class JwtClient < HttpClient
|
5
|
+
def make_request(http_method, url, body = '', headers = {})
|
6
|
+
@http_method = http_method
|
7
|
+
|
8
|
+
super(http_method, url, body, headers)
|
9
|
+
end
|
10
|
+
|
11
|
+
def make_multipart_request(url, data, headers = {})
|
12
|
+
@http_method = :post
|
13
|
+
|
14
|
+
super(url, data, headers)
|
15
|
+
end
|
16
|
+
|
17
|
+
class JwtUriBuilder
|
18
|
+
attr_reader :request_url, :http_method, :shared_secret, :site, :issuer
|
19
|
+
|
20
|
+
def initialize(request_url, http_method, shared_secret, site, issuer)
|
21
|
+
@request_url = request_url
|
22
|
+
@http_method = http_method
|
23
|
+
@shared_secret = shared_secret
|
24
|
+
@site = site
|
25
|
+
@issuer = issuer
|
26
|
+
end
|
27
|
+
|
28
|
+
def build
|
29
|
+
uri = URI.parse(request_url)
|
30
|
+
new_query = URI.decode_www_form(String(uri.query)) << ['jwt', jwt_header]
|
31
|
+
uri.query = URI.encode_www_form(new_query)
|
32
|
+
|
33
|
+
return uri.to_s unless uri.is_a?(URI::HTTP)
|
34
|
+
|
35
|
+
uri.request_uri
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def jwt_header
|
41
|
+
claim = Atlassian::Jwt.build_claims \
|
42
|
+
issuer,
|
43
|
+
request_url,
|
44
|
+
http_method.to_s,
|
45
|
+
site,
|
46
|
+
(Time.now - 60).to_i,
|
47
|
+
(Time.now + 86_400).to_i
|
48
|
+
|
49
|
+
JWT.encode claim, shared_secret
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :http_method
|
56
|
+
|
57
|
+
def request_path(url)
|
58
|
+
JwtUriBuilder.new(
|
59
|
+
url,
|
60
|
+
http_method.to_s,
|
61
|
+
@options[:shared_secret],
|
62
|
+
@options[:site],
|
63
|
+
@options[:issuer]
|
64
|
+
).build
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/jira/oauth_client.rb
CHANGED
@@ -38,13 +38,15 @@ module JIRA
|
|
38
38
|
@options[:request_token_path] = @options[:context_path] + @options[:request_token_path]
|
39
39
|
@options[:authorize_path] = @options[:context_path] + @options[:authorize_path]
|
40
40
|
@options[:access_token_path] = @options[:context_path] + @options[:access_token_path]
|
41
|
+
# proxy_address does not exist in oauth's gem context but proxy does
|
42
|
+
@options[:proxy] = @options[:proxy_address] if @options[:proxy_address]
|
41
43
|
OAuth::Consumer.new(@options[:consumer_key], @options[:consumer_secret], @options)
|
42
44
|
end
|
43
45
|
|
44
46
|
# Returns the current request token if it is set, else it creates
|
45
47
|
# and sets a new token.
|
46
48
|
def request_token(options = {}, *arguments, &block)
|
47
|
-
@request_token ||= get_request_token(options, *arguments, block)
|
49
|
+
@request_token ||= get_request_token(options, *arguments, &block)
|
48
50
|
end
|
49
51
|
|
50
52
|
# Sets the request token from a given token and secret.
|
@@ -72,29 +74,39 @@ module JIRA
|
|
72
74
|
@access_token
|
73
75
|
end
|
74
76
|
|
75
|
-
def make_request(http_method,
|
77
|
+
def make_request(http_method, url, body = '', headers = {})
|
76
78
|
# When using oauth_2legged we need to add an empty oauth_token parameter to every request.
|
77
79
|
if @options[:auth_type] == :oauth_2legged
|
78
80
|
oauth_params_str = 'oauth_token='
|
79
|
-
uri = URI.parse(
|
81
|
+
uri = URI.parse(url)
|
80
82
|
uri.query = if uri.query.to_s == ''
|
81
83
|
oauth_params_str
|
82
84
|
else
|
83
85
|
uri.query + '&' + oauth_params_str
|
84
86
|
end
|
85
|
-
|
87
|
+
url = uri.to_s
|
86
88
|
end
|
87
89
|
|
88
90
|
case http_method
|
89
91
|
when :delete, :get, :head
|
90
|
-
response = access_token.send http_method,
|
92
|
+
response = access_token.send http_method, url, headers
|
91
93
|
when :post, :put
|
92
|
-
response = access_token.send http_method,
|
94
|
+
response = access_token.send http_method, url, body, headers
|
93
95
|
end
|
94
96
|
@authenticated = true
|
95
97
|
response
|
96
98
|
end
|
97
99
|
|
100
|
+
def make_multipart_request(url, data, headers = {})
|
101
|
+
request = Net::HTTP::Post::Multipart.new url, data, headers
|
102
|
+
|
103
|
+
access_token.sign! request
|
104
|
+
|
105
|
+
response = consumer.http.request(request)
|
106
|
+
@authenticated = true
|
107
|
+
response
|
108
|
+
end
|
109
|
+
|
98
110
|
def authenticated?
|
99
111
|
@authenticated
|
100
112
|
end
|
data/lib/jira/request_client.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'oauth'
|
2
2
|
require 'json'
|
3
3
|
require 'net/https'
|
4
|
-
# require 'pry'
|
5
4
|
|
6
5
|
module JIRA
|
7
6
|
class RequestClient
|
@@ -11,9 +10,22 @@ module JIRA
|
|
11
10
|
|
12
11
|
def request(*args)
|
13
12
|
response = make_request(*args)
|
14
|
-
# binding.pry unless response.kind_of?(Net::HTTPSuccess)
|
15
13
|
raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
|
16
14
|
response
|
17
15
|
end
|
16
|
+
|
17
|
+
def request_multipart(*args)
|
18
|
+
response = make_multipart_request(*args)
|
19
|
+
raise HTTPError, response unless response.is_a?(Net::HTTPSuccess)
|
20
|
+
response
|
21
|
+
end
|
22
|
+
|
23
|
+
def make_request(*args)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_multipart_request(*args)
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
18
30
|
end
|
19
|
-
end
|
31
|
+
end
|