Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] syntactic sugar for JIRA::HTTPError due to Atlassian basic auth changes #336

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require 'jira-ruby'

options = {
:username => 'username',
:password => 'pass1234',
:api_access_token => 'myAPIAccessToken1234', # see link below to generate one.
:site => 'http://mydomain.atlassian.net:443/',
:context_path => '',
:auth_type => :basic
Expand All @@ -38,6 +38,8 @@ end

* [Reference](http://docs.atlassian.com/jira/REST/latest/)

* [How to generate an API Access Token](https://confluence.atlassian.com/cloud/api-tokens-938839638.html)

## Running tests

Before running tests, you will need a public certificate generated.
Expand Down Expand Up @@ -153,16 +155,12 @@ require 'jira-ruby'
# Consider the use of :use_ssl and :ssl_verify_mode options if running locally
# for tests.

# 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

# You will see JIRA::HTTPError (JIRA::HTTPError) if you attempt to use basic auth with your user's password

username = "myremoteuser"
api_token = "myApiToken"

options = {
:username => username,
:password => api_token,
:api_access_token => api_token,
:site => 'http://localhost:8080/', # or 'https://<your_subdomain>.atlassian.net'
:context_path => '/myjira', # often blank
:auth_type => :basic,
Expand Down
3 changes: 3 additions & 0 deletions lib/jira/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module JIRA
# :use_ssl => true,
# :username => nil,
# :password => nil,
# :api_access_token => nil,
# :auth_type => :oauth,
# :proxy_address => nil,
# :proxy_port => nil,
Expand Down Expand Up @@ -76,9 +77,11 @@ def initialize(options = {})
when :jwt
@request_client = JwtClient.new(@options)
when :basic
raise ArgumentError, 'Options: :you must specify a :api_access_token as opposed to a :password' if @options.key?(:password) && [email protected]?(:api_access_token)
@request_client = HttpClient.new(@options)
when :cookie
raise ArgumentError, 'Options: :use_cookies must be true for :cookie authorization type' if @options.key?(:use_cookies) && !@options[:use_cookies]
raise ArgumentError, 'Options: when :use_cookies is true you must specify a :password as opposed to an :api_access_token' if @options.key?(:api_access_token) && [email protected]?(:password)
@options[:use_cookies] = true
@request_client = HttpClient.new(@options)
@request_client.make_cookie_auth_request
Expand Down
5 changes: 3 additions & 2 deletions lib/jira/http_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ module JIRA
class HttpClient < RequestClient
DEFAULT_OPTIONS = {
username: '',
password: ''
password: '',
api_access_token: ''
}.freeze

attr_reader :options
Expand All @@ -30,7 +31,7 @@ def make_request(http_method, url, body = '', headers = {})
request = Net::HTTP.const_get(http_method.to_s.capitalize).new(path, headers)
request.body = body unless body.nil?
add_cookies(request) if options[:use_cookies]
request.basic_auth(@options[:username], @options[:password]) if @options[:username] && @options[:password]
request.basic_auth(@options[:username], @options[:api_access_token]) if @options[:username] && @options[:api_access_token]
response = basic_auth_http_conn.request(request)
@authenticated = response.is_a? Net::HTTPOK
store_cookies(response) if options[:use_cookies]
Expand Down
2 changes: 1 addition & 1 deletion lib/jira/resource/attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def save!(attrs)

request = Net::HTTP::Post::Multipart.new url, data, headers
request.basic_auth(client.request_client.options[:username],
client.request_client.options[:password])
client.request_client.options[:api_access_token])

response = client.request_client.basic_auth_http_conn.request(request)

Expand Down
15 changes: 14 additions & 1 deletion spec/jira/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@

it 'sets the username and password' do
expect(subject.options[:username]).to eq('foo')
expect(subject.options[:password]).to eq('bar')
expect(subject.options[:api_access_token]).to eq('bar')
end

it 'fails with wrong user name and password' do
Expand All @@ -155,6 +155,12 @@
expect(subject.Project.all).to be_empty
expect(subject.authenticated?).to be_truthy
end

it 'raises an Exception when constructed with a password' do
expect(lambda {
JIRA::Client.new(username: 'foo', password: 'bad_password', auth_type: :basic)
}).to raise_exception(ArgumentError, 'can only construct an auth_type: :basic client with an :api_access_token')
end
end

context 'with cookie authentication' do
Expand Down Expand Up @@ -205,6 +211,13 @@
expect(subject.options[:username]).to be_nil
expect(subject.options[:password]).to be_nil
end

it 'raises an Exception when constructed with an api_access_token' do
expect(lambda {
JIRA::Client.new(username: 'foo', api_access_token: 'incorrect_usage_of_token', auth_type: :cookie)
}).to raise_exception(ArgumentError, 'can only construct a auth_type: :cookie client with a :password')

end
end

context 'with jwt authentication' do
Expand Down
6 changes: 3 additions & 3 deletions spec/jira/http_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
basic_auth_http_conn = double
request = double
allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).exactly(5).times.and_return(request)
expect(request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:api_access_token]).exactly(5).times.and_return(request)
expect(basic_auth_http_conn).to receive(:request).exactly(5).times.with(request).and_return(response)
%i[delete get head].each do |method|
expect(Net::HTTP.const_get(method.to_s.capitalize)).to receive(:new).with('/path', headers).and_return(request)
Expand Down Expand Up @@ -141,7 +141,7 @@
expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request)

expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response)
expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request)
expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:api_access_token]).and_return(http_request)
allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
basic_client.make_request(:get, '/foo', body, headers)
end
Expand All @@ -154,7 +154,7 @@
expect(Net::HTTP::Get).to receive(:new).with('/foo', headers).and_return(http_request)

expect(basic_auth_http_conn).to receive(:request).with(http_request).and_return(response)
expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:password]).and_return(http_request)
expect(http_request).to receive(:basic_auth).with(basic_client.options[:username], basic_client.options[:api_access_token]).and_return(http_request)
allow(basic_client).to receive(:basic_auth_http_conn).and_return(basic_auth_http_conn)
basic_client.make_request(:get, 'http://mydomain.com/foo', body, headers)
end
Expand Down