1
0
Fork 0
mirror of https://github.com/jnunemaker/httparty synced 2023-03-27 23:23:07 -04:00

Merge pull request #429 from bonybrown/md5sess_200

Added support for RFC2617 MD5-sess algorithm type
This commit is contained in:
John Nunemaker 2015-08-19 07:13:35 -04:00
commit 777563f5b9
5 changed files with 104 additions and 2 deletions

View file

@ -18,3 +18,13 @@ Feature: Digest Authentication
| username | password |
| jcash | maninblack |
Then the return value should match 'Digest Authenticated Page'
Scenario: Passing proper credentials to a page requiring Digest Authentication using md5-sess algorithm
Given a remote service that returns 'Digest Authenticated Page Using MD5-sess'
And that service is accessed at the path '/digest_auth.html'
And that service is protected by MD5-sess Digest Authentication
And that service requires the username 'jcash' with the password 'maninblack'
When I call HTTParty#get with '/digest_auth.html' and a digest_auth hash:
| username | password |
| jcash | maninblack |
Then the return value should match 'Digest Authenticated Page Using MD5-sess'

View file

@ -88,6 +88,39 @@ module DigestAuthentication
end
end
module DigestAuthenticationUsingMD5Sess
NONCE = 'nonce'
REALM = 'testrealm@host.com'
QOP = 'auth,auth-int'
def self.extended(base)
base.custom_headers["WWW-Authenticate"] = %(Digest realm="#{REALM}",qop="#{QOP}",algorithm="MD5-sess",nonce="#{NONCE}",opaque="opaque"')
end
def process(request, response)
if authorized?(request)
super
else
reply_with(response, 401, "Incorrect. You have 20 seconds to comply.")
end
end
def md5(str)
Digest::MD5.hexdigest(str)
end
def authorized?(request)
auth = request.params["HTTP_AUTHORIZATION"]
params = {}
auth.to_s.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 }
a1a = [@username,REALM,@password].join(':')
a1 = [md5(a1a),NONCE,params['cnonce'] ].join(':')
a2 = [ request.params["REQUEST_METHOD"], request.params["REQUEST_URI"] ] .join(':')
expected_response = md5( [md5(a1), NONCE, params['nc'], params['cnonce'], QOP, md5(a2)].join(':') )
expected_response == params['response']
end
end
def new_mongrel_redirector(target_url, relative_path = false)
target_url = "http://#{@host_and_port}#{target_url}" unless relative_path
Mongrel::RedirectHandler.new(target_url)

View file

@ -55,6 +55,10 @@ Given /that service is protected by Digest Authentication/ do
@handler.extend DigestAuthentication
end
Given /that service is protected by MD5-sess Digest Authentication/ do
@handler.extend DigestAuthenticationUsingMD5Sess
end
Given /that service requires the username '(.*)' with the password '(.*)'/ do |username, password|
@handler.username = username
@handler.password = password

View file

@ -41,6 +41,8 @@ module Net
%(response="#{request_digest}")
]
header << %(algorithm="#{@response['algorithm']}") if algorithm_present?
if qop_present?
fields = [
%(cnonce="#{@cnonce}"),
@ -66,7 +68,8 @@ module Net
header =~ /Digest (.*)/
params = {}
$1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
non_quoted = $1.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
non_quoted.gsub(/(\w+)=([^,]*)/) { params[$1] = $2 }
params
end
@ -105,8 +108,21 @@ module Net
Digest::MD5.hexdigest(str)
end
def algorithm_present?
@response.key?('algorithm') && !@response['algorithm'].empty?
end
def use_md5_sess?
algorithm_present? && @response['algorithm'] == 'MD5-sess'
end
def a1
[@username, @response['realm'], @password].join(":")
a1_user_realm_pwd = [@username, @response['realm'], @password].join(':')
if use_md5_sess?
[ md5(a1_user_realm_pwd), @response['nonce'], @cnonce ].join(':')
else
a1_user_realm_pwd
end
end
def a2

View file

@ -188,4 +188,43 @@ RSpec.describe Net::HTTPHeader::DigestAuthenticator do
expect(authorization_header).to include(%(response="#{request_digest}"))
end
end
context "with algorithm specified" do
before do
@digest = setup_digest({
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5'
})
end
it "should recognise algorithm was specified" do
expect( @digest.send :algorithm_present? ).to be(true)
end
it "should set the algorithm header" do
expect(authorization_header).to include('algorithm="MD5"')
end
end
context "with md5-sess algorithm specified" do
before do
@digest = setup_digest({
'www-authenticate' => 'Digest realm="myhost@testrealm.com", nonce="NONCE", qop="auth", algorithm=MD5-sess'
})
end
it "should recognise algorithm was specified" do
expect( @digest.send :algorithm_present? ).to be(true)
end
it "should set the algorithm header" do
expect(authorization_header).to include('algorithm="MD5-sess"')
end
it "should set response using md5-sess algorithm" do
request_digest = "md5(md5(md5(Mufasa:myhost@testrealm.com:Circle Of Life):NONCE:md5(deadbeef)):NONCE:00000001:md5(deadbeef):auth:md5(GET:/dir/index.html))"
expect(authorization_header).to include(%(response="#{request_digest}"))
end
end
end