uv-rays 1.2.1 → 1.2.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.
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