rubyntlm 0.6.6 → 0.6.8
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +48 -48
- data/lib/net/ntlm/blob.rb +11 -10
- data/lib/net/ntlm/channel_binding.rb +13 -9
- data/lib/net/ntlm/client/session.rb +34 -145
- data/lib/net/ntlm/client/session_crypto.rb +131 -0
- data/lib/net/ntlm/client.rb +8 -9
- data/lib/net/ntlm/encode_util.rb +39 -38
- data/lib/net/ntlm/exceptions.rb +3 -0
- data/lib/net/ntlm/field.rb +29 -31
- data/lib/net/ntlm/field_set.rb +39 -18
- data/lib/net/ntlm/int16_le.rb +8 -8
- data/lib/net/ntlm/int32_le.rb +8 -7
- data/lib/net/ntlm/int64_le.rb +8 -7
- data/lib/net/ntlm/md4.rb +102 -64
- data/lib/net/ntlm/message/type0.rb +4 -7
- data/lib/net/ntlm/message/type1.rb +8 -9
- data/lib/net/ntlm/message/type2.rb +87 -67
- data/lib/net/ntlm/message/type3.rb +43 -41
- data/lib/net/ntlm/message.rb +116 -111
- data/lib/net/ntlm/rc4.rb +51 -44
- data/lib/net/ntlm/response.rb +112 -0
- data/lib/net/ntlm/security_buffer.rb +13 -15
- data/lib/net/ntlm/string.rb +8 -7
- data/lib/net/ntlm/target_info.rb +52 -44
- data/lib/net/ntlm/version.rb +3 -1
- data/lib/net/ntlm.rb +37 -125
- data/lib/rubyntlm.rb +3 -1
- metadata +6 -45
- data/.devcontainer/devcontainer.json +0 -22
- data/.github/dependabot.yml +0 -10
- data/.github/workflows/build.yml +0 -55
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/Gemfile +0 -20
- data/Rakefile +0 -37
- data/examples/http.rb +0 -86
- data/examples/imap.rb +0 -73
- data/examples/smtp.rb +0 -94
- data/rubyntlm.gemspec +0 -28
- data/spec/lib/net/ntlm/blob_spec.rb +0 -14
- data/spec/lib/net/ntlm/channel_binding_spec.rb +0 -15
- data/spec/lib/net/ntlm/client/session_spec.rb +0 -85
- data/spec/lib/net/ntlm/client_spec.rb +0 -62
- data/spec/lib/net/ntlm/encode_util_spec.rb +0 -14
- data/spec/lib/net/ntlm/field_set_spec.rb +0 -31
- data/spec/lib/net/ntlm/field_spec.rb +0 -32
- data/spec/lib/net/ntlm/int16_le_spec.rb +0 -16
- data/spec/lib/net/ntlm/int32_le_spec.rb +0 -17
- data/spec/lib/net/ntlm/int64_le_spec.rb +0 -17
- data/spec/lib/net/ntlm/md4_spec.rb +0 -16
- data/spec/lib/net/ntlm/message/type0_spec.rb +0 -19
- data/spec/lib/net/ntlm/message/type1_spec.rb +0 -129
- data/spec/lib/net/ntlm/message/type2_spec.rb +0 -131
- data/spec/lib/net/ntlm/message/type3_spec.rb +0 -336
- data/spec/lib/net/ntlm/message_spec.rb +0 -15
- data/spec/lib/net/ntlm/security_buffer_spec.rb +0 -62
- data/spec/lib/net/ntlm/string_spec.rb +0 -70
- data/spec/lib/net/ntlm/target_info_spec.rb +0 -74
- data/spec/lib/net/ntlm/version_spec.rb +0 -26
- data/spec/lib/net/ntlm_spec.rb +0 -133
- data/spec/spec_helper.rb +0 -51
- data/spec/support/certificates/sha_256_hash.pem +0 -19
- data/spec/support/shared/examples/net/ntlm/field_shared.rb +0 -25
- data/spec/support/shared/examples/net/ntlm/fieldset_shared.rb +0 -239
- data/spec/support/shared/examples/net/ntlm/int_shared.rb +0 -43
- data/spec/support/shared/examples/net/ntlm/message_shared.rb +0 -35
data/examples/smtp.rb
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
# $Id: smtp.rb,v 1.2 2006/10/05 01:36:52 koheik Exp $
|
|
2
|
-
require 'socket'
|
|
3
|
-
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
|
4
|
-
require 'net/ntlm'
|
|
5
|
-
|
|
6
|
-
$user = nil
|
|
7
|
-
$passwd = nil
|
|
8
|
-
|
|
9
|
-
$host = "localhost"
|
|
10
|
-
$port = 25
|
|
11
|
-
|
|
12
|
-
$debug = true
|
|
13
|
-
|
|
14
|
-
def readline(f)
|
|
15
|
-
(l = f.gets).chomp!
|
|
16
|
-
puts "srv> " + l if $debug
|
|
17
|
-
l
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def writeline(f, str)
|
|
21
|
-
puts "cli> " + str if $debug
|
|
22
|
-
f.print str + "\r\n"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def main
|
|
26
|
-
s = TCPSocket.new($host, $port)
|
|
27
|
-
|
|
28
|
-
# greetings
|
|
29
|
-
readline s
|
|
30
|
-
writeline s, "EHLO #{$host}"
|
|
31
|
-
while(line = readline(s))
|
|
32
|
-
login = true if /^250-AUTH=LOGIN/ =~ line
|
|
33
|
-
ntlm = true if /^250-AUTH.+NTLM.*/ =~ line
|
|
34
|
-
break if /^250 OK/ =~ line
|
|
35
|
-
end
|
|
36
|
-
unless ntlm and login
|
|
37
|
-
raise RuntimeError, "it looks like the server doesn't support NTLM Login"
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# send Type1 Message
|
|
41
|
-
t1 = Net::NTLM::Message::Type1.new()
|
|
42
|
-
writeline s, "AUTH NTLM " + t1.encode64
|
|
43
|
-
|
|
44
|
-
# receive Type2 Message, i hope
|
|
45
|
-
line = readline s
|
|
46
|
-
unless /334 (.+)/ =~ line
|
|
47
|
-
raise RuntimeError, "i don't recognize this: #{line}"
|
|
48
|
-
end
|
|
49
|
-
t2 = Net::NTLM::Message.decode64($1)
|
|
50
|
-
|
|
51
|
-
unless $user and $passwd
|
|
52
|
-
target = t2.target_name
|
|
53
|
-
target = Net::NTLM::decode_utf16le(target) if t2.has_flag?(:UNICODE)
|
|
54
|
-
puts "Target: #{target}"
|
|
55
|
-
print "User name: "
|
|
56
|
-
($user = $stdin.readline).chomp!
|
|
57
|
-
print "Password: "
|
|
58
|
-
($passwd = $stdin.readline).chomp!
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# send Type3 Message
|
|
62
|
-
t3 = t2.response({:user => $user, :password => $passwd}, {:ntlmv2 => true})
|
|
63
|
-
writeline s, t3.encode64
|
|
64
|
-
|
|
65
|
-
# and result is...
|
|
66
|
-
line = readline s
|
|
67
|
-
|
|
68
|
-
unless /^235(.+)Authentication successful./i =~ line
|
|
69
|
-
raise RuntimeError, "sorry, authentication failed."
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# do real job here like...
|
|
73
|
-
# from = $user
|
|
74
|
-
# to = "billg"
|
|
75
|
-
# writeline s, "MAIL FROM: #{from}"
|
|
76
|
-
# readline s
|
|
77
|
-
# writeline s, "RCPT TO: #{to}"
|
|
78
|
-
# readline s
|
|
79
|
-
# writeline s, "DATA"
|
|
80
|
-
# readline s
|
|
81
|
-
# writeline s, "From: #{from}"
|
|
82
|
-
# writeline s, "To: #{to}"
|
|
83
|
-
# writeline s, "blab blab blab..."
|
|
84
|
-
# writeline s, "#{from}"
|
|
85
|
-
# writeline s, "."
|
|
86
|
-
# readline s
|
|
87
|
-
|
|
88
|
-
# say bye
|
|
89
|
-
writeline s, "QUIT"
|
|
90
|
-
s.close
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
main
|
|
94
|
-
|
data/rubyntlm.gemspec
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'lib', 'net', 'ntlm', 'version')
|
|
2
|
-
|
|
3
|
-
Gem::Specification.new do |s|
|
|
4
|
-
s.platform = Gem::Platform::RUBY
|
|
5
|
-
s.name = 'rubyntlm'
|
|
6
|
-
s.version = Net::NTLM::VERSION::STRING
|
|
7
|
-
s.summary = 'Ruby/NTLM library.'
|
|
8
|
-
s.description = 'Ruby/NTLM provides message creator and parser for the NTLM authentication.'
|
|
9
|
-
|
|
10
|
-
s.authors = ['Kohei Kajimoto','Paul Morton']
|
|
11
|
-
s.email = ['koheik@gmail.com','paul.e.morton@gmail.com']
|
|
12
|
-
s.homepage = 'https://github.com/winrb/rubyntlm'
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
s.files = `git ls-files`.split($/)
|
|
16
|
-
s.require_paths = ["lib"]
|
|
17
|
-
|
|
18
|
-
s.required_ruby_version = '>= 3.0.0'
|
|
19
|
-
|
|
20
|
-
s.license = 'MIT'
|
|
21
|
-
|
|
22
|
-
s.add_dependency "base64"
|
|
23
|
-
|
|
24
|
-
s.metadata["rubygems_mfa_required"] = "true"
|
|
25
|
-
s.metadata["source_code_uri"] = s.homepage
|
|
26
|
-
s.metadata["changelog_uri"] = "#{s.homepage}/blob/master/CHANGELOG.md"
|
|
27
|
-
s.metadata["bug_tracker_uri"] = "#{s.homepage}/issues"
|
|
28
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Blob do
|
|
2
|
-
|
|
3
|
-
fields = [
|
|
4
|
-
{ :name => :blob_signature, :class => Net::NTLM::Int32LE, :value => 257, :active => true },
|
|
5
|
-
{ :name => :reserved, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
|
6
|
-
{ :name => :timestamp, :class => Net::NTLM::Int64LE, :value => 0, :active => true },
|
|
7
|
-
{ :name => :challenge, :class => Net::NTLM::String, :value => '', :active => true },
|
|
8
|
-
{ :name => :unknown1, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
|
9
|
-
{ :name => :target_info, :class => Net::NTLM::String, :value => '', :active => true },
|
|
10
|
-
{ :name => :unknown2, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
it_behaves_like 'a fieldset', fields
|
|
14
|
-
end
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::ChannelBinding do
|
|
2
|
-
let(:certificates_path) { 'spec/support/certificates' }
|
|
3
|
-
let(:sha_256_path) { File.join(certificates_path, 'sha_256_hash.pem') }
|
|
4
|
-
let(:sha_256_cert) { OpenSSL::X509::Certificate.new(File.read(sha_256_path)) }
|
|
5
|
-
let(:cert_hash) { "\x04\x0E\x56\x28\xEC\x4A\x98\x29\x91\x70\x73\x62\x03\x7B\xB2\x3C".force_encoding(Encoding::ASCII_8BIT) }
|
|
6
|
-
|
|
7
|
-
subject { Net::NTLM::ChannelBinding.create(sha_256_cert) }
|
|
8
|
-
|
|
9
|
-
describe '#channel_binding_token' do
|
|
10
|
-
|
|
11
|
-
it 'returns the correct hash' do
|
|
12
|
-
expect(subject.channel_binding_token).to eq cert_hash
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Client::Session do
|
|
2
|
-
let(:t2_challenge) { Net::NTLM::Message.decode64 "TlRMTVNTUAACAAAADAAMADgAAAA1goriAAyk1DmJUnUAAAAAAAAAAFAAUABEAAAABgLwIwAAAA9TAEUAUgBWAEUAUgACAAwAUwBFAFIAVgBFAFIAAQAMAFMARQBSAFYARQBSAAQADABzAGUAcgB2AGUAcgADAAwAcwBlAHIAdgBlAHIABwAIADd7mrNaB9ABAAAAAA==" }
|
|
3
|
-
let(:inst) { Net::NTLM::Client::Session.new(nil, t2_challenge) }
|
|
4
|
-
let(:user_session_key) {["3c4918ff0b33e2603e5d7ceaf34bb7d5"].pack("H*")}
|
|
5
|
-
let(:client_sign_key) {["f7f97a82ec390f9c903dac4f6aceb132"].pack("H*")}
|
|
6
|
-
let(:client_seal_key) {["6f0d99535033951cbe499cd1914fe9ee"].pack("H*")}
|
|
7
|
-
let(:server_sign_key) {["f7f97a82ec390f9c903dac4f6aceb132"].pack("H*")}
|
|
8
|
-
let(:server_seal_key) {["6f0d99535033951cbe499cd1914fe9ee"].pack("H*")}
|
|
9
|
-
|
|
10
|
-
describe "#sign_message" do
|
|
11
|
-
|
|
12
|
-
it "signs a message and when KEY_EXCHANGE is true" do
|
|
13
|
-
expect(inst).to receive(:client_sign_key).and_return(client_sign_key)
|
|
14
|
-
expect(inst).to receive(:client_seal_key).and_return(client_seal_key)
|
|
15
|
-
expect(inst).to receive(:negotiate_key_exchange?).and_return(true)
|
|
16
|
-
sm = inst.sign_message("Test Message")
|
|
17
|
-
str = "01000000b35ccd60c110c52f00000000"
|
|
18
|
-
expect(sm.unpack("H*")[0]).to eq(str)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe "#verify_signature" do
|
|
24
|
-
|
|
25
|
-
it "verifies a message signature" do
|
|
26
|
-
expect(inst).to receive(:server_sign_key).and_return(server_sign_key)
|
|
27
|
-
expect(inst).to receive(:server_seal_key).and_return(server_seal_key)
|
|
28
|
-
expect(inst).to receive(:negotiate_key_exchange?).and_return(true)
|
|
29
|
-
sig = "01000000b35ccd60c110c52f00000000"
|
|
30
|
-
sm = inst.verify_signature([sig].pack("H*"), "Test Message")
|
|
31
|
-
expect(sm).to be true
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
describe "#seal_message" do
|
|
37
|
-
it "should seal the message" do
|
|
38
|
-
expect(inst).to receive(:client_seal_key).and_return(client_seal_key)
|
|
39
|
-
emsg = inst.seal_message("rubyntlm")
|
|
40
|
-
expect(emsg.unpack("H*")[0]).to eq("d7389b9604f6274f")
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
describe "#unseal_message" do
|
|
45
|
-
it "should unseal the message" do
|
|
46
|
-
expect(inst).to receive(:server_seal_key).and_return(server_seal_key)
|
|
47
|
-
msg = inst.unseal_message(["d7389b9604f6274f"].pack("H*"))
|
|
48
|
-
expect(msg).to eq("rubyntlm")
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
describe "#exported_session_key" do
|
|
53
|
-
it "returns a random 16-byte key when negotiate_key_exchange? is true" do
|
|
54
|
-
expect(inst).to receive(:negotiate_key_exchange?).and_return(true)
|
|
55
|
-
expect(inst).not_to receive(:user_session_key)
|
|
56
|
-
inst.exported_session_key
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it "returns the user_session_key when negotiate_key_exchange? is false" do
|
|
60
|
-
expect(inst).to receive(:negotiate_key_exchange?).and_return(false)
|
|
61
|
-
expect(inst).to receive(:user_session_key).and_return(user_session_key)
|
|
62
|
-
inst.exported_session_key
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
context 'when authenticating anonymously' do
|
|
67
|
-
let(:inst) { Net::NTLM::Client::Session.new(Net::NTLM::Client.new('', ''), t2_challenge) }
|
|
68
|
-
|
|
69
|
-
describe "#authenticate!" do
|
|
70
|
-
it "should set the response fields correctly" do
|
|
71
|
-
t3 = inst.authenticate!
|
|
72
|
-
expect(t3).to be_a(Net::NTLM::Message::Type3)
|
|
73
|
-
expect(t3.lm_response).to eq("\x00".b)
|
|
74
|
-
expect(t3.ntlm_response).to eq('')
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
describe "#is_anonymous?" do
|
|
79
|
-
it "should be true" do
|
|
80
|
-
expect(inst.is_anonymous?).to be_truthy
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Client do
|
|
2
|
-
let(:inst) { Net::NTLM::Client.new("test", "test01", :workstation => "testhost") }
|
|
3
|
-
let(:user_session_key) {["3c4918ff0b33e2603e5d7ceaf34bb7d5"].pack("H*")}
|
|
4
|
-
|
|
5
|
-
describe "#init_context" do
|
|
6
|
-
|
|
7
|
-
it "returns a default Type1 message" do
|
|
8
|
-
t1 = inst.init_context
|
|
9
|
-
expect(t1).to be_instance_of Net::NTLM::Message::Type1
|
|
10
|
-
expect(t1.domain).to eq("")
|
|
11
|
-
expect(t1.workstation).to eq("testhost")
|
|
12
|
-
expect(t1).to have_flag(:UNICODE)
|
|
13
|
-
expect(t1).to have_flag(:OEM)
|
|
14
|
-
expect(t1).to have_flag(:SIGN)
|
|
15
|
-
expect(t1).to have_flag(:SEAL)
|
|
16
|
-
expect(t1).to have_flag(:REQUEST_TARGET)
|
|
17
|
-
expect(t1).to have_flag(:NTLM)
|
|
18
|
-
expect(t1).to have_flag(:ALWAYS_SIGN)
|
|
19
|
-
expect(t1).to have_flag(:NTLM2_KEY)
|
|
20
|
-
expect(t1).to have_flag(:KEY128)
|
|
21
|
-
expect(t1).to have_flag(:KEY_EXCHANGE)
|
|
22
|
-
expect(t1).to have_flag(:KEY56)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "clears session variable on new init_context" do
|
|
26
|
-
inst.instance_variable_set :@session, "BADSESSION"
|
|
27
|
-
expect(inst.session).to eq("BADSESSION")
|
|
28
|
-
inst.init_context
|
|
29
|
-
expect(inst.session).to be_nil
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it "returns a Type1 message with custom flags" do
|
|
33
|
-
flags = Net::NTLM::FLAGS[:UNICODE] | Net::NTLM::FLAGS[:REQUEST_TARGET] | Net::NTLM::FLAGS[:NTLM]
|
|
34
|
-
inst = Net::NTLM::Client.new("test", "test01", :workstation => "testhost", :flags => flags)
|
|
35
|
-
t1 = inst.init_context
|
|
36
|
-
expect(t1).to be_instance_of Net::NTLM::Message::Type1
|
|
37
|
-
expect(t1.domain).to eq("")
|
|
38
|
-
expect(t1.workstation).to eq("testhost")
|
|
39
|
-
expect(t1).to have_flag(:UNICODE)
|
|
40
|
-
expect(t1).not_to have_flag(:OEM)
|
|
41
|
-
expect(t1).not_to have_flag(:SIGN)
|
|
42
|
-
expect(t1).not_to have_flag(:SEAL)
|
|
43
|
-
expect(t1).to have_flag(:REQUEST_TARGET)
|
|
44
|
-
expect(t1).to have_flag(:NTLM)
|
|
45
|
-
expect(t1).not_to have_flag(:ALWAYS_SIGN)
|
|
46
|
-
expect(t1).not_to have_flag(:NTLM2_KEY)
|
|
47
|
-
expect(t1).not_to have_flag(:KEY128)
|
|
48
|
-
expect(t1).not_to have_flag(:KEY_EXCHANGE)
|
|
49
|
-
expect(t1).not_to have_flag(:KEY56)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "calls authenticate! when we receive a Challenge Message" do
|
|
53
|
-
t2_challenge = "TlRMTVNTUAACAAAADAAMADgAAAA1goriAAyk1DmJUnUAAAAAAAAAAFAAUABEAAAABgLwIwAAAA9TAEUAUgBWAEUAUgACAAwAUwBFAFIAVgBFAFIAAQAMAFMARQBSAFYARQBSAAQADABzAGUAcgB2AGUAcgADAAwAcwBlAHIAdgBlAHIABwAIADd7mrNaB9ABAAAAAA=="
|
|
54
|
-
session = double("session")
|
|
55
|
-
expect(session).to receive(:authenticate!)
|
|
56
|
-
expect(Net::NTLM::Client::Session).to receive(:new).with(inst, instance_of(Net::NTLM::Message::Type2), nil).and_return(session)
|
|
57
|
-
inst.init_context t2_challenge
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
end
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::EncodeUtil do
|
|
2
|
-
|
|
3
|
-
context '#encode_utf16le' do
|
|
4
|
-
it 'should convert an ASCII string to UTF' do
|
|
5
|
-
expect(Net::NTLM::EncodeUtil.encode_utf16le('Test'.encode(::Encoding::ASCII_8BIT).freeze)).to eq("T\x00e\x00s\x00t\x00")
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
context '#decode_utf16le' do
|
|
10
|
-
it 'should convert a UTF string to ASCII' do
|
|
11
|
-
expect(Net::NTLM::EncodeUtil.decode_utf16le("T\x00e\x00s\x00t\x00".freeze)).to eq('Test')
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
end
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::FieldSet do
|
|
2
|
-
|
|
3
|
-
fields = []
|
|
4
|
-
|
|
5
|
-
it_behaves_like 'a fieldset', fields
|
|
6
|
-
|
|
7
|
-
subject(:fieldset_class) do
|
|
8
|
-
Class.new(Net::NTLM::FieldSet)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
context 'an instance' do
|
|
12
|
-
subject(:fieldset_object) do
|
|
13
|
-
fieldset_class.string(:test_string, { :value => 'Test', :active => true, :size => 4})
|
|
14
|
-
fieldset_class.string(:test_string2, { :value => 'Foo', :active => true, :size => 3})
|
|
15
|
-
fieldset_class.new
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'should serialize all the fields' do
|
|
19
|
-
expect(fieldset_object.serialize).to eq('TestFoo')
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'should parse a string across the fields' do
|
|
23
|
-
fieldset_object.parse('FooBarBaz')
|
|
24
|
-
expect(fieldset_object.serialize).to eq('FooBarB')
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'should return an aggregate size of all the fields' do
|
|
28
|
-
expect(fieldset_object.size).to eq(7)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Field do
|
|
2
|
-
|
|
3
|
-
it_behaves_like 'a field', 'Foo', false
|
|
4
|
-
|
|
5
|
-
context 'with no size specified' do
|
|
6
|
-
let (:field_without_size) { Net::NTLM::Field.new({ :value => 'Foo', :active => true }) }
|
|
7
|
-
it 'should set size to 0 if not active' do
|
|
8
|
-
expect(field_without_size.size).to eq(0)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'should return 0 if active but no size specified' do
|
|
12
|
-
field_without_size.active = true
|
|
13
|
-
expect(field_without_size.size).to eq(0)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
context 'with a size specified' do
|
|
18
|
-
let (:field_with_size) { Net::NTLM::Field.new({ :value => 'Foo', :active => true, :size => 100 }) }
|
|
19
|
-
|
|
20
|
-
it 'should return the size provided in the initialize options if active' do
|
|
21
|
-
expect(field_with_size.size).to eq(100)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it 'should still return 0 if not active' do
|
|
25
|
-
field_with_size.active = false
|
|
26
|
-
expect(field_with_size.size).to eq(0)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Int16LE do
|
|
2
|
-
|
|
3
|
-
int_values = {
|
|
4
|
-
:default => 15,
|
|
5
|
-
:default_hex => "\x0F\x00",
|
|
6
|
-
:alt => 14,
|
|
7
|
-
:alt_hex => "\x0E\x00",
|
|
8
|
-
:small => "\x0F",
|
|
9
|
-
:size => 2,
|
|
10
|
-
:bits => 16
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
it_behaves_like 'a field', 15, false
|
|
14
|
-
it_behaves_like 'an integer field', int_values
|
|
15
|
-
|
|
16
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Int32LE do
|
|
2
|
-
|
|
3
|
-
int_values = {
|
|
4
|
-
:default => 252716124,
|
|
5
|
-
:default_hex => "\x5C\x24\x10\x0f",
|
|
6
|
-
:alt => 235938908,
|
|
7
|
-
:alt_hex => "\x5C\x24\x10\x0e",
|
|
8
|
-
:small => "\x0F\x00",
|
|
9
|
-
:size => 4,
|
|
10
|
-
:bits => 32
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
it_behaves_like 'a field', 252716124, false
|
|
15
|
-
it_behaves_like 'an integer field', int_values
|
|
16
|
-
|
|
17
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Int64LE do
|
|
2
|
-
|
|
3
|
-
int_values = {
|
|
4
|
-
:default => 5294967295,
|
|
5
|
-
:default_hex => [5294967295 & 0x00000000ffffffff, 5294967295 >> 32].pack("V2"),
|
|
6
|
-
:alt => 5294967294,
|
|
7
|
-
:alt_hex => [5294967294 & 0x00000000ffffffff, 5294967294 >> 32].pack("V2"),
|
|
8
|
-
:small => "\x5C\x24\x10\x0f",
|
|
9
|
-
:size => 8,
|
|
10
|
-
:bits => 64
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
it_behaves_like 'a field', 252716124, false
|
|
15
|
-
it_behaves_like 'an integer field', int_values
|
|
16
|
-
|
|
17
|
-
end
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Md4 do
|
|
2
|
-
describe '.digest' do
|
|
3
|
-
it 'hashes binary input containing high bytes' do
|
|
4
|
-
# Independently calculated with OpenSSL's legacy MD4 provider.
|
|
5
|
-
expect(described_class.digest("\xff".b).unpack('H*').first).
|
|
6
|
-
to eq('82c167af8e345bd055487af8d2b540c9')
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it 'preserves the caller input and encoding' do
|
|
10
|
-
input = "\xff".b.freeze
|
|
11
|
-
described_class.digest(input)
|
|
12
|
-
expect(input).to eq("\xff".b)
|
|
13
|
-
expect(input.encoding).to eq(Encoding::ASCII_8BIT)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Message::Type0 do
|
|
2
|
-
|
|
3
|
-
fields = [
|
|
4
|
-
{ :name => :sign, :class => Net::NTLM::String, :value => Net::NTLM::SSP_SIGN, :active => true },
|
|
5
|
-
{ :name => :type, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
|
6
|
-
]
|
|
7
|
-
flags = [
|
|
8
|
-
:UNICODE,
|
|
9
|
-
:OEM,
|
|
10
|
-
:REQUEST_TARGET,
|
|
11
|
-
:NTLM,
|
|
12
|
-
:ALWAYS_SIGN,
|
|
13
|
-
:NTLM2_KEY
|
|
14
|
-
]
|
|
15
|
-
it_behaves_like 'a fieldset', fields
|
|
16
|
-
it_behaves_like 'a message', flags
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
RSpec.describe Net::NTLM::Message::Type1 do
|
|
2
|
-
fields = [
|
|
3
|
-
{ :name => :sign, :class => Net::NTLM::String, :value => Net::NTLM::SSP_SIGN, :active => true },
|
|
4
|
-
{ :name => :type, :class => Net::NTLM::Int32LE, :value => 1, :active => true },
|
|
5
|
-
{ :name => :flag, :class => Net::NTLM::Int32LE, :value => Net::NTLM::DEFAULT_FLAGS[:TYPE1], :active => true },
|
|
6
|
-
{ :name => :domain, :class => Net::NTLM::SecurityBuffer, :value => '', :active => true },
|
|
7
|
-
{ :name => :workstation, :class => Net::NTLM::SecurityBuffer, :value => Socket.gethostname, :active => true },
|
|
8
|
-
{ :name => :os_version, :class => Net::NTLM::String, :value => '', :active => false },
|
|
9
|
-
]
|
|
10
|
-
flags = [
|
|
11
|
-
:UNICODE,
|
|
12
|
-
:OEM,
|
|
13
|
-
:REQUEST_TARGET,
|
|
14
|
-
:NTLM,
|
|
15
|
-
:ALWAYS_SIGN,
|
|
16
|
-
:NTLM2_KEY
|
|
17
|
-
]
|
|
18
|
-
it_behaves_like 'a fieldset', fields
|
|
19
|
-
it_behaves_like 'a message', flags
|
|
20
|
-
|
|
21
|
-
let(:type1_packet) {"TlRMTVNTUAABAAAAB4IIAAAAAAAgAAAAAAAAACAAAAA="}
|
|
22
|
-
|
|
23
|
-
it 'should deserialize' do
|
|
24
|
-
t1 = Net::NTLM::Message.decode64(type1_packet)
|
|
25
|
-
expect(t1.class).to eq(Net::NTLM::Message::Type1)
|
|
26
|
-
expect(t1.domain).to eq('')
|
|
27
|
-
expect(t1.flag).to eq(557575)
|
|
28
|
-
expect(t1.os_version).to eq('')
|
|
29
|
-
expect(t1.sign).to eq("NTLMSSP\0")
|
|
30
|
-
expect(t1.type).to eq(1)
|
|
31
|
-
expect(t1.workstation).to eq('')
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'should serialize' do
|
|
35
|
-
t1 = Net::NTLM::Message::Type1.new
|
|
36
|
-
t1.workstation = ''
|
|
37
|
-
expect(t1.encode64).to eq(type1_packet)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
describe '.parse' do
|
|
41
|
-
subject(:message) { described_class.parse(data) }
|
|
42
|
-
# http://davenport.sourceforge.net/ntlm.html#appendixC7
|
|
43
|
-
context 'NTLM2 Session Response Authentication; NTLM2 Signing and Sealing Using the 128-bit NTLM2 Session Response User Session Key With Key Exchange Negotiated' do
|
|
44
|
-
let(:data) do
|
|
45
|
-
['4e544c4d5353500001000000b78208e000000000000000000000000000000000'].pack('H*')
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'should set the magic' do
|
|
49
|
-
expect(message.sign).to eql(Net::NTLM::SSP_SIGN)
|
|
50
|
-
end
|
|
51
|
-
it 'should set the type' do
|
|
52
|
-
expect(message.type).to eq(1)
|
|
53
|
-
end
|
|
54
|
-
it 'should set the flags' do
|
|
55
|
-
expect(message.flag).to eq(0xe00882b7)
|
|
56
|
-
expect(message).to have_flag(:UNICODE)
|
|
57
|
-
expect(message).to have_flag(:OEM)
|
|
58
|
-
expect(message).to have_flag(:REQUEST_TARGET)
|
|
59
|
-
expect(message).to have_flag(:SIGN)
|
|
60
|
-
expect(message).to have_flag(:SEAL)
|
|
61
|
-
expect(message).to have_flag(:NTLM)
|
|
62
|
-
expect(message).to have_flag(:ALWAYS_SIGN)
|
|
63
|
-
expect(message).to have_flag(:NTLM2_KEY)
|
|
64
|
-
expect(message).to have_flag(:KEY128)
|
|
65
|
-
expect(message).to have_flag(:KEY_EXCHANGE)
|
|
66
|
-
expect(message).to have_flag(:KEY56)
|
|
67
|
-
end
|
|
68
|
-
it 'should have empty workstation' do
|
|
69
|
-
expect(message.workstation).to be_empty
|
|
70
|
-
end
|
|
71
|
-
it 'should have empty domain' do
|
|
72
|
-
expect(message.domain).to be_empty
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
# http://davenport.sourceforge.net/ntlm.html#appendixC9
|
|
78
|
-
context 'NTLMv2 Authentication; NTLM1 Signing and Sealing Using the 40-bit NTLMv2 User Session Key' do
|
|
79
|
-
let(:data) { ['4e544c4d53535000010000003782000000000000000000000000000000000000'].pack('H*') }
|
|
80
|
-
|
|
81
|
-
it 'should set the magic' do
|
|
82
|
-
expect(message.sign).to eql(Net::NTLM::SSP_SIGN)
|
|
83
|
-
end
|
|
84
|
-
it 'should set the type' do
|
|
85
|
-
expect(message.type).to eq(1)
|
|
86
|
-
end
|
|
87
|
-
it 'should set the flags' do
|
|
88
|
-
expect(message.flag).to eq(0x00008237)
|
|
89
|
-
expect(message).to have_flag(:UNICODE)
|
|
90
|
-
expect(message).to have_flag(:OEM)
|
|
91
|
-
expect(message).to have_flag(:REQUEST_TARGET)
|
|
92
|
-
expect(message).to have_flag(:SIGN)
|
|
93
|
-
expect(message).to have_flag(:SEAL)
|
|
94
|
-
expect(message).to have_flag(:NTLM)
|
|
95
|
-
expect(message).to have_flag(:ALWAYS_SIGN)
|
|
96
|
-
end
|
|
97
|
-
it 'should have empty workstation' do
|
|
98
|
-
expect(message.workstation).to be_empty
|
|
99
|
-
end
|
|
100
|
-
it 'should have empty domain' do
|
|
101
|
-
expect(message.domain).to be_empty
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
context 'NTLMv2 with OS version' do
|
|
106
|
-
let(:data) { ['4e544c4d5353500001000000978208e2000000000000000000000000000000000602f0230000000f'].pack('H*') }
|
|
107
|
-
|
|
108
|
-
it 'should set the magic' do
|
|
109
|
-
expect(message.sign).to eql(Net::NTLM::SSP_SIGN)
|
|
110
|
-
end
|
|
111
|
-
it 'should set the type' do
|
|
112
|
-
expect(message.type).to eq(1)
|
|
113
|
-
end
|
|
114
|
-
it 'should have empty workstation' do
|
|
115
|
-
expect(message.workstation).to be_empty
|
|
116
|
-
end
|
|
117
|
-
it 'should have empty domain' do
|
|
118
|
-
expect(message.domain).to be_empty
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it 'should set OS version info' do
|
|
122
|
-
expect(message.os_version).to eq(['0602f0230000000f'].pack('H*'))
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
end
|