mirror of
https://github.com/jnunemaker/httparty
synced 2023-03-27 23:23:07 -04:00
Added Digest Access Authentication support to HTTParty.
New File: lib/net_http_digest.rb From: http://codesnippets.joyent.com/posts/show/1075 This extends Net::HTTP with a new digest_authentication method. Extended HTTParty to use this new functionality in a backwards compatible fashion. To use the new digest_auth method, merely use :digest_auth as your HTTParty credentials option instead of :basic_auth. HTTParty will take care of the rest.
This commit is contained in:
parent
05dcf3b479
commit
fd19af35ac
4 changed files with 92 additions and 2 deletions
|
@ -11,6 +11,7 @@ dir = Pathname(__FILE__).dirname.expand_path
|
|||
|
||||
require dir + 'httparty/module_inheritable_attributes'
|
||||
require dir + 'httparty/cookie_hash'
|
||||
require dir + 'net_digest_auth'
|
||||
|
||||
module HTTParty
|
||||
VERSION = "0.5.2".freeze
|
||||
|
|
|
@ -94,12 +94,16 @@ module HTTParty
|
|||
options[:body].is_a?(Hash) ? options[:body].to_params : options[:body]
|
||||
end
|
||||
|
||||
def credentials
|
||||
options[:basic_auth] || options[:digest_auth]
|
||||
end
|
||||
|
||||
def username
|
||||
options[:basic_auth][:username]
|
||||
credentials[:username]
|
||||
end
|
||||
|
||||
def password
|
||||
options[:basic_auth][:password]
|
||||
credentials[:password]
|
||||
end
|
||||
|
||||
def setup_raw_request
|
||||
|
@ -107,6 +111,14 @@ module HTTParty
|
|||
@raw_request.body = body if body
|
||||
@raw_request.initialize_http_header(options[:headers])
|
||||
@raw_request.basic_auth(username, password) if options[:basic_auth]
|
||||
setup_digest_auth if options[:digest_auth]
|
||||
end
|
||||
|
||||
def setup_digest_auth
|
||||
res = http.head(uri.request_uri)
|
||||
if res['www-authenticate'] != nil && res['www-authenticate'].length > 0
|
||||
@raw_request.digest_auth(username, password, res)
|
||||
end
|
||||
end
|
||||
|
||||
def perform_actual_request
|
||||
|
@ -182,7 +194,9 @@ module HTTParty
|
|||
raise HTTParty::RedirectionTooDeep.new(last_response), 'HTTP redirects too deep' if options[:limit].to_i <= 0
|
||||
raise ArgumentError, 'only get, post, put, delete, head, and options methods are supported' unless SupportedHTTPMethods.include?(http_method)
|
||||
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
|
||||
raise ArgumentError, 'only one authentication method, :basic_auth or :digest_auth may be used at a time' if options[:basic_auth] && options[:digest_auth]
|
||||
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
||||
raise ArgumentError, ':digest_auth must be a hash' if options[:digest_auth] && !options[:digest_auth].is_a?(Hash)
|
||||
raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
|
||||
end
|
||||
|
||||
|
|
44
lib/net_digest_auth.rb
Normal file
44
lib/net_digest_auth.rb
Normal file
|
@ -0,0 +1,44 @@
|
|||
require 'digest/md5'
|
||||
require 'net/http'
|
||||
|
||||
module Net
|
||||
module HTTPHeader
|
||||
@@nonce_count = -1
|
||||
CNONCE = Digest::MD5.new.update("%x" % (Time.now.to_i + rand(65535))).hexdigest
|
||||
def digest_auth(user, password, response)
|
||||
# based on http://segment7.net/projects/ruby/snippets/digest_auth.rb
|
||||
@@nonce_count += 1
|
||||
|
||||
|
||||
response['www-authenticate'] =~ /^(\w+) (.*)/
|
||||
|
||||
params = {}
|
||||
$2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
||||
|
||||
a_1 = "#{user}:#{params['realm']}:#{password}"
|
||||
a_2 = "#{@method}:#{@path}"
|
||||
request_digest = ''
|
||||
request_digest << Digest::MD5.new.update(a_1).hexdigest
|
||||
request_digest << ':' << params['nonce']
|
||||
request_digest << ':' << ('%08x' % @@nonce_count)
|
||||
request_digest << ':' << CNONCE
|
||||
request_digest << ':' << params['qop']
|
||||
request_digest << ':' << Digest::MD5.new.update(a_2).hexdigest
|
||||
|
||||
header = []
|
||||
header << "Digest username=\"#{user}\""
|
||||
header << "realm=\"#{params['realm']}\""
|
||||
|
||||
header << "qop=#{params['qop']}"
|
||||
|
||||
header << "algorithm=MD5"
|
||||
header << "uri=\"#{@path}\""
|
||||
header << "nonce=\"#{params['nonce']}\""
|
||||
header << "nc=#{'%08x' % @@nonce_count}"
|
||||
header << "cnonce=\"#{CNONCE}\""
|
||||
header << "response=\"#{Digest::MD5.new.update(request_digest).hexdigest}\""
|
||||
|
||||
@header['Authorization'] = header
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,6 +30,17 @@ describe HTTParty::Request do
|
|||
@request.send(:setup_raw_request)
|
||||
@request.instance_variable_get(:@raw_request)['authorization'].should_not be_nil
|
||||
end
|
||||
|
||||
it "should use digest auth when configured" do
|
||||
FakeWeb.register_uri(:head, "http://api.foo.com/v1",
|
||||
:www_authenticate => 'Digest realm="Log Viewer", qop="auth", nonce="2CA0EC6B0E126C4800E56BA0C0003D3C", opaque="5ccc069c403ebaf9f0171e9517f40e41", stale=false')
|
||||
|
||||
@request.options[:digest_auth] = {:username => 'foobar', :password => 'secret'}
|
||||
@request.send(:setup_raw_request)
|
||||
|
||||
raw_request = @request.instance_variable_get(:@raw_request)
|
||||
raw_request.instance_variable_get(:@header)['Authorization'].should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#uri" do
|
||||
|
@ -373,5 +384,25 @@ describe HTTParty::Request do
|
|||
}.should raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
describe "argument validation" do
|
||||
it "should raise argument error if basic_auth and digest_auth are both present" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => {}, :digest_auth => {}).perform
|
||||
}.should raise_error(ArgumentError, "only one authentication method, :basic_auth or :digest_auth may be used at a time")
|
||||
end
|
||||
|
||||
it "should raise argument error if basic_auth is not a hash" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :basic_auth => ["foo", "bar"]).perform
|
||||
}.should raise_error(ArgumentError, ":basic_auth must be a hash")
|
||||
end
|
||||
|
||||
it "should raise argument error if digest_auth is not a hash" do
|
||||
lambda {
|
||||
HTTParty::Request.new(Net::HTTP::Post, 'http://api.foo.com/v1', :digest_auth => ["foo", "bar"]).perform
|
||||
}.should raise_error(ArgumentError, ":digest_auth must be a hash")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue