rubysspi 1.2.4 → 1.3
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/CHANGELOG.txt +7 -0
- data/Rakefile +1 -1
- data/bin/apply_sspi_patch +3 -2
- data/lib/win32/sspi.rb +16 -7
- data/lib/win32/sspi/http_proxy_patch.rb +2 -2
- data/test/test_ruby_sspi.rb +48 -12
- data/test/trace_proxy.rb +8 -2
- metadata +2 -2
data/CHANGELOG.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
== 1.3
|
2
|
+
* Updated library to work with either "Negotiate" or "NTLM" authorization schemes. Arguments to Win32::SSPI.get_initial_token have changed
|
3
|
+
but that should only impact code directly using the library. Net::HTTP support still works the same.
|
4
|
+
|
5
|
+
== 1.2.5
|
6
|
+
* Fixed patching on net/http so hard-coded paths are not used, but paths from rbconfig.
|
7
|
+
|
1
8
|
== 1.2.4
|
2
9
|
* Compatibility updates for rubygems 1.2.0
|
3
10
|
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'rake/testtask'
|
|
6
6
|
spec = Gem::Specification.new do |s|
|
7
7
|
s.name = "rubysspi"
|
8
8
|
s.summary = "A library which implements Ruby bindings to the Win32 SSPI library. Also includes a module to add Negotiate authentication support to Net::HTTP."
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.3"
|
10
10
|
s.author = "Justin Bailey"
|
11
11
|
s.email = "jgbailey @nospam@ gmail.com"
|
12
12
|
s.homepage = "http://rubyforge.org/projects/rubysspi/"
|
data/bin/apply_sspi_patch
CHANGED
@@ -62,20 +62,21 @@ unless spec
|
|
62
62
|
exit
|
63
63
|
end
|
64
64
|
|
65
|
-
gem_path = Pathname.new(spec.full_gem_path) + "lib"
|
65
|
+
gem_path = (Pathname.new(spec.full_gem_path) + "lib").sub(Config::TOPDIR, "\#{Config::TOPDIR}")
|
66
66
|
|
67
67
|
# Write patch file.
|
68
68
|
puts "Creating patch file to replace #{orig_file}"
|
69
69
|
orig_file.open("w") { |f| f.write(<<EOS) }
|
70
70
|
# Include original net/http
|
71
71
|
require 'net/#{orig_dest.basename(orig_dest.extname)}'
|
72
|
+
require 'rbconfig'
|
72
73
|
|
73
74
|
# This magic constant can be defined to disable the patch.
|
74
75
|
unless defined? DISABLE_RUBY_SSPI_PATCH
|
75
76
|
# Because rubygems >= 0.9.2 requires net/http,
|
76
77
|
# we can't depend on ruby gems here. Instead, directly
|
77
78
|
# require path containing RubySSPI gem.
|
78
|
-
$: <<
|
79
|
+
$: << %(#{gem_path}) unless $:.include?(%(#{gem_path}))
|
79
80
|
require 'win32/sspi/http_proxy_patch'
|
80
81
|
end
|
81
82
|
EOS
|
data/lib/win32/sspi.rb
CHANGED
@@ -224,9 +224,14 @@ module Win32
|
|
224
224
|
raise "http must respond to :get" unless http.respond_to?(:get)
|
225
225
|
nego_auth = self.new user, domain
|
226
226
|
|
227
|
-
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
228
|
-
|
227
|
+
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
228
|
+
# Negotiate may not be supported, so we need to look for NTLM too.
|
229
|
+
|
230
|
+
if resp["Proxy-Authenticate"].include? "Negotiate"
|
229
231
|
resp = http.get path, { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) }
|
232
|
+
elsif resp["Proxy-Authenticate"].include? "NTLM"
|
233
|
+
resp = http.get path, { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
234
|
+
resp = http.get path, { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(resp["Proxy-Authenticate"].split(" ").last.strip) }
|
230
235
|
end
|
231
236
|
|
232
237
|
resp
|
@@ -247,9 +252,11 @@ module Win32
|
|
247
252
|
|
248
253
|
# Gets the initial Negotiate token. Returns it as a base64 encoded string suitable for use in HTTP. Can
|
249
254
|
# be easily decoded, however.
|
250
|
-
|
255
|
+
#
|
256
|
+
# auth_type is the authentication method being used. It is usually "Negotiate" or "NTLM".
|
257
|
+
def get_initial_token(auth_type)
|
251
258
|
raise "This object is no longer usable because its resources have been freed." if @cleaned_up
|
252
|
-
get_credentials
|
259
|
+
get_credentials auth_type
|
253
260
|
|
254
261
|
outputBuffer = SecurityBuffer.new
|
255
262
|
@context = CtxtHandle.new
|
@@ -275,7 +282,7 @@ module Win32
|
|
275
282
|
# Nil token OK, just set it to empty string
|
276
283
|
token = "" if token.nil?
|
277
284
|
|
278
|
-
if token.include?
|
285
|
+
if token.include?("Negotiate") || token.include?("NTLM")
|
279
286
|
# If the Negotiate prefix is passed in, assume we are seeing "Negotiate <token>" and get the token.
|
280
287
|
token = token.split(" ").last
|
281
288
|
end
|
@@ -314,11 +321,13 @@ module Win32
|
|
314
321
|
end
|
315
322
|
|
316
323
|
# Gets credentials based on user, domain or both. If both are nil, an error occurs
|
317
|
-
|
324
|
+
#
|
325
|
+
# auth_type is the authentication type being used. It usually either "Negotiate" or "NTLM".
|
326
|
+
def get_credentials(auth_type)
|
318
327
|
@credentials = CredHandle.new
|
319
328
|
ts = TimeStamp.new
|
320
329
|
@identity = Identity.new @user, @domain
|
321
|
-
result = SSPIResult.new(API::AcquireCredentialsHandle.call(nil,
|
330
|
+
result = SSPIResult.new(API::AcquireCredentialsHandle.call(nil, auth_type, SECPKG_CRED_OUTBOUND, nil, @identity.to_p,
|
322
331
|
nil, nil, @credentials.to_p, ts.to_p))
|
323
332
|
raise "Error acquire credentials: #{result}" unless result.ok?
|
324
333
|
end
|
@@ -78,10 +78,10 @@ module Net
|
|
78
78
|
end_transport req, res
|
79
79
|
begin_transport req
|
80
80
|
if proxy?
|
81
|
-
req["Proxy-Authorization"] = "#{tok} #{n.get_initial_token}"
|
81
|
+
req["Proxy-Authorization"] = "#{tok} #{n.get_initial_token(tok)}"
|
82
82
|
req["Proxy-Connection"] = "Keep-Alive"
|
83
83
|
else
|
84
|
-
req["Authorization"] = "#{tok} #{n.get_initial_token}"
|
84
|
+
req["Authorization"] = "#{tok} #{n.get_initial_token(tok)}"
|
85
85
|
end
|
86
86
|
# Some versions of ISA will close the connection if this isn't present.
|
87
87
|
req["Connection"] = "Keep-Alive"
|
data/test/test_ruby_sspi.rb
CHANGED
@@ -32,8 +32,16 @@ class NTLMTest < Test::Unit::TestCase
|
|
32
32
|
|
33
33
|
Net::HTTP.Proxy(proxy.host, proxy.port).start("www.google.com") do |http|
|
34
34
|
nego_auth = Win32::SSPI::NegotiateAuth.new
|
35
|
-
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
36
|
-
|
35
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
36
|
+
if sr["Proxy-Authenticate"].include? "Negotiate"
|
37
|
+
resp = http.get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
38
|
+
elsif sr["Proxy-Authenticate"].include? "NTLM"
|
39
|
+
sr = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
40
|
+
resp = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
41
|
+
else
|
42
|
+
raise "Proxy-Authentica method must be either NTLM or Negotiate. Got #{sr["Proxy-Authenticate"].inspect}"
|
43
|
+
end
|
44
|
+
|
37
45
|
# Google redirects to country of origins domain if not US.
|
38
46
|
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
39
47
|
resp = http.get "/foobar.html"
|
@@ -56,8 +64,17 @@ class NTLMTest < Test::Unit::TestCase
|
|
56
64
|
|
57
65
|
Net::HTTP.Proxy(proxy.host, proxy.port).start("www.google.com") do |http|
|
58
66
|
nego_auth = Win32::SSPI::NegotiateAuth.new
|
59
|
-
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
60
|
-
|
67
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
68
|
+
|
69
|
+
if sr["Proxy-Authenticate"].include? "Negotiate"
|
70
|
+
resp = http.get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
71
|
+
elsif sr["Proxy-Authenticate"].include? "NTLM"
|
72
|
+
sr = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
73
|
+
resp = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
74
|
+
else
|
75
|
+
raise "Proxy-Authentica method must be either NTLM or Negotiate. Got #{sr["Proxy-Authenticate"].inspect}"
|
76
|
+
end
|
77
|
+
|
61
78
|
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
62
79
|
assert_raises(RuntimeError, "Should not be able to call complete_authentication again") do
|
63
80
|
nego_auth.complete_authentication "foo"
|
@@ -71,19 +88,38 @@ class NTLMTest < Test::Unit::TestCase
|
|
71
88
|
# Test that raw token works
|
72
89
|
Net::HTTP.Proxy(proxy.host, proxy.port).start("www.google.com") do |http|
|
73
90
|
nego_auth = Win32::SSPI::NegotiateAuth.new
|
74
|
-
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
91
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
92
|
+
|
93
|
+
if sr["Proxy-Authenticate"].include? "Negotiate"
|
94
|
+
token = Base64.decode64(sr["Proxy-Authenticate"].split(" ").last.strip)
|
95
|
+
completed_token = nego_auth.complete_authentication(token)
|
96
|
+
resp = http.get "/", { "Proxy-Authorization" => "Negotiate " + completed_token }
|
97
|
+
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
98
|
+
elsif sr["Proxy-Authenticate"].include? "NTLM"
|
99
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
100
|
+
token = Base64.decode64(sr["Proxy-Authenticate"].split(" ").last.strip)
|
101
|
+
completed_token = nego_auth.complete_authentication(token)
|
102
|
+
resp = http.get "/", { "Proxy-Authorization" => "NTLM " + completed_token }
|
103
|
+
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
104
|
+
else
|
105
|
+
raise "Proxy-Authentica method must be either NTLM or Negotiate. Got #{sr["Proxy-Authenticate"].inspect}"
|
106
|
+
end
|
79
107
|
end
|
80
108
|
|
81
109
|
# Test that token w/ "Negotiate" header included works
|
82
110
|
Net::HTTP.Proxy(proxy.host, proxy.port).start("www.google.com") do |http|
|
83
111
|
nego_auth = Win32::SSPI::NegotiateAuth.new
|
84
|
-
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
85
|
-
|
86
|
-
|
112
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
113
|
+
if sr["Proxy-Authenticate"].include? "Negotiate"
|
114
|
+
resp = http.get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(sr["Proxy-Authenticate"]) }
|
115
|
+
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
116
|
+
elsif sr["Proxy-Authenticate"].include? "NTLM"
|
117
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
118
|
+
resp = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(sr["Proxy-Authenticate"]) }
|
119
|
+
assert success_or_redirect(resp.code), "Response code not as expected: #{resp.inspect}"
|
120
|
+
else
|
121
|
+
raise "Proxy-Authentica method must be either NTLM or Negotiate. Got #{sr["Proxy-Authenticate"].inspect}"
|
122
|
+
end
|
87
123
|
end
|
88
124
|
end
|
89
125
|
|
data/test/trace_proxy.rb
CHANGED
@@ -29,8 +29,14 @@ conn = Net::HTTP.Proxy(proxy.host, proxy.port).new("www.google.com")
|
|
29
29
|
conn.set_debug_output $stdout
|
30
30
|
conn.start() do |http|
|
31
31
|
nego_auth = Win32::SSPI::NegotiateAuth.new
|
32
|
-
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token }
|
33
|
-
|
32
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.get_initial_token("Negotiate") }
|
33
|
+
if sr["Proxy-Authenticate"].include? "Negotiate"
|
34
|
+
resp = http.get "/", { "Proxy-Authorization" => "Negotiate " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
35
|
+
elsif sr["Proxy-Authenticate"].include? "NTLM"
|
36
|
+
sr = http.request_get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.get_initial_token("NTLM") }
|
37
|
+
resp = http.get "/", { "Proxy-Authorization" => "NTLM " + nego_auth.complete_authentication(sr["Proxy-Authenticate"].split(" ").last.strip) }
|
38
|
+
end
|
39
|
+
|
34
40
|
# Google redirects to country of origins domain if not US.
|
35
41
|
raise "Response code not as expected: #{resp.inspect}" unless resp.code.to_i == 200 || resp.code.to_i == 302
|
36
42
|
resp = http.get "/foobar.html"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubysspi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: "1.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Bailey
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-08
|
12
|
+
date: 2008-12-08 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|