httpclient-jgraichen 2.3.4.2

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/README.txt +759 -0
  3. data/bin/httpclient +65 -0
  4. data/lib/hexdump.rb +50 -0
  5. data/lib/http-access2.rb +55 -0
  6. data/lib/http-access2/cookie.rb +1 -0
  7. data/lib/http-access2/http.rb +1 -0
  8. data/lib/httpclient.rb +1156 -0
  9. data/lib/httpclient/auth.rb +899 -0
  10. data/lib/httpclient/cacert.p7s +1912 -0
  11. data/lib/httpclient/connection.rb +88 -0
  12. data/lib/httpclient/cookie.rb +438 -0
  13. data/lib/httpclient/http.rb +1046 -0
  14. data/lib/httpclient/include_client.rb +83 -0
  15. data/lib/httpclient/session.rb +1028 -0
  16. data/lib/httpclient/ssl_config.rb +405 -0
  17. data/lib/httpclient/timeout.rb +140 -0
  18. data/lib/httpclient/util.rb +178 -0
  19. data/lib/httpclient/version.rb +3 -0
  20. data/lib/oauthclient.rb +110 -0
  21. data/sample/async.rb +8 -0
  22. data/sample/auth.rb +11 -0
  23. data/sample/cookie.rb +18 -0
  24. data/sample/dav.rb +103 -0
  25. data/sample/howto.rb +49 -0
  26. data/sample/oauth_buzz.rb +57 -0
  27. data/sample/oauth_friendfeed.rb +59 -0
  28. data/sample/oauth_twitter.rb +61 -0
  29. data/sample/ssl/0cert.pem +22 -0
  30. data/sample/ssl/0key.pem +30 -0
  31. data/sample/ssl/1000cert.pem +19 -0
  32. data/sample/ssl/1000key.pem +18 -0
  33. data/sample/ssl/htdocs/index.html +10 -0
  34. data/sample/ssl/ssl_client.rb +22 -0
  35. data/sample/ssl/webrick_httpsd.rb +29 -0
  36. data/sample/stream.rb +21 -0
  37. data/sample/thread.rb +27 -0
  38. data/sample/wcat.rb +21 -0
  39. data/test/ca-chain.cert +44 -0
  40. data/test/ca.cert +23 -0
  41. data/test/client.cert +19 -0
  42. data/test/client.key +15 -0
  43. data/test/helper.rb +129 -0
  44. data/test/htdigest +1 -0
  45. data/test/htpasswd +2 -0
  46. data/test/runner.rb +2 -0
  47. data/test/server.cert +19 -0
  48. data/test/server.key +15 -0
  49. data/test/sslsvr.rb +65 -0
  50. data/test/subca.cert +21 -0
  51. data/test/test_auth.rb +348 -0
  52. data/test/test_cookie.rb +412 -0
  53. data/test/test_hexdump.rb +14 -0
  54. data/test/test_http-access2.rb +507 -0
  55. data/test/test_httpclient.rb +1783 -0
  56. data/test/test_include_client.rb +52 -0
  57. data/test/test_ssl.rb +235 -0
  58. metadata +100 -0
@@ -0,0 +1,23 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIID0DCCArigAwIBAgIBADANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES
3
+ MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X
4
+ DTA0MDEzMDAwNDIzMloXDTM2MDEyMjAwNDIzMlowPDELMAkGA1UEBgwCSlAxEjAQ
5
+ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQswCQYDVQQDDAJDQTCCASIw
6
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANbv0x42BTKFEQOE+KJ2XmiSdZpR
7
+ wjzQLAkPLRnLB98tlzs4xo+y4RyY/rd5TT9UzBJTIhP8CJi5GbS1oXEerQXB3P0d
8
+ L5oSSMwGGyuIzgZe5+vZ1kgzQxMEKMMKlzA73rbMd4Jx3u5+jdbP0EDrPYfXSvLY
9
+ bS04n2aX7zrN3x5KdDrNBfwBio2/qeaaj4+9OxnwRvYP3WOvqdW0h329eMfHw0pi
10
+ JI0drIVdsEqClUV4pebT/F+CPUPkEh/weySgo9wANockkYu5ujw2GbLFcO5LXxxm
11
+ dEfcVr3r6t6zOA4bJwL0W/e6LBcrwiG/qPDFErhwtgTLYf6Er67SzLyA66UCAwEA
12
+ AaOB3DCB2TAPBgNVHRMBAf8EBTADAQH/MDEGCWCGSAGG+EIBDQQkFiJSdWJ5L09w
13
+ ZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRJ7Xd380KzBV7f
14
+ USKIQ+O/vKbhDzAOBgNVHQ8BAf8EBAMCAQYwZAYDVR0jBF0wW4AUSe13d/NCswVe
15
+ 31EiiEPjv7ym4Q+hQKQ+MDwxCzAJBgNVBAYMAkpQMRIwEAYDVQQKDAlKSU4uR1Iu
16
+ SlAxDDAKBgNVBAsMA1JSUjELMAkGA1UEAwwCQ0GCAQAwDQYJKoZIhvcNAQEFBQAD
17
+ ggEBAIu/mfiez5XN5tn2jScgShPgHEFJBR0BTJBZF6xCk0jyqNx/g9HMj2ELCuK+
18
+ r/Y7KFW5c5M3AQ+xWW0ZSc4kvzyTcV7yTVIwj2jZ9ddYMN3nupZFgBK1GB4Y05GY
19
+ MJJFRkSu6d/Ph5ypzBVw2YMT/nsOo5VwMUGLgS7YVjU+u/HNWz80J3oO17mNZllj
20
+ PvORJcnjwlroDnS58KoJ7GDgejv3ESWADvX1OHLE4cRkiQGeLoEU4pxdCxXRqX0U
21
+ PbwIkZN9mXVcrmPHq8MWi4eC/V7hnbZETMHuWhUoiNdOEfsAXr3iP4KjyyRdwc7a
22
+ d/xgcK06UVQRL/HbEYGiQL056mc=
23
+ -----END CERTIFICATE-----
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDKDCCAhCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES
3
+ MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X
4
+ DTA0MDEzMTAzMTQ1OFoXDTM1MDEyMzAzMTQ1OFowZTELMAkGA1UEBgwCSlAxEjAQ
5
+ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRAwDgYDVQQDDAdleGFtcGxl
6
+ MSIwIAYJKoZIhvcNAQkBDBNleGFtcGxlQGV4YW1wbGUub3JnMIGfMA0GCSqGSIb3
7
+ DQEBAQUAA4GNADCBiQKBgQDRWssrK8Gyr+500hpLjCGR3+AHL8/hEJM5zKi/MgLW
8
+ jTkvsgOwbYwXOiNtAbR9y4/ucDq7EY+cMUMHES4uFaPTcOaAV0aZRmk8AgslN1tQ
9
+ gNS6ew7/Luq3DcVeWkX8PYgR9VG0mD1MPfJ6+IFA5d3vKpdBkBgN4l46jjO0/2Xf
10
+ ewIDAQABo4GPMIGMMAwGA1UdEwEB/wQCMAAwMQYJYIZIAYb4QgENBCQWIlJ1Ynkv
11
+ T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFOFvay0H7lr2
12
+ xUx6waYEV2bVDYQhMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYI
13
+ KwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBABd2dYWqbDIWf5sWFvslezxJv8gI
14
+ w64KCJBuyJAiDuf+oazr3016kMzAlt97KecLZDusGNagPrq02UX7YMoQFsWJBans
15
+ cDtHrkM0al5r6/WGexNMgtYbNTYzt/IwodISGBgZ6dsOuhznwms+IBsTNDAvWeLP
16
+ lt2tOqD8kEmjwMgn0GDRuKjs4EoboA3kMULb1p9akDV9ZESU3eOtpS5/G5J5msLI
17
+ 9WXbYBjcjvkLuJH9VsJhb+R58Vl0ViemvAHhPilSl1SPWVunGhv6FcIkdBEi1k9F
18
+ e8BNMmsEjFiANiIRvpdLRbiGBt0KrKTndVfsmoKCvY48oCOvnzxtahFxfs8=
19
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICWwIBAAKBgQDRWssrK8Gyr+500hpLjCGR3+AHL8/hEJM5zKi/MgLWjTkvsgOw
3
+ bYwXOiNtAbR9y4/ucDq7EY+cMUMHES4uFaPTcOaAV0aZRmk8AgslN1tQgNS6ew7/
4
+ Luq3DcVeWkX8PYgR9VG0mD1MPfJ6+IFA5d3vKpdBkBgN4l46jjO0/2XfewIDAQAB
5
+ AoGAZcz8llWErtsV3QB9gNb3S/PNADGjqBFjReva8n3jG2k4sZSibpwWTwUaTNtT
6
+ ZQgjSRKRvH1hk9XwffNAvXAQZNNkuj/16gO2oO45nyLj4dO365ujLptWnVIWDHOE
7
+ uN0GeiZO+VzcCisT0WCq4tvtLeH8svrxzA8cbXIEyOK7NiECQQDwo2zPFyKAZ/Cu
8
+ lDJ6zKT+RjfWwW7DgWzirAlTrt4ViMaW+IaDH29TmQpb4V4NuR3Xi+2Xl4oicu6S
9
+ 36TW9+/FAkEA3rgfOQJuLlWSnw1RTGwvnC816a/W7iYYY7B+0U4cDbfWl7IoXT4y
10
+ M8nV/HESooviZLqBwzAYSoj3fFKYBKpGPwJAUO8GN5iWWA2dW3ooiDiv/X1sZmRk
11
+ dojfMFWgRW747tEzya8Ivq0h6kH8w+5GjeMG8Gn1nRiwsulo6Ckj7dEx6QJACyui
12
+ 7UIQ8qP6GZ4aYMHgVW4Mvy7Bkeo5OO7GPYs0Xv/EdJFL8vlGnVBXOjUVoS9w6Gpu
13
+ TbLg1QQvnX2rADjmEwJANxZO2GUkaWGsEif8aGW0x5g/IdaMGG27pTWk5zqix7P3
14
+ 1UDrdo/JOXhptovhRi06EppIxAxYmbh9vd9VN8Itlw==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,129 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'test/unit'
3
+ begin
4
+ require 'simplecov'
5
+ require 'simplecov-rcov'
6
+ SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
7
+ SimpleCov.start
8
+ rescue LoadError
9
+ end
10
+
11
+ require 'httpclient'
12
+ require 'webrick'
13
+ require 'webrick/httpproxy.rb'
14
+ require 'logger'
15
+ require 'stringio'
16
+ require 'cgi'
17
+ require 'webrick/httputils'
18
+
19
+
20
+ module Helper
21
+ Port = 17171
22
+ ProxyPort = 17172
23
+
24
+ def serverport
25
+ @serverport
26
+ end
27
+
28
+ def proxyport
29
+ @proxyport
30
+ end
31
+
32
+ def serverurl
33
+ "http://localhost:#{serverport}/"
34
+ end
35
+
36
+ def proxyurl
37
+ "http://localhost:#{proxyport}/"
38
+ end
39
+
40
+ def setup
41
+ @logger = Logger.new(STDERR)
42
+ @logger.level = Logger::Severity::FATAL
43
+ @proxyio = StringIO.new
44
+ @proxylogger = Logger.new(@proxyio)
45
+ @proxylogger.level = Logger::Severity::DEBUG
46
+ @server = @proxyserver = @client = nil
47
+ @server_thread = @proxyserver_thread = nil
48
+ @serverport = Port
49
+ @proxyport = ProxyPort
50
+ end
51
+
52
+ def teardown
53
+ teardown_client if @client
54
+ teardown_proxyserver if @proxyserver
55
+ teardown_server if @server
56
+ end
57
+
58
+ def setup_client
59
+ @client = HTTPClient.new
60
+ end
61
+
62
+ #def setup_server
63
+ # override it
64
+ # @server = WEBrick::HTTPServer.new(...)
65
+ # @server_thread = start_server_thread(@server)
66
+ #end
67
+
68
+ def setup_proxyserver
69
+ @proxyserver = WEBrick::HTTPProxyServer.new(
70
+ :BindAddress => "localhost",
71
+ :Logger => @proxylogger,
72
+ :Port => 0,
73
+ :AccessLog => []
74
+ )
75
+ @proxyport = @proxyserver.config[:Port]
76
+ @proxyserver_thread = start_server_thread(@proxyserver)
77
+ end
78
+
79
+ def teardown_client
80
+ @client.reset_all
81
+ end
82
+
83
+ def teardown_server
84
+ @server.shutdown
85
+ #@server_thread.kill
86
+ end
87
+
88
+ def teardown_proxyserver
89
+ @proxyserver.shutdown
90
+ #@proxyserver_thread.kill
91
+ end
92
+
93
+ def start_server_thread(server)
94
+ t = Thread.new {
95
+ Thread.current.abort_on_exception = true
96
+ server.start
97
+ }
98
+ while server.status != :Running
99
+ Thread.pass
100
+ unless t.alive?
101
+ t.join
102
+ raise
103
+ end
104
+ end
105
+ t
106
+ end
107
+
108
+ def params(str)
109
+ HTTP::Message.parse(str).inject({}) { |r, (k, v)| r[k] = v.first; r }
110
+ end
111
+
112
+ def silent
113
+ begin
114
+ back, $VERBOSE = $VERBOSE, nil
115
+ yield
116
+ ensure
117
+ $VERBOSE = back
118
+ end
119
+ end
120
+
121
+ def escape_env
122
+ env = {}
123
+ env.update(ENV)
124
+ yield
125
+ ensure
126
+ ENV.clear
127
+ ENV.update(env)
128
+ end
129
+ end
@@ -0,0 +1 @@
1
+ admin:auth:4302fe65caa32f27721949149ccd3083
@@ -0,0 +1,2 @@
1
+ admin:Qg266hq/YYKe2
2
+ guest:gbPc4vPCH.h12
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ exit Test::Unit::AutoRunner.run(true, File.dirname($0))
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIC/zCCAeegAwIBAgIBATANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQGDAJKUDES
3
+ MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxDjAMBgNVBAMMBVN1YkNB
4
+ MB4XDTA0MDEzMTAzMTMxNloXDTMzMDEyMzAzMTMxNlowQzELMAkGA1UEBgwCSlAx
5
+ EjAQBgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMRIwEAYDVQQDDAlsb2Nh
6
+ bGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANFJTxWqup3nV9dsJAku
7
+ p+WaXnPNIzcpAA3qMGZDJTJsfa8Du7ZxTP0XJK5mETttBrn711cJxAuP3KjqnW9S
8
+ vtZ9lY2sXJ6Zj62sN5LwG3VVe25dI28yR1EsbHjJ5Zjf9tmggMC6am52dxuHbt5/
9
+ vHo4ngJuKE/U+eeGRivMn6gFAgMBAAGjgYUwgYIwDAYDVR0TAQH/BAIwADAxBglg
10
+ hkgBhvhCAQ0EJBYiUnVieS9PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAd
11
+ BgNVHQ4EFgQUpZIyygD9JxFYHHOTEuWOLbCKfckwCwYDVR0PBAQDAgWgMBMGA1Ud
12
+ JQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQBwAIj5SaBHaA5X31IP
13
+ CFCJiep96awfp7RANO0cuUj+ZpGoFn9d6FXY0g+Eg5wAkCNIzZU5NHN9xsdOpnUo
14
+ zIBbyTfQEPrge1CMWMvL6uGaoEXytq84VTitF/xBTky4KtTn6+es4/e7jrrzeUXQ
15
+ RC46gkHObmDT91RkOEGjHLyld2328jo3DIN/VTHIryDeVHDWjY5dENwpwdkhhm60
16
+ DR9IrNBbXWEe9emtguNXeN0iu1ux0lG1Hc6pWGQxMlRKNvGh0yZB9u5EVe38tOV0
17
+ jQaoNyL7qzcQoXD3Dmbi1p0iRmg/+HngISsz8K7k7MBNVsSclztwgCzTZOBiVtkM
18
+ rRlQ
19
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICXQIBAAKBgQDRSU8Vqrqd51fXbCQJLqflml5zzSM3KQAN6jBmQyUybH2vA7u2
3
+ cUz9FySuZhE7bQa5+9dXCcQLj9yo6p1vUr7WfZWNrFyemY+trDeS8Bt1VXtuXSNv
4
+ MkdRLGx4yeWY3/bZoIDAumpudncbh27ef7x6OJ4CbihP1PnnhkYrzJ+oBQIDAQAB
5
+ AoGBAIf4CstW2ltQO7+XYGoex7Hh8s9lTSW/G2vu5Hbr1LTHy3fzAvdq8MvVR12O
6
+ rk9fa+lU9vhzPc0NMB0GIDZ9GcHuhW5hD1Wg9OSCbTOkZDoH3CAFqonjh4Qfwv5W
7
+ IPAFn9KHukdqGXkwEMdErsUaPTy9A1V/aROVEaAY+HJgq/eZAkEA/BP1QMV04WEZ
8
+ Oynzz7/lLizJGGxp2AOvEVtqMoycA/Qk+zdKP8ufE0wbmCE3Qd6GoynavsHb6aGK
9
+ gQobb8zDZwJBANSK6MrXlrZTtEaeZuyOB4mAmRzGzOUVkUyULUjEx2GDT93ujAma
10
+ qm/2d3E+wXAkNSeRpjUmlQXy/2oSqnGvYbMCQQDRM+cYyEcGPUVpWpnj0shrF/QU
11
+ 9vSot/X1G775EMTyaw6+BtbyNxVgOIu2J+rqGbn3c+b85XqTXOPL0A2RLYkFAkAm
12
+ syhSDtE9X55aoWsCNZY/vi+i4rvaFoQ/WleogVQAeGVpdo7/DK9t9YWoFBIqth0L
13
+ mGSYFu9ZhvZkvQNV8eYrAkBJ+rOIaLDsmbrgkeDruH+B/9yrm4McDtQ/rgnOGYnH
14
+ LjLpLLOrgUxqpzLWe++EwSLwK2//dHO+SPsQJ4xsyQJy
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,65 @@
1
+ require 'webrick/https'
2
+ require 'logger'
3
+ require 'rbconfig'
4
+
5
+ PORT = 17171
6
+ DIR = File.dirname(File.expand_path(__FILE__))
7
+
8
+ def cert(filename)
9
+ OpenSSL::X509::Certificate.new(File.open(File.join(DIR, filename)) { |f|
10
+ f.read
11
+ })
12
+ end
13
+
14
+ def key(filename)
15
+ OpenSSL::PKey::RSA.new(File.open(File.join(DIR, filename)) { |f|
16
+ f.read
17
+ })
18
+ end
19
+
20
+ def do_hello(req, res)
21
+ res['content-type'] = 'text/html'
22
+ res.body = "hello"
23
+ end
24
+
25
+ logger = Logger.new(STDERR)
26
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
27
+
28
+ server = WEBrick::HTTPServer.new(
29
+ :BindAddress => "localhost",
30
+ :Logger => logger,
31
+ :Port => PORT,
32
+ :AccessLog => [],
33
+ :DocumentRoot => DIR,
34
+ :SSLEnable => true,
35
+ :SSLCACertificateFile => File.join(DIR, 'ca.cert'),
36
+ :SSLCertificate => cert('server.cert'),
37
+ :SSLPrivateKey => key('server.key'),
38
+ :SSLVerifyClient => nil, #OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT|OpenSSL::SSL::VERIFY_PEER,
39
+ :SSLClientCA => cert('ca.cert'),
40
+ :SSLCertName => nil
41
+ )
42
+ trap(:INT) do
43
+ server.shutdown
44
+ end
45
+ [:hello].each do |sym|
46
+ server.mount(
47
+ "/#{sym}",
48
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
49
+ )
50
+ end
51
+
52
+ t = Thread.new {
53
+ Thread.current.abort_on_exception = true
54
+ server.start
55
+ }
56
+ while server.status != :Running
57
+ sleep 0.1
58
+ unless t.alive?
59
+ t.join
60
+ raise
61
+ end
62
+ end
63
+ STDOUT.sync = true
64
+ puts $$
65
+ t.join
@@ -0,0 +1,21 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDaDCCAlCgAwIBAgIBATANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGDAJKUDES
3
+ MBAGA1UECgwJSklOLkdSLkpQMQwwCgYDVQQLDANSUlIxCzAJBgNVBAMMAkNBMB4X
4
+ DTA0MDEzMDAwNDMyN1oXDTM1MDEyMjAwNDMyN1owPzELMAkGA1UEBgwCSlAxEjAQ
5
+ BgNVBAoMCUpJTi5HUi5KUDEMMAoGA1UECwwDUlJSMQ4wDAYDVQQDDAVTdWJDQTCC
6
+ ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0Ou7AyRcRXnB/kVHv/6kwe
7
+ ANzgg/DyJfsAUqW90m7Lu1nqyug8gK0RBd77yU0w5HOAMHTVSdpjZK0g2sgx4Mb1
8
+ d/213eL9TTl5MRVEChTvQr8q5DVG/8fxPPE7fMI8eOAzd98/NOAChk+80r4Sx7fC
9
+ kGVEE1bKwY1MrUsUNjOY2d6t3M4HHV3HX1V8ShuKfsHxgCmLzdI8U+5CnQedFgkm
10
+ 3e+8tr8IX5RR1wA1Ifw9VadF7OdI/bGMzog/Q8XCLf+WPFjnK7Gcx6JFtzF6Gi4x
11
+ 4dp1Xl45JYiVvi9zQ132wu8A1pDHhiNgQviyzbP+UjcB/tsOpzBQF8abYzgEkWEC
12
+ AwEAAaNyMHAwDwYDVR0TAQH/BAUwAwEB/zAxBglghkgBhvhCAQ0EJBYiUnVieS9P
13
+ cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUlCjXWLsReYzH
14
+ LzsxwVnCXmKoB/owCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCJ/OyN
15
+ rT8Cq2Y+G2yA/L1EMRvvxwFBqxavqaqHl/6rwsIBFlB3zbqGA/0oec6MAVnYynq4
16
+ c4AcHTjx3bQ/S4r2sNTZq0DH4SYbQzIobx/YW8PjQUJt8KQdKMcwwi7arHP7A/Ha
17
+ LKu8eIC2nsUBnP4NhkYSGhbmpJK+PFD0FVtD0ZIRlY/wsnaZNjWWcnWF1/FNuQ4H
18
+ ySjIblqVQkPuzebv3Ror6ZnVDukn96Mg7kP4u6zgxOeqlJGRe1M949SS9Vudjl8X
19
+ SF4aZUUB9pQGhsqQJVqaz2OlhGOp9D0q54xko/rekjAIcuDjl1mdX4F2WRrzpUmZ
20
+ uY/bPeOBYiVsOYVe
21
+ -----END CERTIFICATE-----
@@ -0,0 +1,348 @@
1
+ require File.expand_path('helper', File.dirname(__FILE__))
2
+ require 'digest/md5'
3
+ require 'rack'
4
+ require 'rack/lint'
5
+ require 'rack/showexceptions'
6
+ require 'rack-ntlm'
7
+
8
+ class TestAuth < Test::Unit::TestCase
9
+ include Helper
10
+
11
+ def setup
12
+ super
13
+ setup_server
14
+ end
15
+
16
+ def teardown
17
+ super
18
+ end
19
+
20
+ def setup_server
21
+ @server = WEBrick::HTTPServer.new(
22
+ :BindAddress => "localhost",
23
+ :Logger => @logger,
24
+ :Port => 0,
25
+ :AccessLog => [],
26
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__))
27
+ )
28
+ @serverport = @server.config[:Port]
29
+ @server.mount(
30
+ '/basic_auth',
31
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_basic_auth).to_proc)
32
+ )
33
+ @server.mount(
34
+ '/digest_auth',
35
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_digest_auth).to_proc)
36
+ )
37
+ @server.mount(
38
+ '/digest_sess_auth',
39
+ WEBrick::HTTPServlet::ProcHandler.new(method(:do_digest_sess_auth).to_proc)
40
+ )
41
+ # NTLM endpoint
42
+ ntlm_handler = Rack::Handler::WEBrick.new(@server,
43
+ Rack::Builder.app do
44
+ use Rack::ShowExceptions
45
+ use Rack::ContentLength
46
+ use Rack::Ntlm, {:uri_pattern => /.*/, :auth => {:username => "admin", :password => "admin"}}
47
+ run lambda { |env| [200, { 'Content-Type' => 'text/html' }, ['ntlm_auth OK']] }
48
+ end
49
+ )
50
+ @server.mount(
51
+ '/ntlm_auth',
52
+ WEBrick::HTTPServlet::ProcHandler.new(Proc.new do |req, res|
53
+ ntlm_handler.service(req, res)
54
+ end)
55
+ )
56
+ # Htpasswd
57
+ htpasswd = File.join(File.dirname(__FILE__), 'htpasswd')
58
+ htpasswd_userdb = WEBrick::HTTPAuth::Htpasswd.new(htpasswd)
59
+ htdigest = File.join(File.dirname(__FILE__), 'htdigest')
60
+ htdigest_userdb = WEBrick::HTTPAuth::Htdigest.new(htdigest)
61
+ @basic_auth = WEBrick::HTTPAuth::BasicAuth.new(
62
+ :Logger => @logger,
63
+ :Realm => 'auth',
64
+ :UserDB => htpasswd_userdb
65
+ )
66
+ @digest_auth = WEBrick::HTTPAuth::DigestAuth.new(
67
+ :Logger => @logger,
68
+ :Algorithm => 'MD5',
69
+ :Realm => 'auth',
70
+ :UserDB => htdigest_userdb
71
+ )
72
+ @digest_sess_auth = WEBrick::HTTPAuth::DigestAuth.new(
73
+ :Logger => @logger,
74
+ :Algorithm => 'MD5-sess',
75
+ :Realm => 'auth',
76
+ :UserDB => htdigest_userdb
77
+ )
78
+ @server_thread = start_server_thread(@server)
79
+
80
+ @proxy_digest_auth = WEBrick::HTTPAuth::ProxyDigestAuth.new(
81
+ :Logger => @proxylogger,
82
+ :Algorithm => 'MD5',
83
+ :Realm => 'auth',
84
+ :UserDB => htdigest_userdb
85
+ )
86
+
87
+ @proxyserver = WEBrick::HTTPProxyServer.new(
88
+ :ProxyAuthProc => @proxy_digest_auth.method(:authenticate).to_proc,
89
+ :BindAddress => "localhost",
90
+ :Logger => @proxylogger,
91
+ :Port => 0,
92
+ :AccessLog => []
93
+ )
94
+ @proxyport = @proxyserver.config[:Port]
95
+ @proxyserver_thread = start_server_thread(@proxyserver)
96
+ end
97
+
98
+ def do_basic_auth(req, res)
99
+ @basic_auth.authenticate(req, res)
100
+ res['content-type'] = 'text/plain'
101
+ res.body = 'basic_auth OK'
102
+ end
103
+
104
+ def do_digest_auth(req, res)
105
+ @digest_auth.authenticate(req, res)
106
+ res['content-type'] = 'text/plain'
107
+ res['x-query'] = req.body
108
+ res.body = 'digest_auth OK' + req.query_string.to_s
109
+ end
110
+
111
+ def do_digest_sess_auth(req, res)
112
+ @digest_sess_auth.authenticate(req, res)
113
+ res['content-type'] = 'text/plain'
114
+ res['x-query'] = req.body
115
+ res.body = 'digest_sess_auth OK' + req.query_string.to_s
116
+ end
117
+
118
+ def test_ntlm_auth
119
+ c = HTTPClient.new
120
+ c.set_auth("http://localhost:#{serverport}/ntlm_auth", 'admin', 'admin')
121
+ assert_equal('ntlm_auth OK', c.get_content("http://localhost:#{serverport}/ntlm_auth"))
122
+ puts c.inspect
123
+ end
124
+
125
+ def test_basic_auth
126
+ c = HTTPClient.new
127
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
128
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
129
+ end
130
+
131
+ def test_basic_auth_compat
132
+ c = HTTPClient.new
133
+ c.set_basic_auth("http://localhost:#{serverport}/", 'admin', 'admin')
134
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
135
+ end
136
+
137
+ def test_BASIC_auth
138
+ c = HTTPClient.new
139
+ webrick_backup = @basic_auth.instance_eval { @auth_scheme }
140
+ #httpaccess2_backup = c.www_auth.basic_auth.instance_eval { @scheme }
141
+ begin
142
+ @basic_auth.instance_eval { @auth_scheme = "BASIC" }
143
+ c.www_auth.basic_auth.instance_eval { @scheme = "BASIC" }
144
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
145
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth"))
146
+ ensure
147
+ @basic_auth.instance_eval { @auth_scheme = webrick_backup }
148
+ #c.www_auth.basic_auth.instance_eval { @scheme = httpaccess2_backup }
149
+ end
150
+ end
151
+
152
+ def test_basic_auth_reuses_credentials
153
+ c = HTTPClient.new
154
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
155
+ assert_equal('basic_auth OK', c.get_content("http://localhost:#{serverport}/basic_auth/"))
156
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
157
+ c.debug_dev = str = ''
158
+ c.get_content("http://localhost:#{serverport}/basic_auth/sub/dir/")
159
+ assert_match /Authorization: Basic YWRtaW46YWRtaW4=/, str
160
+ end
161
+
162
+ def test_digest_auth
163
+ c = HTTPClient.new
164
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
165
+ assert_equal('digest_auth OK', c.get_content("http://localhost:#{serverport}/digest_auth"))
166
+ end
167
+
168
+ def test_digest_auth_reuses_credentials
169
+ c = HTTPClient.new
170
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
171
+ assert_equal('digest_auth OK', c.get_content("http://localhost:#{serverport}/digest_auth/"))
172
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
173
+ c.debug_dev = str = ''
174
+ c.get_content("http://localhost:#{serverport}/digest_auth/sub/dir/")
175
+ assert_match /Authorization: Digest/, str
176
+ end
177
+
178
+ def test_digest_auth_with_block
179
+ c = HTTPClient.new
180
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
181
+ called = false
182
+ c.get_content("http://localhost:#{serverport}/digest_auth") do |str|
183
+ assert_equal('digest_auth OK', str)
184
+ called = true
185
+ end
186
+ assert(called)
187
+ #
188
+ called = false
189
+ c.get("http://localhost:#{serverport}/digest_auth") do |str|
190
+ assert_equal('digest_auth OK', str)
191
+ called = true
192
+ end
193
+ assert(called)
194
+ end
195
+
196
+ def test_digest_auth_with_post_io
197
+ c = HTTPClient.new
198
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
199
+ post_body = StringIO.new("1234567890")
200
+ assert_equal('1234567890', c.post("http://localhost:#{serverport}/digest_auth", post_body).header['x-query'][0])
201
+ #
202
+ post_body = StringIO.new("1234567890")
203
+ post_body.read(5)
204
+ assert_equal('67890', c.post("http://localhost:#{serverport}/digest_auth", post_body).header['x-query'][0])
205
+ end
206
+
207
+ def test_digest_auth_with_querystring
208
+ c = HTTPClient.new
209
+ c.debug_dev = STDERR if $DEBUG
210
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
211
+ assert_equal('digest_auth OKbar=baz', c.get_content("http://localhost:#{serverport}/digest_auth/foo?bar=baz"))
212
+ end
213
+
214
+ def test_perfer_digest
215
+ c = HTTPClient.new
216
+ c.set_auth('http://example.com/', 'admin', 'admin')
217
+ c.test_loopback_http_response << "HTTP/1.0 401 Unauthorized\nWWW-Authenticate: Basic realm=\"foo\"\nWWW-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
218
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
219
+ c.debug_dev = str = ''
220
+ c.get_content('http://example.com/')
221
+ assert_match(/^Authorization: Digest/, str)
222
+ end
223
+
224
+ def test_digest_sess_auth
225
+ c = HTTPClient.new
226
+ c.set_auth("http://localhost:#{serverport}/", 'admin', 'admin')
227
+ assert_equal('digest_sess_auth OK', c.get_content("http://localhost:#{serverport}/digest_sess_auth"))
228
+ end
229
+
230
+ def test_proxy_auth
231
+ c = HTTPClient.new
232
+ c.set_proxy_auth('admin', 'admin')
233
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Basic realm=\"foo\"\nContent-Length: 2\n\nNG"
234
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
235
+ c.debug_dev = str = ''
236
+ c.get_content('http://example.com/')
237
+ assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
238
+ end
239
+
240
+ def test_proxy_auth_reuses_credentials
241
+ c = HTTPClient.new
242
+ c.set_proxy_auth('admin', 'admin')
243
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Basic realm=\"foo\"\nContent-Length: 2\n\nNG"
244
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
245
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
246
+ c.get_content('http://www1.example.com/')
247
+ c.debug_dev = str = ''
248
+ c.get_content('http://www2.example.com/')
249
+ assert_match(/Proxy-Authorization: Basic YWRtaW46YWRtaW4=/, str)
250
+ end
251
+
252
+ def test_digest_proxy_auth_loop
253
+ c = HTTPClient.new
254
+ c.set_proxy_auth('admin', 'admin')
255
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
256
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
257
+ md5 = Digest::MD5.new
258
+ ha1 = md5.hexdigest("admin:foo:admin")
259
+ ha2 = md5.hexdigest("GET:/")
260
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
261
+ c.debug_dev = str = ''
262
+ c.get_content('http://example.com/')
263
+ assert_match(/Proxy-Authorization: Digest/, str)
264
+ assert_match(%r"response=\"#{response}\"", str)
265
+ end
266
+
267
+ def test_digest_proxy_auth
268
+ c=HTTPClient.new("http://localhost:#{proxyport}/")
269
+ c.set_proxy_auth('admin', 'admin')
270
+ c.set_auth("http://127.0.0.1:#{serverport}/", 'admin', 'admin')
271
+ assert_equal('basic_auth OK', c.get_content("http://127.0.0.1:#{serverport}/basic_auth"))
272
+ end
273
+
274
+ def test_digest_proxy_invalid_auth
275
+ c=HTTPClient.new("http://localhost:#{proxyport}/")
276
+ c.set_proxy_auth('admin', 'wrong')
277
+ c.set_auth("http://127.0.0.1:#{serverport}/", 'admin', 'admin')
278
+ assert_raises(HTTPClient::BadResponseError) do
279
+ c.get_content("http://127.0.0.1:#{serverport}/basic_auth")
280
+ end
281
+ end
282
+
283
+ def test_prefer_digest_to_basic_proxy_auth
284
+ c = HTTPClient.new
285
+ c.set_proxy_auth('admin', 'admin')
286
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nProxy-Authenticate: Basic realm=\"bar\"\nContent-Length: 2\n\nNG"
287
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
288
+ md5 = Digest::MD5.new
289
+ ha1 = md5.hexdigest("admin:foo:admin")
290
+ ha2 = md5.hexdigest("GET:/")
291
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
292
+ c.debug_dev = str = ''
293
+ c.get_content('http://example.com/')
294
+ assert_match(/Proxy-Authorization: Digest/, str)
295
+ assert_match(%r"response=\"#{response}\"", str)
296
+ end
297
+
298
+ def test_digest_proxy_auth_reuses_credentials
299
+ c = HTTPClient.new
300
+ c.set_proxy_auth('admin', 'admin')
301
+ c.test_loopback_http_response << "HTTP/1.0 407 Unauthorized\nProxy-Authenticate: Digest realm=\"foo\", nonce=\"nonce\", stale=false\nContent-Length: 2\n\nNG"
302
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
303
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
304
+ md5 = Digest::MD5.new
305
+ ha1 = md5.hexdigest("admin:foo:admin")
306
+ ha2 = md5.hexdigest("GET:/")
307
+ response = md5.hexdigest("#{ha1}:nonce:#{ha2}")
308
+ c.get_content('http://www1.example.com/')
309
+ c.debug_dev = str = ''
310
+ c.get_content('http://www2.example.com/')
311
+ assert_match(/Proxy-Authorization: Digest/, str)
312
+ assert_match(%r"response=\"#{response}\"", str)
313
+ end
314
+
315
+ def test_oauth
316
+ c = HTTPClient.new
317
+ config = HTTPClient::OAuth::Config.new(
318
+ :realm => 'http://photos.example.net/',
319
+ :consumer_key => 'dpf43f3p2l4k3l03',
320
+ :consumer_secret => 'kd94hf93k423kf44',
321
+ :token => 'nnch734d00sl2jdk',
322
+ :secret => 'pfkkdhi9sl3r4s00',
323
+ :version => '1.0',
324
+ :signature_method => 'HMAC-SHA1'
325
+ )
326
+ config.debug_timestamp = '1191242096'
327
+ config.debug_nonce = 'kllo9940pd9333jh'
328
+ c.www_auth.oauth.set_config('http://photos.example.net/', config)
329
+ c.www_auth.oauth.challenge('http://photos.example.net/')
330
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
331
+ c.debug_dev = str = ''
332
+ c.get_content('http://photos.example.net/photos', [[:file, 'vacation.jpg'], [:size, 'original']])
333
+ assert(str.index(%q(GET /photos?file=vacation.jpg&size=original)))
334
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
335
+ #
336
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
337
+ c.debug_dev = str = ''
338
+ c.get_content('http://photos.example.net/photos?file=vacation.jpg&size=original')
339
+ assert(str.index(%q(GET /photos?file=vacation.jpg&size=original)))
340
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
341
+ #
342
+ c.test_loopback_http_response << "HTTP/1.0 200 OK\nContent-Length: 2\n\nOK"
343
+ c.debug_dev = str = ''
344
+ c.post_content('http://photos.example.net/photos', [[:file, 'vacation.jpg'], [:size, 'original']])
345
+ assert(str.index(%q(POST /photos)))
346
+ assert(str.index(%q(Authorization: OAuth realm="http://photos.example.net/", oauth_consumer_key="dpf43f3p2l4k3l03", oauth_nonce="kllo9940pd9333jh", oauth_signature="wPkvxykrw%2BBTdCcGqKr%2B3I%2BPsiM%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1191242096", oauth_token="nnch734d00sl2jdk", oauth_version="1.0")))
347
+ end
348
+ end