-
Notifications
You must be signed in to change notification settings - Fork 18
/
digest_auth.rb
119 lines (100 loc) · 2.84 KB
/
digest_auth.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
require 'net/http'
require 'digest'
require 'cgi'
##
# An implementation of RFC 2617 Digest Access Authentication.
#
# http://www.rfc-editor.org/rfc/rfc2617.txt
#
# Here is a sample usage of DigestAuth on Net::HTTP:
#
# require 'uri'
# require 'net/http'
# require 'net/http/digest_auth'
#
# uri = URI.parse 'http://localhost:8000/'
# uri.user = 'username'
# uri.password = 'password'
#
# h = Net::HTTP.new uri.host, uri.port
#
# req = Net::HTTP::Get.new uri.request_uri
#
# res = h.request req
#
# digest_auth = Net::HTTP::DigestAuth.new
# auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'
#
# req = Net::HTTP::Get.new uri.request_uri
# req.add_field 'Authorization', auth
#
# res = h.request req
class Net::HTTP::DigestAuth
##
# Version of Net::HTTP::DigestAuth you are using
VERSION = '1.0'
##
# Creates a new DigestAuth header creator.
#
# +cnonce+ is the client nonce value. This should be an MD5 hexdigest of a
# secret value.
def initialize cnonce = make_cnonce
@nonce_count = -1
@cnonce = cnonce
end
##
# Creates a digest auth header for +uri+ from the +www_authenticate+ header
# for HTTP method +method+.
#
# The result of this method should be sent along with the HTTP request as
# the "Authorization" header. In Net::HTTP this will look like:
#
# request.add_field 'Authorization', digest_auth.auth_header # ...
#
# See Net::HTTP::DigestAuth for a complete example.
#
# IIS servers handle the "qop" parameter of digest authentication
# differently so you may need to set +iis+ to true for such servers.
def auth_header uri, www_authenticate, method, iis = false
@nonce_count += 1
user = CGI.unescape uri.user
password = CGI.unescape uri.password
www_authenticate =~ /^(\w+) (.*)/
params = {}
$2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
ha1 = Digest::MD5.hexdigest "#{user}:#{params['realm']}:#{password}"
ha2 = Digest::MD5.hexdigest "#{method}:#{uri.request_uri}"
request_digest = [
ha1,
params['nonce'],
('%08x' % @nonce_count),
@cnonce,
params['qop'],
ha2
].join ':'
header = [
"Digest username=\"#{user}\"",
"realm=\"#{params['realm']}\"",
if iis then
"qop=\"#{params['qop']}\""
else
"qop=#{params['qop']}"
end,
"uri=\"#{uri.request_uri}\"",
"nonce=\"#{params['nonce']}\"",
"nc=#{'%08x' % @nonce_count}",
"cnonce=\"#{@cnonce}\"",
"response=\"#{Digest::MD5.hexdigest request_digest}\"",
if params.key? 'opaque' then
"opaque=\"#{params['opaque']}\""
end
].compact
header.join ', '
end
##
# Creates a client nonce value that is used across all requests based on the
# current time.
def make_cnonce
Digest::MD5.hexdigest "%x" % (Time.now.to_i + rand(65535))
end
end