net-http-digest_auth 1.0 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
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