提交 55b58054 编写于 作者: M Mislav Marohnić

Stop trying to re-use existing Access Tokens for hub

Due to upcoming GitHub API changes, the "token" field will not be
accessible anymore, which will make it impossible for hub to re-use an
existing token that might have been generated for another computer.

Now, a new Access Token will be created every time hub needs to exchange
the username/password credentials for an OAuth token.

https://developer.github.com/changes/2014-12-08-removing-authorizations-token/
上级 93691aea
...@@ -5,10 +5,11 @@ Feature: OAuth authentication ...@@ -5,10 +5,11 @@ Feature: OAuth authentication
Scenario: Ask for username & password, create authorization Scenario: Ask for username & password, create authorization
Given the GitHub API server: Given the GitHub API server:
""" """
get('/authorizations') { '[]' }
post('/authorizations') { post('/authorizations') {
assert_basic_auth 'mislav', 'kitty' assert_basic_auth 'mislav', 'kitty'
assert :scopes => ['repo'] assert :scopes => ['repo'],
:note => 'hub',
:note_url => 'http://hub.github.com/'
json :token => 'OTOKEN' json :token => 'OTOKEN'
} }
get('/user') { get('/user') {
...@@ -30,100 +31,12 @@ Feature: OAuth authentication ...@@ -30,100 +31,12 @@ Feature: OAuth authentication
And the file "../home/.config/hub" should contain "oauth_token: OTOKEN" And the file "../home/.config/hub" should contain "oauth_token: OTOKEN"
And the file "../home/.config/hub" should have mode "0600" And the file "../home/.config/hub" should have mode "0600"
Scenario: Ask for username & password, re-use existing authorization
Given the GitHub API server:
"""
get('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
json [
{:token => 'SKIPPD', :note_url => 'http://example.com'},
{:token => 'OTOKEN', :note_url => 'http://hub.github.com/'}
]
}
get('/user') {
json :login => 'mislav'
}
post('/user/repos') {
json :full_name => 'mislav/dotfiles'
}
"""
When I run `hub create` interactively
When I type "mislav"
And I type "kitty"
Then the output should contain "github.com password for mislav (never stored):"
And the exit status should be 0
And the file "../home/.config/hub" should contain "oauth_token: OTOKEN"
Scenario: Re-use existing authorization with an old URL
Given the GitHub API server:
"""
get('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
json [
{:token => 'OTOKEN', :note => 'hub', :note_url => 'http://defunkt.io/hub/'}
]
}
post('/authorizations') {
status 422
json :message => "Validation Failed",
:errors => [{:resource => "OauthAccess", :code => "already_exists", :field => "description"}]
}
get('/user') {
json :login => 'mislav'
}
post('/user/repos') {
json :full_name => 'mislav/dotfiles'
}
"""
When I run `hub create` interactively
When I type "mislav"
And I type "kitty"
Then the output should contain "github.com password for mislav (never stored):"
And the exit status should be 0
And the file "../home/.config/hub" should contain "oauth_token: OTOKEN"
Scenario: Re-use existing authorization found on page 3
Given the GitHub API server:
"""
get('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
page = (params[:page] || 1).to_i
if page < 3
response.headers['Link'] = %(<#{url}?page=#{page+1}>; rel="next")
json []
else
json [
{:token => 'OTOKEN', :note => 'hub', :note_url => 'http://hub.github.com/'}
]
end
}
post('/authorizations') {
status 422
json :message => "Validation Failed",
:errors => [{:resource => "OauthAccess", :code => "already_exists", :field => "description"}]
}
get('/user') {
json :login => 'mislav'
}
post('/user/repos') {
json :full_name => 'mislav/dotfiles'
}
"""
When I run `hub create` interactively
When I type "mislav"
And I type "kitty"
Then the output should contain "github.com password for mislav (never stored):"
And the exit status should be 0
And the file "../home/.config/hub" should contain "oauth_token: OTOKEN"
Scenario: Credentials from GITHUB_USER & GITHUB_PASSWORD Scenario: Credentials from GITHUB_USER & GITHUB_PASSWORD
Given the GitHub API server: Given the GitHub API server:
""" """
get('/authorizations') { post('/authorizations') {
assert_basic_auth 'mislav', 'kitty' assert_basic_auth 'mislav', 'kitty'
json [ json :token => 'OTOKEN'
{:token => 'OTOKEN', :note_url => 'http://hub.github.com/'}
]
} }
get('/user') { get('/user') {
json :login => 'mislav' json :login => 'mislav'
...@@ -141,7 +54,7 @@ Feature: OAuth authentication ...@@ -141,7 +54,7 @@ Feature: OAuth authentication
Scenario: Wrong password Scenario: Wrong password
Given the GitHub API server: Given the GitHub API server:
""" """
get('/authorizations') { post('/authorizations') {
assert_basic_auth 'mislav', 'kitty' assert_basic_auth 'mislav', 'kitty'
} }
""" """
...@@ -155,17 +68,8 @@ Feature: OAuth authentication ...@@ -155,17 +68,8 @@ Feature: OAuth authentication
Scenario: Two-factor authentication, create authorization Scenario: Two-factor authentication, create authorization
Given the GitHub API server: Given the GitHub API server:
""" """
get('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
if request.env['HTTP_X_GITHUB_OTP'] != "112233"
response.headers['X-GitHub-OTP'] = "required;application"
halt 401
end
json [ ]
}
post('/authorizations') { post('/authorizations') {
assert_basic_auth 'mislav', 'kitty' assert_basic_auth 'mislav', 'kitty'
halt 412 unless params[:scopes]
if request.env['HTTP_X_GITHUB_OTP'] != "112233" if request.env['HTTP_X_GITHUB_OTP'] != "112233"
response.headers['X-GitHub-OTP'] = "required;application" response.headers['X-GitHub-OTP'] = "required;application"
halt 401 halt 401
...@@ -188,46 +92,9 @@ Feature: OAuth authentication ...@@ -188,46 +92,9 @@ Feature: OAuth authentication
And the exit status should be 0 And the exit status should be 0
And the file "../home/.config/hub" should contain "oauth_token: OTOKEN" And the file "../home/.config/hub" should contain "oauth_token: OTOKEN"
Scenario: Two-factor authentication, re-use existing authorization
Given the GitHub API server:
"""
token = 'OTOKEN'
post('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
token << 'SMS'
status 412
}
get('/authorizations') {
assert_basic_auth 'mislav', 'kitty'
if request.env['HTTP_X_GITHUB_OTP'] != "112233"
response.headers['X-GitHub-OTP'] = "required;application"
halt 401
end
json [ {
:token => token,
:note_url => 'http://hub.github.com/'
} ]
}
get('/user') {
json :login => 'mislav'
}
post('/user/repos') {
json :full_name => 'mislav/dotfiles'
}
"""
When I run `hub create` interactively
When I type "mislav"
And I type "kitty"
And I type "112233"
Then the output should contain "github.com password for mislav (never stored):"
Then the output should contain "two-factor authentication code:"
And the exit status should be 0
And the file "../home/.config/hub" should contain "oauth_token: OTOKENSMS"
Scenario: Special characters in username & password Scenario: Special characters in username & password
Given the GitHub API server: Given the GitHub API server:
""" """
get('/authorizations') { '[]' }
post('/authorizations') { post('/authorizations') {
assert_basic_auth 'mislav@example.com', 'my pass@phrase ok?' assert_basic_auth 'mislav@example.com', 'my pass@phrase ok?'
json :token => 'OTOKEN' json :token => 'OTOKEN'
......
...@@ -333,36 +333,31 @@ module Hub ...@@ -333,36 +333,31 @@ module Hub
end end
end end
def obtain_oauth_token host, user, two_factor_code = nil def obtain_oauth_token host, user
auth_url = URI.parse("https://%s@%s/authorizations" % [CGI.escape(user), host]) auth_url = URI.parse("https://%s@%s/authorizations" % [CGI.escape(user), host])
auth_params = {
:scopes => ['repo'],
:note => 'hub',
:note_url => oauth_app_url
}
res = nil
two_factor_code = nil
# dummy request to trigger a 2FA SMS since a HTTP GET won't do it loop do
post(auth_url) if !two_factor_code res = post(auth_url, auth_params) do |req|
req['X-GitHub-OTP'] = two_factor_code if two_factor_code
end
# first try to fetch existing authorization if res.success?
res = get_all(auth_url) do |req| break
req['X-GitHub-OTP'] = two_factor_code if two_factor_code elsif res.status == 401 && res['X-GitHub-OTP'].to_s.include?('required')
end
unless res.success?
if !two_factor_code && res['X-GitHub-OTP'].to_s.include?('required')
two_factor_code = config.prompt_auth_code two_factor_code = config.prompt_auth_code
return obtain_oauth_token(host, user, two_factor_code)
else else
res.error! res.error!
end end
end end
if found = res.data.find {|auth| auth['note'] == 'hub' || auth['note_url'] == oauth_app_url } res.data['token']
found['token']
else
# create a new authorization
res = post auth_url,
:scopes => %w[repo], :note => 'hub', :note_url => oauth_app_url do |req|
req['X-GitHub-OTP'] = two_factor_code if two_factor_code
end
res.error! unless res.success?
res.data['token']
end
end end
end end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册