raptor-io 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE +30 -0
- data/README.md +51 -0
- data/lib/rack/handler/raptor-io.rb +130 -0
- data/lib/raptor-io.rb +11 -0
- data/lib/raptor-io/error.rb +19 -0
- data/lib/raptor-io/protocol.rb +6 -0
- data/lib/raptor-io/protocol/error.rb +10 -0
- data/lib/raptor-io/protocol/http.rb +34 -0
- data/lib/raptor-io/protocol/http/client.rb +685 -0
- data/lib/raptor-io/protocol/http/error.rb +16 -0
- data/lib/raptor-io/protocol/http/headers.rb +132 -0
- data/lib/raptor-io/protocol/http/message.rb +67 -0
- data/lib/raptor-io/protocol/http/request.rb +307 -0
- data/lib/raptor-io/protocol/http/request/manipulator.rb +117 -0
- data/lib/raptor-io/protocol/http/request/manipulators.rb +217 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticator.rb +110 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/basic.rb +36 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/digest.rb +135 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/negotiate.rb +69 -0
- data/lib/raptor-io/protocol/http/request/manipulators/authenticators/ntlm.rb +29 -0
- data/lib/raptor-io/protocol/http/request/manipulators/redirect_follower.rb +65 -0
- data/lib/raptor-io/protocol/http/response.rb +166 -0
- data/lib/raptor-io/protocol/http/server.rb +446 -0
- data/lib/raptor-io/ruby.rb +4 -0
- data/lib/raptor-io/ruby/hash.rb +24 -0
- data/lib/raptor-io/ruby/ipaddr.rb +15 -0
- data/lib/raptor-io/ruby/openssl.rb +23 -0
- data/lib/raptor-io/ruby/string.rb +27 -0
- data/lib/raptor-io/socket.rb +175 -0
- data/lib/raptor-io/socket/comm.rb +143 -0
- data/lib/raptor-io/socket/comm/local.rb +94 -0
- data/lib/raptor-io/socket/comm/sapni.rb +75 -0
- data/lib/raptor-io/socket/comm/socks.rb +237 -0
- data/lib/raptor-io/socket/comm_chain.rb +30 -0
- data/lib/raptor-io/socket/error.rb +45 -0
- data/lib/raptor-io/socket/switch_board.rb +183 -0
- data/lib/raptor-io/socket/switch_board/route.rb +42 -0
- data/lib/raptor-io/socket/tcp.rb +231 -0
- data/lib/raptor-io/socket/tcp/ssl.rb +77 -0
- data/lib/raptor-io/socket/tcp_server.rb +16 -0
- data/lib/raptor-io/socket/tcp_server/ssl.rb +52 -0
- data/lib/raptor-io/socket/udp.rb +0 -0
- data/lib/raptor-io/version.rb +6 -0
- data/lib/tasks/yard.rake +26 -0
- data/spec/rack/handler/raptor_spec.rb +140 -0
- data/spec/raptor-io/protocol/http/client_spec.rb +671 -0
- data/spec/raptor-io/protocol/http/headers_spec.rb +189 -0
- data/spec/raptor-io/protocol/http/message_spec.rb +5 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticator_spec.rb +193 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/basic_spec.rb +32 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/digest_spec.rb +76 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/negotiate_spec.rb +52 -0
- data/spec/raptor-io/protocol/http/request/manipulators/authenticators/ntlm_spec.rb +37 -0
- data/spec/raptor-io/protocol/http/request/manipulators/redirect_follower_spec.rb +51 -0
- data/spec/raptor-io/protocol/http/request/manipulators_spec.rb +202 -0
- data/spec/raptor-io/protocol/http/request_spec.rb +965 -0
- data/spec/raptor-io/protocol/http/response_spec.rb +236 -0
- data/spec/raptor-io/protocol/http/server_spec.rb +345 -0
- data/spec/raptor-io/ruby/hash_spec.rb +20 -0
- data/spec/raptor-io/ruby/string_spec.rb +20 -0
- data/spec/raptor-io/socket/comm/local_spec.rb +50 -0
- data/spec/raptor-io/socket/switch_board/route_spec.rb +49 -0
- data/spec/raptor-io/socket/switch_board_spec.rb +87 -0
- data/spec/raptor-io/socket/tcp/ssl_spec.rb +18 -0
- data/spec/raptor-io/socket/tcp_server/ssl_spec.rb +59 -0
- data/spec/raptor-io/socket/tcp_server_spec.rb +19 -0
- data/spec/raptor-io/socket/tcp_spec.rb +14 -0
- data/spec/raptor-io/socket_spec.rb +16 -0
- data/spec/raptor-io/version_spec.rb +10 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/manifoolators/fooer.rb +25 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/niccolo_machiavelli.rb +20 -0
- data/spec/support/fixtures/raptor/protocol/http/request/manipulators/options_validator.rb +28 -0
- data/spec/support/fixtures/raptor/socket/ssl_server.crt +18 -0
- data/spec/support/fixtures/raptor/socket/ssl_server.key +15 -0
- data/spec/support/lib/path_helpers.rb +11 -0
- data/spec/support/lib/webserver_option_parser.rb +26 -0
- data/spec/support/lib/webservers.rb +120 -0
- data/spec/support/shared/contexts/with_ssl_server.rb +70 -0
- data/spec/support/shared/contexts/with_tcp_server.rb +58 -0
- data/spec/support/shared/examples/raptor/comm_examples.rb +26 -0
- data/spec/support/shared/examples/raptor/protocols/http/message.rb +106 -0
- data/spec/support/shared/examples/raptor/socket_examples.rb +135 -0
- data/spec/support/webservers/raptor/protocols/http/client.rb +100 -0
- data/spec/support/webservers/raptor/protocols/http/client_close_connection.rb +29 -0
- data/spec/support/webservers/raptor/protocols/http/client_https.rb +43 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/basic.rb +9 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/authenticators/digest.rb +22 -0
- data/spec/support/webservers/raptor/protocols/http/request/manipulators/redirect_follower.rb +11 -0
- metadata +336 -0
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RaptorIO::Protocol::HTTP::Headers do
|
4
|
+
|
5
|
+
describe '#to_s' do
|
6
|
+
it 'supports multiple headers' do
|
7
|
+
headers = described_class.new( 'X-Stuff' => %w(1 2 3) )
|
8
|
+
headers.to_s.should == "X-Stuff: 1\r\nX-Stuff: 2\r\nX-Stuff: 3"
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'formats headers for HTTP transmission' do
|
12
|
+
options = {
|
13
|
+
'x-morE-stUfF' => 'blah'
|
14
|
+
}
|
15
|
+
described_class.new( options ).to_s.should ==
|
16
|
+
"X-More-Stuff: blah"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#delete' do
|
21
|
+
it 'deleted a header field' do
|
22
|
+
h = described_class.new( 'x-my-field' => 'stuff' )
|
23
|
+
h.delete( 'X-My-Field' ).should == 'stuff'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#include?' do
|
28
|
+
context 'when the field is included' do
|
29
|
+
it 'returns true' do
|
30
|
+
h = described_class.new( 'X-My-Field' => 'stuff' )
|
31
|
+
h.include?( 'x-my-field' ).should be_true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
context 'when the field is not included' do
|
35
|
+
it 'returns false' do
|
36
|
+
described_class.new.include?( 'x-my-field' ).should be_false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#set_cookie' do
|
42
|
+
context 'when there are no set-cookie fields' do
|
43
|
+
it 'returns an empty array' do
|
44
|
+
described_class.new.cookies.should == []
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns an array of set-cookie strings' do
|
49
|
+
set_coookies = [
|
50
|
+
'name=value; Expires=Wed, 09 Jun 2020 10:18:14 GMT',
|
51
|
+
'name2=value2; Expires=Wed, 09 Jun 2021 10:18:14 GMT'
|
52
|
+
]
|
53
|
+
|
54
|
+
described_class.new( 'Set-Cookie' => set_coookies ).set_cookie.should == set_coookies
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#parsed_set_cookie' do
|
59
|
+
context 'when there are no Set-cookie fields' do
|
60
|
+
it 'returns an empty array' do
|
61
|
+
described_class.new.parsed_set_cookie.should == []
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns an array of cookies as hashes' do
|
66
|
+
described_class.new(
|
67
|
+
'Set-Cookie' => [
|
68
|
+
'name=value; Expires=Wed, 09 Jun 2020 10:18:14 GMT',
|
69
|
+
'name2=value2; Expires=Wed, 09 Jun 2021 10:18:14 GMT'
|
70
|
+
]
|
71
|
+
).parsed_set_cookie.should == [
|
72
|
+
{
|
73
|
+
name: 'name',
|
74
|
+
value: 'value',
|
75
|
+
version: 0,
|
76
|
+
port: nil,
|
77
|
+
discard: nil,
|
78
|
+
comment_url: nil,
|
79
|
+
expires: Time.parse( '2020-06-09 13:18:14 +0300' ),
|
80
|
+
max_age: nil,
|
81
|
+
comment: nil,
|
82
|
+
secure: nil,
|
83
|
+
path: nil,
|
84
|
+
domain: nil
|
85
|
+
},
|
86
|
+
{
|
87
|
+
name: 'name2',
|
88
|
+
value: 'value2',
|
89
|
+
version: 0,
|
90
|
+
port: nil,
|
91
|
+
discard: nil,
|
92
|
+
comment_url: nil,
|
93
|
+
expires: Time.parse( '2021-06-09 13:18:14 +0300' ),
|
94
|
+
max_age: nil,
|
95
|
+
comment: nil,
|
96
|
+
secure: nil,
|
97
|
+
path: nil,
|
98
|
+
domain: nil
|
99
|
+
}
|
100
|
+
]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#cookies' do
|
105
|
+
context 'when there is no Cookie fied' do
|
106
|
+
it 'returns an empty array' do
|
107
|
+
described_class.new.cookies.should == []
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'returns an array of cookies as hashes' do
|
112
|
+
described_class.new(
|
113
|
+
'Cookie' => 'cname=cvalue; c2name=c2value'
|
114
|
+
).cookies.should == [
|
115
|
+
{
|
116
|
+
name: 'cname',
|
117
|
+
value: 'cvalue',
|
118
|
+
version: 0,
|
119
|
+
port: nil,
|
120
|
+
discard: nil,
|
121
|
+
comment_url: nil,
|
122
|
+
expires: nil,
|
123
|
+
max_age: nil,
|
124
|
+
comment: nil,
|
125
|
+
secure: nil,
|
126
|
+
path: nil,
|
127
|
+
domain: nil
|
128
|
+
},
|
129
|
+
{
|
130
|
+
name: 'c2name',
|
131
|
+
value: 'c2value',
|
132
|
+
version: 0,
|
133
|
+
port: nil,
|
134
|
+
discard: nil,
|
135
|
+
comment_url: nil,
|
136
|
+
expires: nil,
|
137
|
+
max_age: nil,
|
138
|
+
comment: nil,
|
139
|
+
secure: nil,
|
140
|
+
path: nil,
|
141
|
+
domain: nil
|
142
|
+
}
|
143
|
+
]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '.parse' do
|
148
|
+
context 'when passed an empty string' do
|
149
|
+
it 'returns empty Headers' do
|
150
|
+
described_class.parse( '' ).should be_empty
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'supports multiple headers' do
|
155
|
+
headers_string = "X-Stuff: 1\r\nX-Stuff: 2\r\n\r\n"
|
156
|
+
|
157
|
+
headers = described_class.parse( headers_string )
|
158
|
+
headers['x-stuff'].should == %w(1 2)
|
159
|
+
headers.class.should == described_class
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'supports CRLF terminators' do
|
163
|
+
headers_string = "content-Type: text/html;charset=utf-8\r\n" +
|
164
|
+
"Content-length: 431\r\n\r\n"
|
165
|
+
|
166
|
+
headers = described_class.parse( headers_string )
|
167
|
+
headers.should ==
|
168
|
+
{
|
169
|
+
'Content-Type' => 'text/html;charset=utf-8',
|
170
|
+
'Content-Length' => '431'
|
171
|
+
}
|
172
|
+
headers.class.should == described_class
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'supports CR terminators' do
|
176
|
+
headers_string = "content-Type: text/html;charset=utf-8\n" +
|
177
|
+
"Content-length: 431\n\n"
|
178
|
+
|
179
|
+
headers = described_class.parse( headers_string )
|
180
|
+
headers.should ==
|
181
|
+
{
|
182
|
+
'Content-Type' => 'text/html;charset=utf-8',
|
183
|
+
'Content-Length' => '431'
|
184
|
+
}
|
185
|
+
headers.class.should == described_class
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'RaptorIO::Protocol::HTTP::Request::Manipulators::Authenticator' do
|
4
|
+
before :all do
|
5
|
+
WebServers.start :basic
|
6
|
+
@basic_url = WebServers.url_for( :basic )
|
7
|
+
|
8
|
+
WebServers.start :digest
|
9
|
+
@digest_url = WebServers.url_for( :digest )
|
10
|
+
|
11
|
+
@iis_address = ENV['IIS']
|
12
|
+
@ntlm_url = "http://#{@iis_address}/ntlm/"
|
13
|
+
@negotiate_url = "http://#{@iis_address}/negotiate/"
|
14
|
+
end
|
15
|
+
|
16
|
+
before( :each ) do
|
17
|
+
RaptorIO::Protocol::HTTP::Request::Manipulators.reset
|
18
|
+
RaptorIO::Protocol::HTTP::Client.reset
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
let(:client) do
|
23
|
+
RaptorIO::Protocol::HTTP::Client.new(
|
24
|
+
switch_board: RaptorIO::Socket::SwitchBoard.new,
|
25
|
+
manipulators: {
|
26
|
+
'authenticator' =>
|
27
|
+
{
|
28
|
+
username: 'admin',
|
29
|
+
password: 'secret'
|
30
|
+
}
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when authentication is of type' do
|
36
|
+
context 'Basic' do
|
37
|
+
it 'provides Basic authentication' do
|
38
|
+
opts = { mode: :sync }
|
39
|
+
2.times do
|
40
|
+
client.get( @basic_url, opts ).code.should == 200
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'Digest' do
|
46
|
+
it 'provides Digest authentication' do
|
47
|
+
opts = { mode: :sync }
|
48
|
+
|
49
|
+
2.times do
|
50
|
+
client.get( @digest_url, opts ).code.should == 200
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'doesn\'t run any queued request until the auth finishes' do
|
55
|
+
cnt = 0
|
56
|
+
|
57
|
+
50.times do |i|
|
58
|
+
client.get( @digest_url ) do |response|
|
59
|
+
response.code.should == 200
|
60
|
+
cnt += 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
client.run
|
65
|
+
client.datastore['authenticator'][:tries].should == 1
|
66
|
+
cnt.should == 50
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'Negotiate' do
|
71
|
+
let(:client) do
|
72
|
+
RaptorIO::Protocol::HTTP::Client.new(
|
73
|
+
manipulators: {
|
74
|
+
'authenticator' =>
|
75
|
+
{
|
76
|
+
username: 'msfadmin',
|
77
|
+
password: 'msfadmin'
|
78
|
+
}
|
79
|
+
}
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'provides Negotiate authentication' do
|
84
|
+
pending if !ENV['IIS']
|
85
|
+
|
86
|
+
opts = { mode: :sync }
|
87
|
+
|
88
|
+
2.times do
|
89
|
+
client.get( @negotiate_url, opts ).code.should == 200
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'doesn\'t run any queued request until the auth finishes' do
|
94
|
+
pending if !ENV['IIS']
|
95
|
+
|
96
|
+
cnt = 0
|
97
|
+
|
98
|
+
50.times do |i|
|
99
|
+
client.get( @negotiate_url ) do |response|
|
100
|
+
response.code.should == 200
|
101
|
+
cnt += 1
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
client.run
|
106
|
+
cnt.should == 50
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'on wrong credentials' do
|
110
|
+
it 'returns a 401' do
|
111
|
+
pending if !ENV['IIS']
|
112
|
+
|
113
|
+
opts = {
|
114
|
+
mode: :sync, manipulators: {
|
115
|
+
'authenticator' =>
|
116
|
+
{
|
117
|
+
username: 'blah',
|
118
|
+
password: 'blah'
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
2.times do
|
124
|
+
client.get( @negotiate_url, opts ).code.should == 401
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'NTLM' do
|
131
|
+
let(:client) do
|
132
|
+
RaptorIO::Protocol::HTTP::Client.new(
|
133
|
+
manipulators: {
|
134
|
+
'authenticator' =>
|
135
|
+
{
|
136
|
+
username: 'msfadmin',
|
137
|
+
password: 'msfadmin'
|
138
|
+
}
|
139
|
+
}
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'provides NTLM authentication' do
|
144
|
+
pending if !ENV['IIS']
|
145
|
+
|
146
|
+
opts = { mode: :sync }
|
147
|
+
|
148
|
+
2.times do
|
149
|
+
client.get( @ntlm_url, opts ).code.should == 200
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'doesn\'t run any queued request until the auth finishes' do
|
154
|
+
pending if !ENV['IIS']
|
155
|
+
|
156
|
+
cnt = 0
|
157
|
+
|
158
|
+
50.times do |i|
|
159
|
+
client.get( @ntlm_url ) do |response|
|
160
|
+
response.code.should == 200
|
161
|
+
cnt += 1
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
client.run
|
166
|
+
cnt.should == 50
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'on wrong credentials' do
|
170
|
+
it 'returns a 401' do
|
171
|
+
pending if !ENV['IIS']
|
172
|
+
|
173
|
+
opts = {
|
174
|
+
mode: :sync, manipulators: {
|
175
|
+
'authenticator' =>
|
176
|
+
{
|
177
|
+
username: 'blah',
|
178
|
+
password: 'blah'
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
2.times do
|
184
|
+
client.get( @ntlm_url, opts ).code.should == 401
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'raptor-io/socket'
|
3
|
+
|
4
|
+
describe 'RaptorIO::Protocol::HTTP::Request::Manipulators::Authenticators::Basic' do
|
5
|
+
before :all do
|
6
|
+
WebServers.start :basic
|
7
|
+
@url = WebServers.url_for( :basic )
|
8
|
+
end
|
9
|
+
|
10
|
+
before( :each ) do
|
11
|
+
RaptorIO::Protocol::HTTP::Request::Manipulators.reset
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:client) { RaptorIO::Protocol::HTTP::Client.new(switch_board:RaptorIO::Socket::SwitchBoard.new) }
|
15
|
+
|
16
|
+
it 'provides Basic authentication' do
|
17
|
+
opts = {
|
18
|
+
mode: :sync, manipulators: {
|
19
|
+
'authenticators/basic' =>
|
20
|
+
{
|
21
|
+
username: 'admin',
|
22
|
+
password: 'secret'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
2.times do
|
28
|
+
client.get( @url, opts ).code.should == 200
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'raptor-io/socket'
|
3
|
+
|
4
|
+
describe 'RaptorIO::Protocol::HTTP::Request::Manipulators::Authenticators::Digest' do
|
5
|
+
before :all do
|
6
|
+
WebServers.start :digest
|
7
|
+
@url = WebServers.url_for( :digest )
|
8
|
+
end
|
9
|
+
|
10
|
+
let( :manipulators ) { RaptorIO::Protocol::HTTP::Request::Manipulators }
|
11
|
+
before( :each ) do
|
12
|
+
RaptorIO::Protocol::HTTP::Request::Manipulators.reset
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:client) do
|
16
|
+
sb = RaptorIO::Socket::SwitchBoard.new
|
17
|
+
RaptorIO::Protocol::HTTP::Client.new(switch_board: sb)
|
18
|
+
end
|
19
|
+
|
20
|
+
def response( algo )
|
21
|
+
RaptorIO::Protocol::HTTP::Response.parse "HTTP/1.1 401 Unauthorized
|
22
|
+
Content-Type: text/plain
|
23
|
+
Content-Length: 0
|
24
|
+
Www-Authenticate: Digest realm=\"Protected Area\", algorithm=\"#{algo}\", nonce=\"MTM3MzI5OTYxNiAxYzk2ZDM4OWY1MTY2ZGM3ODllNGQ2N2RjZDIyYzk1ZA==\", opaque=\"610a2ee688cda9e724885e23cd2cfdee\", qop=\"auth\"
|
25
|
+
Connection: keep-alive
|
26
|
+
Server: thin 1.5.1 codename Straight Razor\r\n\r\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'provides Digest authentication' do
|
30
|
+
opts = {
|
31
|
+
mode: :sync, manipulators: {
|
32
|
+
'authenticators/digest' =>
|
33
|
+
{
|
34
|
+
response: client.get( @url, mode: :sync ),
|
35
|
+
username: 'admin',
|
36
|
+
password: 'secret'
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
2.times do
|
42
|
+
client.get( @url, opts ).code.should == 200
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
%w(MD5 SHA1 SHA2 SHA256 SHA384 SHA512 RMD160).each do |algo|
|
47
|
+
it "supports #{algo}" do
|
48
|
+
manipulators.process(
|
49
|
+
'authenticators/digest',
|
50
|
+
client,
|
51
|
+
RaptorIO::Protocol::HTTP::Request.new( url: @url ),
|
52
|
+
{
|
53
|
+
response: response( algo ),
|
54
|
+
username: 'admin',
|
55
|
+
password: 'secret'
|
56
|
+
}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises error on unknown algorithm' do
|
62
|
+
expect do
|
63
|
+
manipulators.process(
|
64
|
+
'authenticators/digest',
|
65
|
+
client,
|
66
|
+
RaptorIO::Protocol::HTTP::Request.new( url: @url ),
|
67
|
+
{
|
68
|
+
response: response( 'stuff' ),
|
69
|
+
username: 'admin',
|
70
|
+
password: 'secret'
|
71
|
+
}
|
72
|
+
)
|
73
|
+
end.to raise_error RaptorIO::Protocol::HTTP::Error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|