vmc 0.0.4 → 0.0.5
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.
- data/LICENSE +18 -2
- data/README +0 -3
- data/Rakefile +35 -3
- data/bin/vmc +5 -0
- data/bin/vmc.bat +1 -0
- data/lib/parse.rb +719 -0
- data/lib/vmc.rb +1588 -0
- data/lib/vmc_base.rb +205 -0
- data/vendor/gems/httpclient/VERSION +1 -0
- data/vendor/gems/httpclient/lib/http-access2/cookie.rb +1 -0
- data/vendor/gems/httpclient/lib/http-access2/http.rb +1 -0
- data/vendor/gems/httpclient/lib/http-access2.rb +53 -0
- data/vendor/gems/httpclient/lib/httpclient/auth.rb +522 -0
- data/vendor/gems/httpclient/lib/httpclient/cacert.p7s +1579 -0
- data/vendor/gems/httpclient/lib/httpclient/cacert_sha1.p7s +1579 -0
- data/vendor/gems/httpclient/lib/httpclient/connection.rb +84 -0
- data/vendor/gems/httpclient/lib/httpclient/cookie.rb +562 -0
- data/vendor/gems/httpclient/lib/httpclient/http.rb +867 -0
- data/vendor/gems/httpclient/lib/httpclient/session.rb +864 -0
- data/vendor/gems/httpclient/lib/httpclient/ssl_config.rb +417 -0
- data/vendor/gems/httpclient/lib/httpclient/timeout.rb +136 -0
- data/vendor/gems/httpclient/lib/httpclient/util.rb +86 -0
- data/vendor/gems/httpclient/lib/httpclient.rb +1020 -0
- data/vendor/gems/httpclient/lib/tags +908 -0
- metadata +142 -10
@@ -0,0 +1,522 @@
|
|
1
|
+
# HTTPClient - HTTP client library.
|
2
|
+
# Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
|
3
|
+
#
|
4
|
+
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
|
5
|
+
# redistribute it and/or modify it under the same terms of Ruby's license;
|
6
|
+
# either the dual license version in 2003, or any later version.
|
7
|
+
|
8
|
+
|
9
|
+
require 'digest/md5'
|
10
|
+
require 'httpclient/session'
|
11
|
+
|
12
|
+
|
13
|
+
class HTTPClient
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'net/ntlm'
|
17
|
+
NTLMEnabled = true
|
18
|
+
rescue LoadError
|
19
|
+
NTLMEnabled = false
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'win32/sspi'
|
24
|
+
SSPIEnabled = true
|
25
|
+
rescue LoadError
|
26
|
+
SSPIEnabled = false
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# Common abstract class for authentication filter.
|
31
|
+
#
|
32
|
+
# There are 2 authentication filters.
|
33
|
+
# WWWAuth:: Authentication filter for handling authentication negotiation
|
34
|
+
# between Web server. Parses 'WWW-Authentication' header in
|
35
|
+
# response and generates 'Authorization' header in request.
|
36
|
+
# ProxyAuth:: Authentication filter for handling authentication negotiation
|
37
|
+
# between Proxy server. Parses 'Proxy-Authentication' header in
|
38
|
+
# response and generates 'Proxy-Authorization' header in request.
|
39
|
+
class AuthFilterBase
|
40
|
+
private
|
41
|
+
|
42
|
+
def parse_authentication_header(res, tag)
|
43
|
+
challenge = res.header[tag]
|
44
|
+
return nil unless challenge
|
45
|
+
challenge.collect { |c| parse_challenge_header(c) }.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_challenge_header(challenge)
|
49
|
+
scheme, param_str = challenge.scan(/\A(\S+)(?:\s+(.*))?\z/)[0]
|
50
|
+
return nil if scheme.nil?
|
51
|
+
return scheme, param_str
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Authentication filter for handling authentication negotiation between
|
57
|
+
# Web server. Parses 'WWW-Authentication' header in response and
|
58
|
+
# generates 'Authorization' header in request.
|
59
|
+
#
|
60
|
+
# Authentication filter is implemented using request filter of HTTPClient.
|
61
|
+
# It traps HTTP response header and maintains authentication state, and
|
62
|
+
# traps HTTP request header for inserting necessary authentication header.
|
63
|
+
#
|
64
|
+
# WWWAuth has sub filters (BasicAuth, DigestAuth, NegotiateAuth and
|
65
|
+
# SSPINegotiateAuth) and delegates some operations to it.
|
66
|
+
# NegotiateAuth requires 'ruby/ntlm' module.
|
67
|
+
# SSPINegotiateAuth requires 'win32/sspi' module.
|
68
|
+
class WWWAuth < AuthFilterBase
|
69
|
+
attr_reader :basic_auth
|
70
|
+
attr_reader :digest_auth
|
71
|
+
attr_reader :negotiate_auth
|
72
|
+
attr_reader :sspi_negotiate_auth
|
73
|
+
|
74
|
+
# Creates new WWWAuth.
|
75
|
+
def initialize
|
76
|
+
@basic_auth = BasicAuth.new
|
77
|
+
@digest_auth = DigestAuth.new
|
78
|
+
@negotiate_auth = NegotiateAuth.new
|
79
|
+
@sspi_negotiate_auth = SSPINegotiateAuth.new
|
80
|
+
# sort authenticators by priority
|
81
|
+
@authenticator = [@negotiate_auth, @sspi_negotiate_auth, @digest_auth, @basic_auth]
|
82
|
+
end
|
83
|
+
|
84
|
+
# Resets challenge state. See sub filters for more details.
|
85
|
+
def reset_challenge
|
86
|
+
@authenticator.each do |auth|
|
87
|
+
auth.reset_challenge
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Set authentication credential. See sub filters for more details.
|
92
|
+
def set_auth(uri, user, passwd)
|
93
|
+
@authenticator.each do |auth|
|
94
|
+
auth.set(uri, user, passwd)
|
95
|
+
end
|
96
|
+
reset_challenge
|
97
|
+
end
|
98
|
+
|
99
|
+
# Filter API implementation. Traps HTTP request and insert
|
100
|
+
# 'Authorization' header if needed.
|
101
|
+
def filter_request(req)
|
102
|
+
@authenticator.each do |auth|
|
103
|
+
if cred = auth.get(req)
|
104
|
+
req.header.set('Authorization', auth.scheme + " " + cred)
|
105
|
+
return
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Filter API implementation. Traps HTTP response and parses
|
111
|
+
# 'WWW-Authenticate' header.
|
112
|
+
def filter_response(req, res)
|
113
|
+
command = nil
|
114
|
+
if res.status == HTTP::Status::UNAUTHORIZED
|
115
|
+
if challenge = parse_authentication_header(res, 'www-authenticate')
|
116
|
+
uri = req.header.request_uri
|
117
|
+
challenge.each do |scheme, param_str|
|
118
|
+
@authenticator.each do |auth|
|
119
|
+
if scheme.downcase == auth.scheme.downcase
|
120
|
+
challengeable = auth.challenge(uri, param_str)
|
121
|
+
command = :retry if challengeable
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
# ignore unknown authentication scheme
|
126
|
+
end
|
127
|
+
end
|
128
|
+
command
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
# Authentication filter for handling authentication negotiation between
|
134
|
+
# Proxy server. Parses 'Proxy-Authentication' header in response and
|
135
|
+
# generates 'Proxy-Authorization' header in request.
|
136
|
+
#
|
137
|
+
# Authentication filter is implemented using request filter of HTTPClient.
|
138
|
+
# It traps HTTP response header and maintains authentication state, and
|
139
|
+
# traps HTTP request header for inserting necessary authentication header.
|
140
|
+
#
|
141
|
+
# ProxyAuth has sub filters (BasicAuth, NegotiateAuth, and SSPINegotiateAuth)
|
142
|
+
# and delegates some operations to it.
|
143
|
+
# NegotiateAuth requires 'ruby/ntlm' module.
|
144
|
+
# SSPINegotiateAuth requires 'win32/sspi' module.
|
145
|
+
class ProxyAuth < AuthFilterBase
|
146
|
+
attr_reader :basic_auth
|
147
|
+
attr_reader :negotiate_auth
|
148
|
+
attr_reader :sspi_negotiate_auth
|
149
|
+
|
150
|
+
# Creates new ProxyAuth.
|
151
|
+
def initialize
|
152
|
+
@basic_auth = BasicAuth.new
|
153
|
+
@negotiate_auth = NegotiateAuth.new
|
154
|
+
@sspi_negotiate_auth = SSPINegotiateAuth.new
|
155
|
+
# sort authenticators by priority
|
156
|
+
@authenticator = [@negotiate_auth, @sspi_negotiate_auth, @basic_auth]
|
157
|
+
end
|
158
|
+
|
159
|
+
# Resets challenge state. See sub filters for more details.
|
160
|
+
def reset_challenge
|
161
|
+
@authenticator.each do |auth|
|
162
|
+
auth.reset_challenge
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Set authentication credential. See sub filters for more details.
|
167
|
+
def set_auth(user, passwd)
|
168
|
+
@authenticator.each do |auth|
|
169
|
+
auth.set(nil, user, passwd)
|
170
|
+
end
|
171
|
+
reset_challenge
|
172
|
+
end
|
173
|
+
|
174
|
+
# Filter API implementation. Traps HTTP request and insert
|
175
|
+
# 'Proxy-Authorization' header if needed.
|
176
|
+
def filter_request(req)
|
177
|
+
@authenticator.each do |auth|
|
178
|
+
if cred = auth.get(req)
|
179
|
+
req.header.set('Proxy-Authorization', auth.scheme + " " + cred)
|
180
|
+
return
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Filter API implementation. Traps HTTP response and parses
|
186
|
+
# 'Proxy-Authenticate' header.
|
187
|
+
def filter_response(req, res)
|
188
|
+
command = nil
|
189
|
+
if res.status == HTTP::Status::PROXY_AUTHENTICATE_REQUIRED
|
190
|
+
if challenge = parse_authentication_header(res, 'proxy-authenticate')
|
191
|
+
uri = req.header.request_uri
|
192
|
+
challenge.each do |scheme, param_str|
|
193
|
+
@authenticator.each do |auth|
|
194
|
+
if scheme.downcase == auth.scheme.downcase
|
195
|
+
challengeable = auth.challenge(uri, param_str)
|
196
|
+
command = :retry if challengeable
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
# ignore unknown authentication scheme
|
201
|
+
end
|
202
|
+
end
|
203
|
+
command
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Authentication filter for handling BasicAuth negotiation.
|
208
|
+
# Used in WWWAuth and ProxyAuth.
|
209
|
+
class BasicAuth
|
210
|
+
# Authentication scheme.
|
211
|
+
attr_reader :scheme
|
212
|
+
|
213
|
+
# Creates new BasicAuth filter.
|
214
|
+
def initialize
|
215
|
+
@cred = nil
|
216
|
+
@auth = {}
|
217
|
+
@challengeable = {}
|
218
|
+
@scheme = "Basic"
|
219
|
+
end
|
220
|
+
|
221
|
+
# Resets challenge state. Do not send '*Authorization' header until the
|
222
|
+
# server sends '*Authentication' again.
|
223
|
+
def reset_challenge
|
224
|
+
@challengeable.clear
|
225
|
+
end
|
226
|
+
|
227
|
+
# Set authentication credential.
|
228
|
+
# uri == nil for generic purpose (allow to use user/password for any URL).
|
229
|
+
def set(uri, user, passwd)
|
230
|
+
if uri.nil?
|
231
|
+
@cred = ["#{user}:#{passwd}"].pack('m').tr("\n", '')
|
232
|
+
else
|
233
|
+
uri = Util.uri_dirname(uri)
|
234
|
+
@auth[uri] = ["#{user}:#{passwd}"].pack('m').tr("\n", '')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Response handler: returns credential.
|
239
|
+
# It sends cred only when a given uri is;
|
240
|
+
# * child page of challengeable(got *Authenticate before) uri and,
|
241
|
+
# * child page of defined credential
|
242
|
+
def get(req)
|
243
|
+
target_uri = req.header.request_uri
|
244
|
+
return nil unless @challengeable.find { |uri, ok|
|
245
|
+
Util.uri_part_of(target_uri, uri) and ok
|
246
|
+
}
|
247
|
+
return @cred if @cred
|
248
|
+
Util.hash_find_value(@auth) { |uri, cred|
|
249
|
+
Util.uri_part_of(target_uri, uri)
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
# Challenge handler: remember URL for response.
|
254
|
+
def challenge(uri, param_str)
|
255
|
+
@challengeable[uri] = true
|
256
|
+
true
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# Authentication filter for handling DigestAuth negotiation.
|
262
|
+
# Used in WWWAuth.
|
263
|
+
class DigestAuth
|
264
|
+
# Authentication scheme.
|
265
|
+
attr_reader :scheme
|
266
|
+
|
267
|
+
# Creates new DigestAuth filter.
|
268
|
+
def initialize
|
269
|
+
@auth = {}
|
270
|
+
@challenge = {}
|
271
|
+
@nonce_count = 0
|
272
|
+
@scheme = "Digest"
|
273
|
+
end
|
274
|
+
|
275
|
+
# Resets challenge state. Do not send '*Authorization' header until the
|
276
|
+
# server sends '*Authentication' again.
|
277
|
+
def reset_challenge
|
278
|
+
@challenge.clear
|
279
|
+
end
|
280
|
+
|
281
|
+
# Set authentication credential.
|
282
|
+
# uri == nil is ignored.
|
283
|
+
def set(uri, user, passwd)
|
284
|
+
if uri
|
285
|
+
uri = Util.uri_dirname(uri)
|
286
|
+
@auth[uri] = [user, passwd]
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Response handler: returns credential.
|
291
|
+
# It sends cred only when a given uri is;
|
292
|
+
# * child page of challengeable(got *Authenticate before) uri and,
|
293
|
+
# * child page of defined credential
|
294
|
+
def get(req)
|
295
|
+
target_uri = req.header.request_uri
|
296
|
+
param = Util.hash_find_value(@challenge) { |uri, v|
|
297
|
+
Util.uri_part_of(target_uri, uri)
|
298
|
+
}
|
299
|
+
return nil unless param
|
300
|
+
user, passwd = Util.hash_find_value(@auth) { |uri, auth_data|
|
301
|
+
Util.uri_part_of(target_uri, uri)
|
302
|
+
}
|
303
|
+
return nil unless user
|
304
|
+
uri = req.header.request_uri
|
305
|
+
calc_cred(req.header.request_method, uri, user, passwd, param)
|
306
|
+
end
|
307
|
+
|
308
|
+
# Challenge handler: remember URL and challenge token for response.
|
309
|
+
def challenge(uri, param_str)
|
310
|
+
@challenge[uri] = parse_challenge_param(param_str)
|
311
|
+
true
|
312
|
+
end
|
313
|
+
|
314
|
+
private
|
315
|
+
|
316
|
+
# this method is implemented by sromano and posted to
|
317
|
+
# http://tools.assembla.com/breakout/wiki/DigestForSoap
|
318
|
+
# Thanks!
|
319
|
+
# supported algorithm: MD5 only for now
|
320
|
+
def calc_cred(method, uri, user, passwd, param)
|
321
|
+
a_1 = "#{user}:#{param['realm']}:#{passwd}"
|
322
|
+
a_2 = "#{method}:#{uri.path}"
|
323
|
+
nonce = param['nonce']
|
324
|
+
cnonce = generate_cnonce()
|
325
|
+
@nonce_count += 1
|
326
|
+
message_digest = []
|
327
|
+
message_digest << Digest::MD5.hexdigest(a_1)
|
328
|
+
message_digest << nonce
|
329
|
+
message_digest << ('%08x' % @nonce_count)
|
330
|
+
message_digest << cnonce
|
331
|
+
message_digest << param['qop']
|
332
|
+
message_digest << Digest::MD5.hexdigest(a_2)
|
333
|
+
header = []
|
334
|
+
header << "username=\"#{user}\""
|
335
|
+
header << "realm=\"#{param['realm']}\""
|
336
|
+
header << "nonce=\"#{nonce}\""
|
337
|
+
header << "uri=\"#{uri.path}\""
|
338
|
+
header << "cnonce=\"#{cnonce}\""
|
339
|
+
header << "nc=#{'%08x' % @nonce_count}"
|
340
|
+
header << "qop=\"#{param['qop']}\""
|
341
|
+
header << "response=\"#{Digest::MD5.hexdigest(message_digest.join(":"))}\""
|
342
|
+
header << "algorithm=\"MD5\""
|
343
|
+
header << "opaque=\"#{param['opaque']}\"" if param.key?('opaque')
|
344
|
+
header.join(", ")
|
345
|
+
end
|
346
|
+
|
347
|
+
# cf. WEBrick::HTTPAuth::DigestAuth#generate_next_nonce(aTime)
|
348
|
+
def generate_cnonce
|
349
|
+
now = "%012d" % Time.now.to_i
|
350
|
+
pk = Digest::MD5.hexdigest([now, self.__id__, Process.pid, rand(65535)].join)[0, 32]
|
351
|
+
[now + ':' + pk].pack('m*').chop
|
352
|
+
end
|
353
|
+
|
354
|
+
def parse_challenge_param(param_str)
|
355
|
+
param = {}
|
356
|
+
param_str.scan(/\s*([^\,]+(?:\\.[^\,]*)*)/).each do |str|
|
357
|
+
key, value = str[0].scan(/\A([^=]+)=(.*)\z/)[0]
|
358
|
+
if /\A"(.*)"\z/ =~ value
|
359
|
+
value = $1.gsub(/\\(.)/, '\1')
|
360
|
+
end
|
361
|
+
param[key] = value
|
362
|
+
end
|
363
|
+
param
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
# Authentication filter for handling Negotiate/NTLM negotiation.
|
369
|
+
# Used in WWWAuth and ProxyAuth.
|
370
|
+
#
|
371
|
+
# NegotiateAuth depends on 'ruby/ntlm' module.
|
372
|
+
class NegotiateAuth
|
373
|
+
# Authentication scheme.
|
374
|
+
attr_reader :scheme
|
375
|
+
# NTLM opt for ruby/ntlm. {:ntlmv2 => true} by default.
|
376
|
+
attr_reader :ntlm_opt
|
377
|
+
|
378
|
+
# Creates new NegotiateAuth filter.
|
379
|
+
def initialize
|
380
|
+
@auth = {}
|
381
|
+
@auth_default = nil
|
382
|
+
@challenge = {}
|
383
|
+
@scheme = "Negotiate"
|
384
|
+
@ntlm_opt = {
|
385
|
+
:ntlmv2 => true
|
386
|
+
}
|
387
|
+
end
|
388
|
+
|
389
|
+
# Resets challenge state. Do not send '*Authorization' header until the
|
390
|
+
# server sends '*Authentication' again.
|
391
|
+
def reset_challenge
|
392
|
+
@challenge.clear
|
393
|
+
end
|
394
|
+
|
395
|
+
# Set authentication credential.
|
396
|
+
# uri == nil for generic purpose (allow to use user/password for any URL).
|
397
|
+
def set(uri, user, passwd)
|
398
|
+
if uri
|
399
|
+
uri = Util.uri_dirname(uri)
|
400
|
+
@auth[uri] = [user, passwd]
|
401
|
+
else
|
402
|
+
@auth_default = [user, passwd]
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
# Response handler: returns credential.
|
407
|
+
# See ruby/ntlm for negotiation state transition.
|
408
|
+
def get(req)
|
409
|
+
return nil unless NTLMEnabled
|
410
|
+
target_uri = req.header.request_uri
|
411
|
+
domain_uri, param = @challenge.find { |uri, v|
|
412
|
+
Util.uri_part_of(target_uri, uri)
|
413
|
+
}
|
414
|
+
return nil unless param
|
415
|
+
user, passwd = Util.hash_find_value(@auth) { |uri, auth_data|
|
416
|
+
Util.uri_part_of(target_uri, uri)
|
417
|
+
}
|
418
|
+
unless user
|
419
|
+
user, passwd = @auth_default
|
420
|
+
end
|
421
|
+
return nil unless user
|
422
|
+
state = param[:state]
|
423
|
+
authphrase = param[:authphrase]
|
424
|
+
case state
|
425
|
+
when :init
|
426
|
+
t1 = Net::NTLM::Message::Type1.new
|
427
|
+
return t1.encode64
|
428
|
+
when :response
|
429
|
+
t2 = Net::NTLM::Message.decode64(authphrase)
|
430
|
+
t3 = t2.response({:user => user, :password => passwd}, @ntlm_opt.dup)
|
431
|
+
@challenge.delete(domain_uri)
|
432
|
+
return t3.encode64
|
433
|
+
end
|
434
|
+
nil
|
435
|
+
end
|
436
|
+
|
437
|
+
# Challenge handler: remember URL and challenge token for response.
|
438
|
+
def challenge(uri, param_str)
|
439
|
+
return false unless NTLMEnabled
|
440
|
+
if param_str.nil? or @challenge[uri].nil?
|
441
|
+
c = @challenge[uri] = {}
|
442
|
+
c[:state] = :init
|
443
|
+
c[:authphrase] = ""
|
444
|
+
else
|
445
|
+
c = @challenge[uri]
|
446
|
+
c[:state] = :response
|
447
|
+
c[:authphrase] = param_str
|
448
|
+
end
|
449
|
+
true
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
|
454
|
+
# Authentication filter for handling Negotiate/NTLM negotiation.
|
455
|
+
# Used in ProxyAuth.
|
456
|
+
#
|
457
|
+
# SSPINegotiateAuth depends on 'win32/sspi' module.
|
458
|
+
class SSPINegotiateAuth
|
459
|
+
# Authentication scheme.
|
460
|
+
attr_reader :scheme
|
461
|
+
|
462
|
+
# Creates new SSPINegotiateAuth filter.
|
463
|
+
def initialize
|
464
|
+
@challenge = {}
|
465
|
+
@scheme = "Negotiate"
|
466
|
+
end
|
467
|
+
|
468
|
+
# Resets challenge state. Do not send '*Authorization' header until the
|
469
|
+
# server sends '*Authentication' again.
|
470
|
+
def reset_challenge
|
471
|
+
@challenge.clear
|
472
|
+
end
|
473
|
+
|
474
|
+
# Set authentication credential.
|
475
|
+
# NOT SUPPORTED: username and necessary data is retrieved by win32/sspi.
|
476
|
+
# See win32/sspi for more details.
|
477
|
+
def set(uri, user, passwd)
|
478
|
+
# not supported
|
479
|
+
end
|
480
|
+
|
481
|
+
# Response handler: returns credential.
|
482
|
+
# See win32/sspi for negotiation state transition.
|
483
|
+
def get(req)
|
484
|
+
return nil unless SSPIEnabled
|
485
|
+
target_uri = req.header.request_uri
|
486
|
+
domain_uri, param = @challenge.find { |uri, v|
|
487
|
+
Util.uri_part_of(target_uri, uri)
|
488
|
+
}
|
489
|
+
return nil unless param
|
490
|
+
state = param[:state]
|
491
|
+
authenticator = param[:authenticator]
|
492
|
+
authphrase = param[:authphrase]
|
493
|
+
case state
|
494
|
+
when :init
|
495
|
+
authenticator = param[:authenticator] = Win32::SSPI::NegotiateAuth.new
|
496
|
+
return authenticator.get_initial_token(@scheme)
|
497
|
+
when :response
|
498
|
+
@challenge.delete(domain_uri)
|
499
|
+
return authenticator.complete_authentication(authphrase)
|
500
|
+
end
|
501
|
+
nil
|
502
|
+
end
|
503
|
+
|
504
|
+
# Challenge handler: remember URL and challenge token for response.
|
505
|
+
def challenge(uri, param_str)
|
506
|
+
return false unless SSPIEnabled
|
507
|
+
if param_str.nil? or @challenge[uri].nil?
|
508
|
+
c = @challenge[uri] = {}
|
509
|
+
c[:state] = :init
|
510
|
+
c[:authenticator] = nil
|
511
|
+
c[:authphrase] = ""
|
512
|
+
else
|
513
|
+
c = @challenge[uri]
|
514
|
+
c[:state] = :response
|
515
|
+
c[:authphrase] = param_str
|
516
|
+
end
|
517
|
+
true
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
|
522
|
+
end
|