uv-rays 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d9b06f4cf86067b6a2efe196238fab6cf7dda7d7
4
- data.tar.gz: 40e682d35d1bb7360012b442e08c08ca5d16f471
3
+ metadata.gz: 058dd2e60b392b41bd8138d396022069f087f730
4
+ data.tar.gz: 3ba1ec427f37ccbc321c38cd1cd6ed7021dbfaf4
5
5
  SHA512:
6
- metadata.gz: e39c2e2075fe9f6a6bbd22a3142fc12f8bfbd05bf4eb51753b8851241bb1651f22faeb0e0f06731006312325541fe6bce595b5ab03bde13bed3eed7e4a8e4825
7
- data.tar.gz: d69d179bb6714e4e7aeb1c21ce186891af31afbbfd7565b3380ebf1ed7b4c7a2b5719fc8e078ebc4e19594291c026ae99729b8be24649346198dd6379640a9b6
6
+ metadata.gz: f4d0275064097f22c4b3a955f55874ede3735dd7315bd120d2a0b01ad89c497af88523a516df2d9ac2b984295ff907fb1174b2c7c90120f266a6699278318227
7
+ data.tar.gz: 35110447fbce49124c2f5592d9caa35e8e17368f6a1831084213131ad3dbd106f39edae90c395ead4d3e3f7968d638e871445cb31c7a6f2b6af2650daa124b82
@@ -11,7 +11,7 @@ module UV
11
11
 
12
12
  attr_reader :path
13
13
  attr_reader :method
14
- attr_reader :headers
14
+ attr_reader :headers, :options
15
15
 
16
16
 
17
17
  def cookies_hash
@@ -23,22 +23,32 @@ module UV
23
23
  end
24
24
 
25
25
 
26
- def initialize(endpoint, options)
26
+ def initialize(endpoint, options, using_ntlm)
27
27
  super(endpoint.loop, endpoint.loop.defer)
28
28
 
29
29
  @options = options
30
30
  @endpoint = endpoint
31
+ @ntlm_retries = using_ntlm ? 0 : nil
31
32
 
32
33
  @path = options[:path]
33
34
  @method = options[:method]
34
35
  @uri = "#{endpoint.scheme}#{encode_host(endpoint.host, endpoint.port)}#{@path}"
35
36
  end
36
37
 
37
- def resolve(response)
38
- @defer.resolve({
39
- headers: @headers,
40
- body: response
41
- })
38
+ def resolve(response, body)
39
+ if @ntlm_retries && @headers.status == 401 && @headers[:"WWW-Authenticate"] && @ntlm_retries < 3
40
+ @options[:headers][:Authorization] = @endpoint.ntlm_auth_header(@headers[:"WWW-Authenticate"])
41
+ @ntlm_retries += 1
42
+
43
+ response.request = self
44
+ execute(*@exec_params)
45
+ else
46
+ @exec_params = nil
47
+ @defer.resolve({
48
+ headers: @headers,
49
+ body: body
50
+ })
51
+ end
42
52
  end
43
53
 
44
54
  def reject(reason)
@@ -47,6 +57,7 @@ module UV
47
57
 
48
58
  def execute(transport, error)
49
59
  head, body = build_request, @options[:body]
60
+ @exec_params = [transport, error]
50
61
 
51
62
  @endpoint.middleware.each do |m|
52
63
  head, body = m.request(self, head, body) if m.respond_to?(:request)
@@ -79,7 +90,7 @@ module UV
79
90
 
80
91
  if body
81
92
  request_header << body
82
- transport.write(body).catch error
93
+ transport.write(request_header).catch error
83
94
  elsif file
84
95
  transport.write(request_header).catch error
85
96
 
@@ -110,11 +110,14 @@ module UV
110
110
  end
111
111
 
112
112
  def on_message_complete(parser)
113
- @request.resolve(@body)
113
+ req = @request
114
+ bod = @body
114
115
 
115
116
  # Clean up memory
116
117
  @request = nil
117
118
  @body = nil
119
+
120
+ req.resolve(self, bod)
118
121
  end
119
122
 
120
123
  # We need to flush the response on disconnect if content-length is undefined
@@ -1,3 +1,6 @@
1
+ require 'rubyntlm'
2
+
3
+
1
4
  module UV
2
5
  class CookieJar
3
6
  def initialize
@@ -51,7 +54,7 @@ module UV
51
54
 
52
55
  def initialize(uri, options = {})
53
56
  @inactivity_timeout = options[:inactivity_timeout] ||= 10000 # default connection inactivity (post-setup) timeout
54
-
57
+ @ntlm_creds = options[:ntlm]
55
58
 
56
59
  uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
57
60
  @https = uri.scheme == "https"
@@ -102,7 +105,7 @@ module UV
102
105
  options[:method] = method
103
106
 
104
107
  # Setup the request with callbacks
105
- request = Http::Request.new(self, options)
108
+ request = Http::Request.new(self, options, @ntlm_creds)
106
109
  request.then(proc { |result|
107
110
  @waiting_response = nil
108
111
 
@@ -212,6 +215,13 @@ module UV
212
215
  @response.request = @staging_request
213
216
  @staging_request = nil
214
217
 
218
+ if @ntlm_creds
219
+ opts = @waiting_response.options
220
+ opts[:headers] ||= {}
221
+ opts = opts[:headers]
222
+ opts[:Authorization] = ntlm_auth_header
223
+ end
224
+
215
225
  @timer.again if @inactivity_timeout > 0
216
226
  @waiting_response.execute(@transport, proc { |err|
217
227
  @transport.close
@@ -242,7 +252,30 @@ module UV
242
252
  reqs.each do |request|
243
253
  request.reject(:close_connection)
244
254
  end
245
- super(after_writing)
255
+ super(after_writing) if @transport
256
+ end
257
+
258
+ def ntlm_auth_header(challenge = nil)
259
+ if @ntlm_auth && challenge.nil?
260
+ return @ntlm_auth
261
+ elsif challenge
262
+ scheme, param_str = parse_ntlm_challenge_header(challenge)
263
+ if param_str.nil?
264
+ @ntlm_auth = nil
265
+ return ntlm_auth_header(creds)
266
+ else
267
+ t2 = Net::NTLM::Message.decode64(param_str)
268
+ t3 = t2.response(@ntlm_creds, ntlmv2: true)
269
+ @ntlm_auth = "NTLM #{t3.encode64}"
270
+ return @ntlm_auth
271
+ end
272
+ else
273
+ domain = @ntlm_creds[:domain]
274
+ t1 = Net::NTLM::Message::Type1.new()
275
+ t1.domain = domain if domain
276
+ @ntlm_auth = "NTLM #{t1.encode64}"
277
+ return @ntlm_auth
278
+ end
246
279
  end
247
280
 
248
281
 
@@ -257,5 +290,11 @@ module UV
257
290
  def stop_timer
258
291
  @timer.stop unless @timer.nil?
259
292
  end
293
+
294
+ def parse_ntlm_challenge_header(challenge)
295
+ scheme, param_str = challenge.scan(/\A(\S+)(?:\s+(.*))?\z/)[0]
296
+ return nil if scheme.nil?
297
+ return scheme, param_str
298
+ end
260
299
  end
261
300
  end
@@ -1,3 +1,3 @@
1
1
  module UV
2
- VERSION = '1.2.1'
2
+ VERSION = '1.2.2'
3
3
  end
@@ -20,6 +20,33 @@ module HttpServer
20
20
  end
21
21
  end
22
22
 
23
+ module NTLMServer
24
+ def post_init
25
+ @parser = ::HttpParser::Parser.new(self)
26
+ @state = ::HttpParser::Parser.new_instance
27
+ @state.type = :request
28
+
29
+ @req = 0
30
+ end
31
+
32
+ def on_message_complete(parser)
33
+ if @req == 0
34
+ @state = ::HttpParser::Parser.new_instance
35
+ write("HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: NTLM TlRMTVNTUAACAAAAEgASADgAAAAFgokCuEPycVw6htsAAAAAAAAAAK4ArgBKAAAABgOAJQAAAA9SAEEAQgBPAE4ARQBUAE8AQwACABIAUgBBAEIATwBOAEUAVABPAEMAAQAUAFMAWQBQAFYAMQA5ADkAMAA1ADUABAAcAG8AYwAuAHIAYQBiAG8AbgBlAHQALgBjAG8AbQADADIAUwBZAFAAVgAxADkAOQAwADUANQAuAG8AYwAuAHIAYQBiAG8AbgBlAHQALgBjAG8AbQAFABYAcgBhAGIAbwBuAGUAdAAuAGMAbwBtAAcACACcZNzCwkbRAQAAAAA=\r\nContent-type: text/html\r\nContent-length: 0\r\n\r\n")
36
+ else
37
+ write("HTTP/1.1 200 OK\r\nContent-type: text/html\r\nContent-length: 1\r\n\r\ny")
38
+ end
39
+ @req += 1
40
+ end
41
+
42
+ def on_read(data, connection)
43
+ if @parser.parse(@state, data)
44
+ p 'parse error'
45
+ p @state.error
46
+ end
47
+ end
48
+ end
49
+
23
50
  module OldServer
24
51
  def post_init
25
52
  @parser = ::HttpParser::Parser.new(self)
@@ -201,4 +228,40 @@ describe UV::HttpEndpoint do
201
228
  expect(@response2[:headers].keep_alive).to eq(false)
202
229
  end
203
230
  end
231
+
232
+ describe 'NTLM auth support' do
233
+ it "should perform NTLM auth transparently" do
234
+ @loop.run { |logger|
235
+ logger.progress do |level, errorid, error|
236
+ begin
237
+ @general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
238
+ rescue Exception
239
+ @general_failure << 'error in logger'
240
+ end
241
+ end
242
+
243
+ tcp = UV.start_server '127.0.0.1', 3250, NTLMServer
244
+ server = UV::HttpEndpoint.new 'http://127.0.0.1:3250', ntlm: {
245
+ user: 'username',
246
+ password: 'password',
247
+ domain: 'domain'
248
+ }
249
+
250
+ request = server.get(path: '/')
251
+ request.then(proc { |response|
252
+ @response = response
253
+ tcp.close
254
+ @loop.stop
255
+ }, @request_failure)
256
+ }
257
+
258
+ expect(@general_failure).to eq([])
259
+ expect(@response[:headers][:"Content-type"]).to eq('text/html')
260
+ expect(@response[:headers].http_version).to eq('1.1')
261
+ expect(@response[:headers].status).to eq(200)
262
+ expect(@response[:headers].cookies).to eq({})
263
+ expect(@response[:headers].keep_alive).to eq(true)
264
+ expect(@response[:body]).to eq('y')
265
+ end
266
+ end
204
267
  end
data/uv-rays.gemspec CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |gem|
20
20
  gem.add_runtime_dependency 'ipaddress'
21
21
  gem.add_runtime_dependency 'addressable'
22
22
  gem.add_runtime_dependency 'http-parser', '>= 1.0.4'
23
+ gem.add_runtime_dependency 'rubyntlm'
23
24
 
24
25
  gem.add_development_dependency 'rspec', '>= 2.14'
25
26
  gem.add_development_dependency 'rake', '>= 10.1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uv-rays
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen von Takach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-14 00:00:00.000000000 Z
11
+ date: 2016-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: libuv
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.0.4
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubyntlm
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rspec
113
127
  requirement: !ruby/object:Gem::Requirement