net-http-digest_auth 1.0 → 1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data.tar.gz.sig CHANGED
Binary file
data/.gemtest ADDED
File without changes
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ === 1.1
2
+
3
+ * Minor enhancements
4
+ * Add support for SHA1, SHA2, SHA256, SHA384, SHA512, RMD160 algorithms
5
+ * Bug fixes
6
+ * Support opaque per RFC 2617 3.2.1
7
+ * Support MD5-sess per RFC 2617 3.2.2.2
8
+ * Support unspecified qop for RFC 2069 compatibility per RFC 2617 3.2.2.1
9
+
1
10
  === 1.0 / 2010-09-10
2
11
 
3
12
  * Major enhancements
data/Manifest.txt CHANGED
@@ -4,4 +4,6 @@ Manifest.txt
4
4
  README.txt
5
5
  Rakefile
6
6
  lib/net/http/digest_auth.rb
7
+ sample/auth_server.rb
8
+ sample/net_http_example.rb
7
9
  test/test_net_http_digest_auth.rb
data/Rakefile CHANGED
@@ -3,12 +3,13 @@
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
5
 
6
+ Hoe.plugin :git
7
+ Hoe.plugin :minitest
8
+
6
9
  Hoe.spec 'net-http-digest_auth' do
7
10
  self.rubyforge_name = 'seattlerb'
8
11
  developer 'Eric Hodel', 'drbrain@segment7.net'
9
12
 
10
- self.testlib = :minitest
11
-
12
13
  spec_extras['homepage'] =
13
14
  'http://seattlerb.rubyforge.org/net-http-digest_auth'
14
15
  end
@@ -33,10 +33,15 @@ require 'cgi'
33
33
 
34
34
  class Net::HTTP::DigestAuth
35
35
 
36
+ ##
37
+ # DigestAuth error class
38
+
39
+ class Error < RuntimeError; end
40
+
36
41
  ##
37
42
  # Version of Net::HTTP::DigestAuth you are using
38
43
 
39
- VERSION = '1.0'
44
+ VERSION = '1.1'
40
45
 
41
46
  ##
42
47
  # Creates a new DigestAuth header creator.
@@ -74,32 +79,60 @@ class Net::HTTP::DigestAuth
74
79
  params = {}
75
80
  $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
76
81
 
77
- a_1 = Digest::MD5.hexdigest "#{user}:#{params['realm']}:#{password}"
78
- a_2 = Digest::MD5.hexdigest "#{method}:#{uri.request_uri}"
79
-
80
- request_digest = [
81
- a_1,
82
- params['nonce'],
83
- ('%08x' % @nonce_count),
84
- @cnonce,
85
- params['qop'],
86
- a_2
87
- ].join ':'
82
+ qop = params['qop']
83
+
84
+ if params['algorithm'] =~ /(.*?)(-sess)?$/
85
+ algorithm = case $1
86
+ when 'MD5' then Digest::MD5
87
+ when 'SHA1' then Digest::SHA1
88
+ when 'SHA2' then Digest::SHA2
89
+ when 'SHA256' then Digest::SHA256
90
+ when 'SHA384' then Digest::SHA384
91
+ when 'SHA512' then Digest::SHA512
92
+ when 'RMD160' then Digest::RMD160
93
+ else raise Error, "unknown algorithm \"#{$1}\""
94
+ end
95
+ sess = $2
96
+ else
97
+ algorithm = Digest::MD5
98
+ sess = false
99
+ end
100
+
101
+ a1 = if sess then
102
+ [ algorithm.hexdigest("#{user}:#{params['realm']}:#{password}"),
103
+ params['nonce'],
104
+ params['cnonce']
105
+ ].join ':'
106
+ else
107
+ "#{user}:#{params['realm']}:#{password}"
108
+ end
109
+
110
+ ha1 = algorithm.hexdigest a1
111
+ ha2 = algorithm.hexdigest "#{method}:#{uri.request_uri}"
112
+
113
+ request_digest = [ha1, params['nonce']]
114
+ request_digest.push ('%08x' % @nonce_count), @cnonce, qop if qop
115
+ request_digest << ha2
116
+ request_digest = request_digest.join ':'
88
117
 
89
118
  header = [
90
119
  "Digest username=\"#{user}\"",
91
120
  "realm=\"#{params['realm']}\"",
92
- if iis then
93
- "qop=\"#{params['qop']}\""
121
+ if qop.nil? then
122
+ elsif iis then
123
+ "qop=\"#{qop}\""
94
124
  else
95
- "qop=#{params['qop']}"
125
+ "qop=#{qop}"
96
126
  end,
97
127
  "uri=\"#{uri.request_uri}\"",
98
128
  "nonce=\"#{params['nonce']}\"",
99
129
  "nc=#{'%08x' % @nonce_count}",
100
130
  "cnonce=\"#{@cnonce}\"",
101
- "response=\"#{Digest::MD5.hexdigest request_digest}\""
102
- ]
131
+ "response=\"#{algorithm.hexdigest(request_digest)[0, 32]}\"",
132
+ if params.key? 'opaque' then
133
+ "opaque=\"#{params['opaque']}\""
134
+ end
135
+ ].compact
103
136
 
104
137
  header.join ', '
105
138
  end
@@ -0,0 +1,48 @@
1
+ require 'webrick'
2
+ require 'tempfile'
3
+
4
+ class AuthServlet < WEBrick::HTTPServlet::AbstractServlet
5
+
6
+ @instance = nil
7
+
8
+ def self.get_instance server, *options
9
+ @instance ||= new(server, *options)
10
+ end
11
+
12
+ def initialize server
13
+ super server
14
+
15
+ config = {}
16
+ config[:Realm] = 'net-http-digest_auth'
17
+ config[:UseOpaque] = false
18
+ config[:AutoReloadUserDB] = false
19
+ config[:Algorithm] = 'MD5'
20
+
21
+ passwd_file = Tempfile.new 'net-http-digest_auth'
22
+ passwd_file.close
23
+
24
+ htpasswd = WEBrick::HTTPAuth::Htpasswd.new passwd_file.path
25
+ htpasswd.auth_type = WEBrick::HTTPAuth::DigestAuth
26
+ htpasswd.set_passwd config[:Realm], 'username', 'password'
27
+ htpasswd.flush
28
+
29
+ config[:UserDB] = htpasswd
30
+
31
+ @digest_auth = WEBrick::HTTPAuth::DigestAuth.new config
32
+ end
33
+
34
+ def do_GET req, res
35
+ @digest_auth.authenticate req, res
36
+
37
+ res.body = 'worked!'
38
+ end
39
+
40
+ end
41
+
42
+ s = WEBrick::HTTPServer.new :Port => 8000
43
+ s.mount '/', AuthServlet
44
+
45
+ trap 'INT' do s.shutdown end
46
+
47
+ s.start
48
+
@@ -0,0 +1,27 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/http/digest_auth'
4
+
5
+ uri = URI.parse 'http://localhost:8000/'
6
+ uri.user = 'username'
7
+ uri.password = 'password'
8
+
9
+ h = Net::HTTP.new uri.host, uri.port
10
+ h.set_debug_output $stderr
11
+
12
+ req = Net::HTTP::Get.new uri.request_uri
13
+
14
+ res = h.request req
15
+
16
+ digest_auth = Net::HTTP::DigestAuth.new
17
+ auth = digest_auth.auth_header uri, res['www-authenticate'], 'GET'
18
+
19
+ req = Net::HTTP::Get.new uri.request_uri
20
+ req.add_field 'Authorization', auth
21
+
22
+ res = h.request req
23
+
24
+ puts
25
+ puts "passed" if res.code == '200'
26
+ puts "failed" if res.code != '200'
27
+
@@ -16,11 +16,7 @@ class TestNetHttpDigestAuth < MiniTest::Unit::TestCase
16
16
  'nonce="4107baa081a592a6021660200000cd6c5686ff5f579324402b374d83e2c9"'
17
17
  ].join ', '
18
18
 
19
- @da = Net::HTTP::DigestAuth.new @cnonce
20
- end
21
-
22
- def test_auth_header
23
- expected = [
19
+ @expected = [
24
20
  'Digest username="user"',
25
21
  'realm="www.example.com"',
26
22
  'qop=auth',
@@ -29,41 +25,78 @@ class TestNetHttpDigestAuth < MiniTest::Unit::TestCase
29
25
  'nc=00000000',
30
26
  'cnonce="9ea5ff3bd34554a4165bbdc1df91dcff"',
31
27
  'response="67be92a5e7b38d08679957db04f5da04"'
32
- ].join ', '
28
+ ]
29
+
30
+ @da = Net::HTTP::DigestAuth.new @cnonce
31
+ end
32
+
33
+ def expected
34
+ @expected.join ', '
35
+ end
36
+
37
+ def test_auth_header
38
+ assert_equal expected, @da.auth_header(@uri, @header, 'GET')
39
+
40
+ @expected[5] = 'nc=00000001'
41
+ @expected[7] = 'response="1f5f0cd1588690c1303737f081c0b9bb"'
33
42
 
34
43
  assert_equal expected, @da.auth_header(@uri, @header, 'GET')
35
44
  end
36
45
 
37
46
  def test_auth_header_iis
38
- expected = [
39
- 'Digest username="user"',
40
- 'realm="www.example.com"',
41
- 'qop="auth"',
42
- 'uri="/"',
43
- 'nonce="4107baa081a592a6021660200000cd6c5686ff5f579324402b374d83e2c9"',
44
- 'nc=00000000',
45
- 'cnonce="9ea5ff3bd34554a4165bbdc1df91dcff"',
46
- 'response="67be92a5e7b38d08679957db04f5da04"'
47
- ].join ', '
47
+ @expected[2] = 'qop="auth"'
48
48
 
49
49
  assert_equal expected, @da.auth_header(@uri, @header, 'GET', true)
50
50
  end
51
51
 
52
+ def test_auth_header_no_qop
53
+ @header.sub! ' qop="auth",', ''
54
+
55
+ @expected[7] = 'response="32f6ca1631ccf7c42a8075deff44e470"'
56
+ @expected.slice! 2
57
+
58
+ assert_equal expected, @da.auth_header(@uri, @header, 'GET')
59
+ end
60
+
61
+ def test_auth_header_opaque
62
+ @expected << 'opaque="5ccc069c403ebaf9f0171e9517f40e41"'
63
+ @header << 'opaque="5ccc069c403ebaf9f0171e9517f40e41"'
64
+
65
+ assert_equal expected, @da.auth_header(@uri, @header, 'GET')
66
+ end
67
+
52
68
  def test_auth_header_post
53
- expected = [
54
- 'Digest username="user"',
55
- 'realm="www.example.com"',
56
- 'qop=auth',
57
- 'uri="/"',
58
- 'nonce="4107baa081a592a6021660200000cd6c5686ff5f579324402b374d83e2c9"',
59
- 'nc=00000000',
60
- 'cnonce="9ea5ff3bd34554a4165bbdc1df91dcff"',
61
- 'response="d82219e1e5430b136bbae1670fa51d48"'
62
- ].join ', '
69
+ @expected[7] = 'response="d82219e1e5430b136bbae1670fa51d48"'
63
70
 
64
71
  assert_equal expected, @da.auth_header(@uri, @header, 'POST')
65
72
  end
66
73
 
74
+ def test_auth_header_sess
75
+ @header << 'algorithm="MD5-sess"'
76
+
77
+ @expected[7] = 'response="76d3ff10007496cee26c61f9d04c72a8"'
78
+
79
+ assert_equal expected, @da.auth_header(@uri, @header, 'GET')
80
+ end
81
+
82
+ def test_auth_header_sha1
83
+ @expected[7] = 'response="2cb62fc18f7b0ebdc34543f896bb7768"'
84
+
85
+ @header << 'algorithm="SHA1"'
86
+
87
+ assert_equal expected, @da.auth_header(@uri, @header, 'GET')
88
+ end
89
+
90
+ def test_auth_header_unknown_algorithm
91
+ @header << 'algorithm="bogus"'
92
+
93
+ e = assert_raises Net::HTTP::DigestAuth::Error do
94
+ @da.auth_header @uri, @header, 'GET'
95
+ end
96
+
97
+ assert_equal 'unknown algorithm "bogus"', e.message
98
+ end
99
+
67
100
  def test_make_cnonce
68
101
  assert_match %r%\A[a-f\d]{32}\z%, @da.make_cnonce
69
102
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-http-digest_auth
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
- prerelease: false
4
+ hash: 13
5
+ prerelease:
6
6
  segments:
7
7
  - 1
8
- - 0
9
- version: "1.0"
8
+ - 1
9
+ version: "1.1"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Eric Hodel
@@ -35,23 +35,23 @@ cert_chain:
35
35
  x52qPcexcYZR7w==
36
36
  -----END CERTIFICATE-----
37
37
 
38
- date: 2010-09-10 00:00:00 -07:00
38
+ date: 2011-03-29 00:00:00 -07:00
39
39
  default_executable:
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubyforge
42
+ name: minitest
43
43
  prerelease: false
44
44
  requirement: &id001 !ruby/object:Gem::Requirement
45
45
  none: false
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- hash: 7
49
+ hash: 11
50
50
  segments:
51
51
  - 2
52
52
  - 0
53
- - 4
54
- version: 2.0.4
53
+ - 2
54
+ version: 2.0.2
55
55
  type: :development
56
56
  version_requirements: *id001
57
57
  - !ruby/object:Gem::Dependency
@@ -62,12 +62,12 @@ dependencies:
62
62
  requirements:
63
63
  - - ">="
64
64
  - !ruby/object:Gem::Version
65
- hash: 21
65
+ hash: 41
66
66
  segments:
67
67
  - 2
68
- - 6
68
+ - 9
69
69
  - 1
70
- version: 2.6.1
70
+ version: 2.9.1
71
71
  type: :development
72
72
  version_requirements: *id002
73
73
  description: |-
@@ -91,7 +91,10 @@ files:
91
91
  - README.txt
92
92
  - Rakefile
93
93
  - lib/net/http/digest_auth.rb
94
+ - sample/auth_server.rb
95
+ - sample/net_http_example.rb
94
96
  - test/test_net_http_digest_auth.rb
97
+ - .gemtest
95
98
  has_rdoc: true
96
99
  homepage: http://seattlerb.rubyforge.org/net-http-digest_auth
97
100
  licenses: []
@@ -123,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
126
  requirements: []
124
127
 
125
128
  rubyforge_project: seattlerb
126
- rubygems_version: 1.3.7
129
+ rubygems_version: 1.6.2
127
130
  signing_key:
128
131
  specification_version: 3
129
132
  summary: An implementation of RFC 2617 - Digest Access Authentication
metadata.gz.sig CHANGED
@@ -1 +1,2 @@
1
- &��a����>�E]F��'�ؕ�A�Z��֗p��%#3�$ײ�����+�(��д~� ��B_i�p����]O@Z�h��_�?�~��P�����h���8��6���hڐ~H���s6�~3Ub
1
+ uP���$��6�Z�5IƎj��c�f��pgQ(�^`8q/i�+�;xv�߄����k��qGA2��� zC��CLD�j�Ī�s.�Z��&nqT֢��k�*�u= ~o��lς�?��h �����yj����bo�x]Z��y/�BXV.פz�: x-)����% ��rghr
2
+ �n 3�,2!D):ڣ;��Eۙ�~���t�YWo�&�]�T����f������/<Z!��(~Г!DŽ$$+��x