rubyntlm 0.2.0 → 0.3.0

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.
@@ -0,0 +1,2 @@
1
+ .yardoc
2
+ /doc
@@ -2,11 +2,5 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - 1.9.2
5
- - jruby-18mode
6
- - jruby-19mode
7
- - rbx-18mode
8
5
  - rbx-19mode
9
- - ruby-head
10
- - jruby-head
11
- - 1.8.7
12
- - ree
6
+ - ruby-head
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gemspec
3
+ gemspec
@@ -1,17 +1,27 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubyntlm (0.2.0)
4
+ rubyntlm (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ diff-lcs (1.2.1)
9
10
  rake (10.0.3)
11
+ rspec (2.13.0)
12
+ rspec-core (~> 2.13.0)
13
+ rspec-expectations (~> 2.13.0)
14
+ rspec-mocks (~> 2.13.0)
15
+ rspec-core (2.13.1)
16
+ rspec-expectations (2.13.0)
17
+ diff-lcs (>= 1.1.3, < 2.0)
18
+ rspec-mocks (2.13.0)
10
19
 
11
20
  PLATFORMS
21
+ java
12
22
  ruby
13
23
 
14
24
  DEPENDENCIES
15
- bundler (~> 1.3)
16
25
  rake
26
+ rspec
17
27
  rubyntlm!
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ruby/NTLM -- NTLM Authentication Library for Ruby
2
2
 
3
- [![Build Status](https://travis-ci.org/winrb/[rubyntlm].png)](https://travis-ci.org/winrb/rubyntlm)
3
+ [![Build Status](https://travis-ci.org/WinRb/rubyntlm.png)](https://travis-ci.org/WinRb/rubyntlm)
4
4
 
5
5
  Ruby/NTLM provides message creator and parser for the NTLM authentication.
6
6
 
data/Rakefile CHANGED
@@ -1,10 +1,21 @@
1
1
  require "bundler/gem_tasks"
2
- require 'rake/testtask'
3
2
 
4
- task :default => [:test]
3
+ task :default => [:spec]
5
4
 
6
- Rake::TestTask.new(:test) do |t|
7
- t.test_files = FileList[ "test/*.rb" ]
8
- t.warning = true
9
- t.verbose = true
5
+
6
+ require 'rspec/core/rake_task'
7
+
8
+ desc 'Default: run specs.'
9
+ task :default => :spec
10
+
11
+ desc "Run specs unit tests"
12
+ RSpec::Core::RakeTask.new do |t|
13
+ t.pattern = "./spec/unit/*_spec.rb"
10
14
  end
15
+
16
+ desc "Generate code coverage"
17
+ RSpec::Core::RakeTask.new(:coverage) do |t|
18
+ t.pattern = "./spec/unit/*_spec.rb" # don't need this, it's default.
19
+ t.rcov = true
20
+ t.rcov_opts = ['--exclude', 'spec']
21
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # = net/ntlm.rb
3
4
  #
@@ -45,15 +46,14 @@
45
46
  require 'base64'
46
47
  require 'openssl'
47
48
  require 'openssl/digest'
48
- require 'kconv'
49
49
  require 'socket'
50
50
 
51
- module Net #:nodoc:
52
- module NTLM #:nodoc:
53
-
54
- module VERSION #:nodoc:
51
+ module Net
52
+ module NTLM
53
+ # @private
54
+ module VERSION
55
55
  MAJOR = 0
56
- MINOR = 2
56
+ MINOR = 3
57
57
  TINY = 0
58
58
  STRING = [MAJOR, MINOR, TINY].join('.')
59
59
  end
@@ -68,14 +68,14 @@ module Net #:nodoc:
68
68
  :UNICODE => 0x00000001,
69
69
  :OEM => 0x00000002,
70
70
  :REQUEST_TARGET => 0x00000004,
71
- # :UNKNOWN => 0x00000008,
71
+ :MBZ9 => 0x00000008,
72
72
  :SIGN => 0x00000010,
73
73
  :SEAL => 0x00000020,
74
- # :UNKNOWN => 0x00000040,
74
+ :NEG_DATAGRAM => 0x00000040,
75
75
  :NETWARE => 0x00000100,
76
76
  :NTLM => 0x00000200,
77
- # :UNKNOWN => 0x00000400,
78
- # :UNKNOWN => 0x00000800,
77
+ :NEG_NT_ONLY => 0x00000400,
78
+ :MBZ7 => 0x00000800,
79
79
  :DOMAIN_SUPPLIED => 0x00001000,
80
80
  :WORKSTATION_SUPPLIED => 0x00002000,
81
81
  :LOCAL_CALL => 0x00004000,
@@ -85,7 +85,7 @@ module Net #:nodoc:
85
85
  :NTLM2_KEY => 0x00080000,
86
86
  :KEY128 => 0x20000000,
87
87
  :KEY56 => 0x80000000
88
- }
88
+ }.freeze
89
89
 
90
90
  FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
91
91
 
@@ -95,24 +95,36 @@ module Net #:nodoc:
95
95
  :TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
96
96
  }
97
97
 
98
- # module functions
98
+
99
99
  class << self
100
+
101
+ # Decode a UTF16 string to a ASCII string
102
+ # @param [String] str The string to convert
100
103
  def decode_utf16le(str)
101
- Kconv.kconv(swap16(str), Kconv::ASCII, Kconv::UTF16)
104
+ str.encode(Encoding::UTF_8, Encoding::UTF_16LE).force_encoding('UTF-8')
102
105
  end
103
106
 
107
+ # Encodes a ASCII string to a UTF16 string
108
+ # @param [String] str The string to convert
109
+ # @note This implementation may seem stupid but the problem is that UTF16-LE and UTF-8 are incompatiable
110
+ # encodings. This library uses string contatination to build the packet bytes. The end result is that
111
+ # you can either marshal the encodings elsewhere of simply know that each time you call encode_utf16le
112
+ # the function will convert the string bytes to UTF-16LE and note the encoding as UTF-8 so that byte
113
+ # concatination works seamlessly.
104
114
  def encode_utf16le(str)
105
- swap16(Kconv.kconv(str, Kconv::UTF16, Kconv::ASCII))
115
+ str = str.force_encoding('UTF-8') if [::Encoding::ASCII_8BIT,::Encoding::US_ASCII].include?(str.encoding)
116
+ str.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('UTF-8')
106
117
  end
107
-
118
+
119
+ # Conver the value to a 64-Bit Little Endian Int
120
+ # @param [String] val The string to convert
108
121
  def pack_int64le(val)
109
122
  [val & 0x00000000ffffffff, val >> 32].pack("V2")
110
123
  end
111
-
112
- def swap16(str)
113
- str.unpack("v*").pack("n*")
114
- end
115
124
 
125
+ # Builds an array of strings that are 7 characters long
126
+ # @param [String] str The string to split
127
+ # @api private
116
128
  def split7(str)
117
129
  s = str.dup
118
130
  until s.empty?
@@ -120,7 +132,10 @@ module Net #:nodoc:
120
132
  end
121
133
  ret
122
134
  end
123
-
135
+
136
+ # Not sure what this is doing
137
+ # @param [String] str String to generate keys for
138
+ # @api private
124
139
  def gen_keys(str)
125
140
  split7(str).map{ |str7|
126
141
  bits = split7(str7.unpack("B*")[0]).inject('')\
@@ -137,11 +152,16 @@ module Net #:nodoc:
137
152
  }
138
153
  end
139
154
 
155
+ # Generates a Lan Manager Hash
156
+ # @param [String] password The password to base the hash on
140
157
  def lm_hash(password)
141
158
  keys = gen_keys password.upcase.ljust(14, "\0")
142
159
  apply_des(LM_MAGIC, keys).join
143
160
  end
144
161
 
162
+ # Generate a NTLM Hash
163
+ # @param [String] password The password to base the hash on
164
+ # @option opt :unicode (false) Unicode encode the password
145
165
  def ntlm_hash(password, opt = {})
146
166
  pwd = password.dup
147
167
  unless opt[:unicode]
@@ -150,6 +170,11 @@ module Net #:nodoc:
150
170
  OpenSSL::Digest::MD4.digest pwd
151
171
  end
152
172
 
173
+ # Generate a NTLMv2 Hash
174
+ # @param [String] user The username
175
+ # @param [String] password The password
176
+ # @param [String] target The domain or workstaiton to authenticate to
177
+ # @option opt :unicode (false) Unicode encode the domain
153
178
  def ntlmv2_hash(user, password, target, opt={})
154
179
  ntlmhash = ntlm_hash(password, opt)
155
180
  userdomain = (user + target).upcase
@@ -159,7 +184,6 @@ module Net #:nodoc:
159
184
  OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain)
160
185
  end
161
186
 
162
- # responses
163
187
  def lm_response(arg)
164
188
  begin
165
189
  hash = arg[:lm_hash]
@@ -254,6 +278,7 @@ module Net #:nodoc:
254
278
 
255
279
 
256
280
  # base classes for primitives
281
+ # @private
257
282
  class Field
258
283
  attr_accessor :active, :value
259
284
 
@@ -297,7 +322,6 @@ module Net #:nodoc:
297
322
  end
298
323
  end
299
324
 
300
-
301
325
  class Int16LE < Field
302
326
  def initialize(opt)
303
327
  super(opt)
@@ -361,34 +385,44 @@ module Net #:nodoc:
361
385
  # base class of data structure
362
386
  class FieldSet
363
387
  class << FieldSet
364
- def define(&block)
365
- c = Class.new(self)
366
- def c.inherited(subclass)
367
- proto = @proto
368
- subclass.instance_eval {
369
- @proto = proto
370
- }
371
- end
372
- c.module_eval(&block)
373
- c
374
- end
375
388
 
389
+
390
+ # @macro string_security_buffer
391
+ # @method $1
392
+ # @method $1=
393
+ # @return [String]
376
394
  def string(name, opts)
377
395
  add_field(name, String, opts)
378
396
  end
379
397
 
398
+ # @macro int16le_security_buffer
399
+ # @method $1
400
+ # @method $1=
401
+ # @return [Int16LE]
380
402
  def int16LE(name, opts)
381
403
  add_field(name, Int16LE, opts)
382
404
  end
383
405
 
406
+ # @macro int32le_security_buffer
407
+ # @method $1
408
+ # @method $1=
409
+ # @return [Int32LE]
384
410
  def int32LE(name, opts)
385
411
  add_field(name, Int32LE, opts)
386
412
  end
387
413
 
414
+ # @macro int64le_security_buffer
415
+ # @method $1
416
+ # @method $1=
417
+ # @return [Int64]
388
418
  def int64LE(name, opts)
389
419
  add_field(name, Int64LE, opts)
390
420
  end
391
421
 
422
+ # @macro security_buffer
423
+ # @method $1
424
+ # @method $1=
425
+ # @return [SecurityBuffer]
392
426
  def security_buffer(name, opts)
393
427
  add_field(name, SecurityBuffer, opts)
394
428
  end
@@ -466,8 +500,7 @@ module Net #:nodoc:
466
500
  end
467
501
  end
468
502
 
469
-
470
- Blob = FieldSet.define {
503
+ class Blob < FieldSet
471
504
  int32LE :blob_signature, {:value => BLOB_SIGN}
472
505
  int32LE :reserved, {:value => 0}
473
506
  int64LE :timestamp, {:value => 0}
@@ -475,15 +508,14 @@ module Net #:nodoc:
475
508
  int32LE :unknown1, {:value => 0}
476
509
  string :target_info, {:value => "", :size => 0}
477
510
  int32LE :unknown2, {:value => 0}
478
- }
511
+ end
512
+
513
+ class SecurityBuffer < FieldSet
479
514
 
480
- SecurityBuffer = FieldSet.define {
481
515
  int16LE :length, {:value => 0}
482
516
  int16LE :allocated, {:value => 0}
483
517
  int32LE :offset, {:value => 0}
484
- }
485
518
 
486
- class SecurityBuffer
487
519
  attr_accessor :active
488
520
  def initialize(opts)
489
521
  super()
@@ -519,7 +551,8 @@ module Net #:nodoc:
519
551
  @active ? @value.size : 0
520
552
  end
521
553
  end
522
-
554
+
555
+ # @private false
523
556
  class Message < FieldSet
524
557
  class << Message
525
558
  def parse(str)
@@ -579,8 +612,6 @@ module Net #:nodoc:
579
612
  end
580
613
 
581
614
 
582
- private
583
-
584
615
  def security_buffers
585
616
  @alist.find_all{|n, f| f.instance_of?(SecurityBuffer)}
586
617
  end
@@ -597,23 +628,25 @@ module Net #:nodoc:
597
628
  end
598
629
 
599
630
  # sub class definitions
600
-
601
- Type0 = Message.define {
631
+ class Type0 < Message
602
632
  string :sign, {:size => 8, :value => SSP_SIGN}
603
633
  int32LE :type, {:value => 0}
604
- }
605
-
606
- Type1 = Message.define {
634
+ end
635
+
636
+ # @private false
637
+ class Type1 < Message
638
+
607
639
  string :sign, {:size => 8, :value => SSP_SIGN}
608
640
  int32LE :type, {:value => 1}
609
641
  int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] }
610
642
  security_buffer :domain, {:value => ""}
611
643
  security_buffer :workstation, {:value => Socket.gethostname }
612
644
  string :padding, {:size => 0, :value => "", :active => false }
613
- }
614
645
 
615
- class Type1
616
646
  class << Type1
647
+ # Parses a Type 1 Message
648
+ # @param [String] str A string containing Type 1 data
649
+ # @return [Type1] The parsed Type 1 message
617
650
  def parse(str)
618
651
  t = new
619
652
  t.parse(str)
@@ -621,6 +654,7 @@ module Net #:nodoc:
621
654
  end
622
655
  end
623
656
 
657
+ # @!visibility private
624
658
  def parse(str)
625
659
  super(str)
626
660
  enable(:domain) if has_flag?(:DOMAIN_SUPPLIED)
@@ -633,7 +667,10 @@ module Net #:nodoc:
633
667
  end
634
668
  end
635
669
 
636
- Type2 = Message.define{
670
+
671
+ # @private false
672
+ class Type2 < Message
673
+
637
674
  string :sign, {:size => 8, :value => SSP_SIGN}
638
675
  int32LE :type, {:value => 2}
639
676
  security_buffer :target_name, {:size => 0, :value => ""}
@@ -642,17 +679,19 @@ module Net #:nodoc:
642
679
  int64LE :context, {:value => 0, :active => false}
643
680
  security_buffer :target_info, {:value => "", :active => false}
644
681
  string :padding, {:size => 0, :value => "", :active => false }
645
- }
646
-
647
- class Type2
682
+
648
683
  class << Type2
684
+ # Parse a Type 2 packet
685
+ # @param [String] str A string containing Type 2 data
686
+ # @return [Type2]
649
687
  def parse(str)
650
688
  t = new
651
689
  t.parse(str)
652
690
  t
653
691
  end
654
692
  end
655
-
693
+
694
+ # @!visibility private
656
695
  def parse(str)
657
696
  super(str)
658
697
  if has_flag?(:TARGET_INFO)
@@ -665,7 +704,16 @@ module Net #:nodoc:
665
704
  super(str)
666
705
  end
667
706
  end
668
-
707
+
708
+ # Generates a Type 3 response based on the Type 2 Information
709
+ # @return [Type3]
710
+ # @option arg [String] :username The username to authenticate with
711
+ # @option arg [String] :password The user's password
712
+ # @option arg [String] :domain ('') The domain to authenticate to
713
+ # @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation
714
+ # @option opt [Boolean] :use_default_target (False) Use the domain supplied by the server in the Type 2 packet
715
+ # @note An empty :domain option authenticates to the local machine.
716
+ # @note The :use_default_target has presidence over the :domain option
669
717
  def response(arg, opt = {})
670
718
  usr = arg[:user]
671
719
  pwd = arg[:password]
@@ -677,7 +725,7 @@ module Net #:nodoc:
677
725
  if opt[:workstation]
678
726
  ws = opt[:workstation]
679
727
  else
680
- ws = ""
728
+ ws = Socket.gethostname
681
729
  end
682
730
 
683
731
  if opt[:client_challenge]
@@ -692,6 +740,7 @@ module Net #:nodoc:
692
740
  usr = NTLM::decode_utf16le(usr)
693
741
  pwd = NTLM::decode_utf16le(pwd)
694
742
  ws = NTLM::decode_utf16le(ws)
743
+ domain = NTLM::decode_utf16le(domain)
695
744
  opt[:unicode] = false
696
745
  end
697
746
 
@@ -699,9 +748,14 @@ module Net #:nodoc:
699
748
  usr = NTLM::encode_utf16le(usr)
700
749
  pwd = NTLM::encode_utf16le(pwd)
701
750
  ws = NTLM::encode_utf16le(ws)
751
+ domain = NTLM::encode_utf16le(domain)
702
752
  opt[:unicode] = true
703
753
  end
704
754
 
755
+ if opt[:use_default_target]
756
+ domain = self.target_name
757
+ end
758
+
705
759
  ti = self.target_info
706
760
 
707
761
  chal = self[:challenge].serialize
@@ -729,8 +783,9 @@ module Net #:nodoc:
729
783
  end
730
784
  end
731
785
 
732
-
733
- Type3 = Message.define{
786
+ # @private false
787
+ class Type3 < Message
788
+
734
789
  string :sign, {:size => 8, :value => SSP_SIGN}
735
790
  int32LE :type, {:value => 3}
736
791
  security_buffer :lm_response, {:value => ""}
@@ -740,16 +795,26 @@ module Net #:nodoc:
740
795
  security_buffer :workstation, {:value => ""}
741
796
  security_buffer :session_key, {:value => "", :active => false }
742
797
  int64LE :flag, {:value => 0, :active => false }
743
- }
744
-
745
- class Type3
798
+
746
799
  class << Type3
800
+ # Parse a Type 3 packet
801
+ # @param [String] str A string containing Type 3 data
802
+ # @return [Type2]
747
803
  def parse(str)
748
804
  t = new
749
805
  t.parse(str)
750
806
  t
751
807
  end
752
-
808
+
809
+ # Builds a Type 3 packet
810
+ # @note All options must be properly encoded with either unicode or oem encoding
811
+ # @return [Type3]
812
+ # @option arg [String] :lm_response The LM hash
813
+ # @option arg [String] :ntlm_response The NTLM hash
814
+ # @option arg [String] :domain The domain to authenticate to
815
+ # @option arg [String] :workstation The name of the calling workstation
816
+ # @option arg [String] :session_key The session key
817
+ # @option arg [Integer] :flag Flags for the packet
753
818
  def create(arg, opt ={})
754
819
  t = new
755
820
  t.lm_response = arg[:lm_response]
@@ -759,14 +824,13 @@ module Net #:nodoc:
759
824
 
760
825
  if arg[:workstation]
761
826
  t.workstation = arg[:workstation]
762
- else
763
- t.workstation = NTLM.encode_utf16le(Socket.gethostname)
764
827
  end
765
828
 
766
829
  if arg[:session_key]
767
830
  t.enable(:session_key)
768
831
  t.session_key = arg[session_key]
769
832
  end
833
+
770
834
  if arg[:flag]
771
835
  t.enable(:session_key)
772
836
  t.enable(:flag)
@@ -16,7 +16,9 @@ Gem::Specification.new do |s|
16
16
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
17
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
18
  s.require_paths = ["lib"]
19
+
20
+ s.required_ruby_version = '1.9.2'
19
21
 
20
- s.add_development_dependency "bundler", "~> 1.3"
21
22
  s.add_development_dependency "rake"
23
+ s.add_development_dependency "rspec"
22
24
  end
@@ -0,0 +1,175 @@
1
+ # encoding: UTF-8
2
+ $:.unshift(File.expand_path(File.dirname(__FILE__) << '../lib'))
3
+ require 'net/ntlm'
4
+
5
+ describe Net::NTLM::Message do
6
+ let(:type1_packet) {"TlRMTVNTUAABAAAAB4IIAAAAAAAgAAAAAAAAACAAAAA="}
7
+ let(:type2_packet) {"TlRMTVNTUAACAAAAHAAcADgAAAAFgooCJ+UA1//+ZM4AAAAAAAAAAJAAkABUAAAABgGxHQAAAA9WAEEARwBSAEEATgBUAC0AMgAwADAAOABSADIAAgAcAFYAQQBHAFIAQQBOAFQALQAyADAAMAA4AFIAMgABABwAVgBBAEcAUgBBAE4AVAAtADIAMAAwADgAUgAyAAQAHAB2AGEAZwByAGEAbgB0AC0AMgAwADAAOABSADIAAwAcAHYAYQBnAHIAYQBuAHQALQAyADAAMAA4AFIAMgAHAAgAZBMdFHQnzgEAAAAA"}
8
+ let(:type3_packet) {"TlRMTVNTUAADAAAAGAAYAEQAAADAAMAAXAAAAAAAAAAcAQAADgAOABwBAAAUABQAKgEAAAAAAAA+AQAABYKKAgAAAADVS27TfQGmWxSSbXmolTUQyxJmD8ISQuBKKHFKC8GksUZISYc8Ps9RAQEAAAAAAAAANasTdCfOAcsSZg/CEkLgAAAAAAIAHABWAEEARwBSAEEATgBUAC0AMgAwADAAOABSADIAAQAcAFYAQQBHAFIAQQBOAFQALQAyADAAMAA4AFIAMgAEABwAdgBhAGcAcgBhAG4AdAAtADIAMAAwADgAUgAyAAMAHAB2AGEAZwByAGEAbgB0AC0AMgAwADAAOABSADIABwAIAGQTHRR0J84BAAAAAAAAAAB2AGEAZwByAGEAbgB0AGsAbwBiAGUALgBsAG8AYwBhAGwA"}
9
+ describe Net::NTLM::Message::Type1 do
10
+ it 'should deserialize' do
11
+ t1 = Net::NTLM::Message.decode64(type1_packet)
12
+ t1.class.should == Net::NTLM::Message::Type1
13
+ t1.domain.should == ''
14
+ t1.flag.should == 557575
15
+ t1.padding.should == ''
16
+ t1.sign.should == "NTLMSSP\0"
17
+ t1.type.should == 1
18
+ t1.workstation.should == ''
19
+ end
20
+
21
+ it 'should serialize' do
22
+ t1 = Net::NTLM::Message::Type1.new
23
+ t1.workstation = ''
24
+ t1.encode64.should == type1_packet
25
+ end
26
+ end
27
+
28
+ describe Net::NTLM::Message::Type2 do
29
+ it 'should deserialize' do
30
+ t2 = Net::NTLM::Message.decode64(type2_packet)
31
+ t2.class.should == Net::NTLM::Message::Type2
32
+ t2.challenge.should == 14872292244261496103
33
+ t2.context.should == 0
34
+ t2.flag.should == 42631685
35
+ t2.padding.should == ("\x06\x01\xB1\x1D\0\0\0\x0F".force_encoding('ASCII-8BIT'))
36
+ t2.sign.should == "NTLMSSP\0"
37
+ Net::NTLM.decode_utf16le(t2.target_info).should == "\u0002\u001CVAGRANT-2008R2\u0001\u001CVAGRANT-2008R2\u0004\u001Cvagrant-2008R2\u0003\u001Cvagrant-2008R2\a\b፤ᐝ❴ǎ\0\0"
38
+ Net::NTLM.decode_utf16le(t2.target_name).should == "VAGRANT-2008R2"
39
+ t2.type.should == 2
40
+ end
41
+
42
+ it 'should serialize' do
43
+ source = Net::NTLM::Message.decode64(type2_packet)
44
+
45
+ t2 = Net::NTLM::Message::Type2.new
46
+ t2.challenge = source.challenge
47
+ t2.context = source.context
48
+ t2.flag = source.flag
49
+ t2.padding = source.padding
50
+ t2.sign = source.sign
51
+ t2.target_info = source.target_info
52
+ t2.target_name = source.target_name
53
+ t2.type = source.type
54
+ t2.enable(:context)
55
+ t2.enable(:target_info)
56
+ t2.enable(:padding)
57
+
58
+ t2.encode64.should == type2_packet
59
+ end
60
+
61
+ it 'should generate a type 3 response' do
62
+ t2 = Net::NTLM::Message.decode64(type2_packet)
63
+
64
+ type3_known = Net::NTLM::Message.decode64(type3_packet)
65
+ type3_known.flag = 0x028a8205
66
+ type3_known.enable(:session_key)
67
+ type3_known.enable(:flag)
68
+
69
+ t3 = t2.response({:user => 'vagrant', :password => 'vagrant', :domain => ''}, {:ntlmv2 => true, :workstation => 'kobe.local'})
70
+ t3.domain.should == type3_known.domain
71
+ t3.flag.should == type3_known.flag
72
+ t3.sign.should == "NTLMSSP\0"
73
+ t3.workstation.should == "k\0o\0b\0e\0.\0l\0o\0c\0a\0l\0"
74
+ t3.user.should == "v\0a\0g\0r\0a\0n\0t\0"
75
+ t3.session_key.should == ''
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ describe Net::NTLM do
82
+ let(:passwd) {"SecREt01"}
83
+ let(:user) {"user"}
84
+ let(:domain) {"domain"}
85
+ let(:challenge) {["0123456789abcdef"].pack("H*")}
86
+ let(:client_ch) {["ffffff0011223344"].pack("H*")}
87
+ let(:timestamp) {1055844000}
88
+ let(:trgt_info) {[
89
+ "02000c0044004f004d00410049004e00" +
90
+ "01000c00530045005200560045005200" +
91
+ "0400140064006f006d00610069006e00" +
92
+ "2e0063006f006d000300220073006500" +
93
+ "72007600650072002e0064006f006d00" +
94
+ "610069006e002e0063006f006d000000" +
95
+ "0000"
96
+ ].pack("H*")}
97
+
98
+ it 'should generate an lm_hash' do
99
+ Net::NTLM::lm_hash(passwd).should == ["ff3750bcc2b22412c2265b23734e0dac"].pack("H*")
100
+ end
101
+
102
+ it 'should generate an ntlm_hash' do
103
+ Net::NTLM::ntlm_hash(passwd).should == ["cd06ca7c7e10c99b1d33b7485a2ed808"].pack("H*")
104
+ end
105
+
106
+ it 'should generate an ntlmv2_hash' do
107
+ Net::NTLM::ntlmv2_hash(user, passwd, domain).should == ["04b8e0ba74289cc540826bab1dee63ae"].pack("H*")
108
+ end
109
+
110
+ it 'should generate an lm_response' do
111
+ Net::NTLM::lm_response(
112
+ {
113
+ :lm_hash => Net::NTLM::lm_hash(passwd),
114
+ :challenge => challenge
115
+ }
116
+ ).should == ["c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"].pack("H*")
117
+ end
118
+
119
+ it 'should generate an ntlm_response' do
120
+ ntlm_hash = Net::NTLM::ntlm_hash(passwd)
121
+ Net::NTLM::ntlm_response(
122
+ {
123
+ :ntlm_hash => ntlm_hash,
124
+ :challenge => challenge
125
+ }
126
+ ).should == ["25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"].pack("H*")
127
+ end
128
+
129
+ it 'should generate a lvm2_response' do
130
+ Net::NTLM::lmv2_response(
131
+ {
132
+ :ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
133
+ :challenge => challenge
134
+ },
135
+ { :client_challenge => client_ch }
136
+ ).should == ["d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"].pack("H*")
137
+ end
138
+
139
+ it 'should generate a ntlmv2_response' do
140
+ Net::NTLM::ntlmv2_response(
141
+ {
142
+ :ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
143
+ :challenge => challenge,
144
+ :target_info => trgt_info
145
+ },
146
+ {
147
+ :timestamp => timestamp,
148
+ :client_challenge => client_ch
149
+ }
150
+ ).should == [
151
+ "cbabbca713eb795d04c97abc01ee4983" +
152
+ "01010000000000000090d336b734c301" +
153
+ "ffffff00112233440000000002000c00" +
154
+ "44004f004d00410049004e0001000c00" +
155
+ "53004500520056004500520004001400" +
156
+ "64006f006d00610069006e002e006300" +
157
+ "6f006d00030022007300650072007600" +
158
+ "650072002e0064006f006d0061006900" +
159
+ "6e002e0063006f006d00000000000000" +
160
+ "0000"
161
+ ].pack("H*")
162
+ end
163
+
164
+ it 'should generate a ntlm2_session' do
165
+ session = Net::NTLM::ntlm2_session(
166
+ {
167
+ :ntlm_hash => Net::NTLM::ntlm_hash(passwd),
168
+ :challenge => challenge
169
+ },
170
+ { :client_challenge => client_ch }
171
+ )
172
+ session[0].should == ["ffffff001122334400000000000000000000000000000000"].pack("H*")
173
+ session[1].should == ["10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"].pack("H*")
174
+ end
175
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyntlm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,26 +10,26 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-03-22 00:00:00.000000000 Z
13
+ date: 2013-03-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: bundler
16
+ name: rake
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
- - - ~>
20
+ - - '>='
21
21
  - !ruby/object:Gem::Version
22
- version: '1.3'
22
+ version: '0'
23
23
  type: :development
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  none: false
27
27
  requirements:
28
- - - ~>
28
+ - - '>='
29
29
  - !ruby/object:Gem::Version
30
- version: '1.3'
30
+ version: '0'
31
31
  - !ruby/object:Gem::Dependency
32
- name: rake
32
+ name: rspec
33
33
  requirement: !ruby/object:Gem::Requirement
34
34
  none: false
35
35
  requirements:
@@ -52,6 +52,7 @@ executables: []
52
52
  extensions: []
53
53
  extra_rdoc_files: []
54
54
  files:
55
+ - .gitignore
55
56
  - .travis.yml
56
57
  - CHANGELOG.md
57
58
  - Gemfile
@@ -64,7 +65,7 @@ files:
64
65
  - lib/net/ntlm.rb
65
66
  - lib/rubyntlm.rb
66
67
  - rubyntlm.gemspec
67
- - test/function_test.rb
68
+ - spec/unit/ntlm_spec.rb
68
69
  homepage: https://github.com/winrb/rubyntlm
69
70
  licenses: []
70
71
  post_install_message:
@@ -74,12 +75,9 @@ require_paths:
74
75
  required_ruby_version: !ruby/object:Gem::Requirement
75
76
  none: false
76
77
  requirements:
77
- - - '>='
78
+ - - '='
78
79
  - !ruby/object:Gem::Version
79
- version: '0'
80
- segments:
81
- - 0
82
- hash: -254558294721854043
80
+ version: 1.9.2
83
81
  required_rubygems_version: !ruby/object:Gem::Requirement
84
82
  none: false
85
83
  requirements:
@@ -88,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
86
  version: '0'
89
87
  segments:
90
88
  - 0
91
- hash: -254558294721854043
89
+ hash: -473842116073612192
92
90
  requirements: []
93
91
  rubyforge_project:
94
92
  rubygems_version: 1.8.25
@@ -96,4 +94,4 @@ signing_key:
96
94
  specification_version: 3
97
95
  summary: Ruby/NTLM library.
98
96
  test_files:
99
- - test/function_test.rb
97
+ - spec/unit/ntlm_spec.rb
@@ -1,111 +0,0 @@
1
- # $Id$
2
- $:.unshift(File.dirname(__FILE__) + '/../lib')
3
- require 'test/unit'
4
- require 'net/ntlm'
5
-
6
- class FunctionTest < Test::Unit::TestCase #:nodoc:
7
- def setup
8
- @passwd = "SecREt01"
9
- @user = "user"
10
- @domain = "domain"
11
- @challenge = ["0123456789abcdef"].pack("H*")
12
- @client_ch = ["ffffff0011223344"].pack("H*")
13
- @timestamp = 1055844000
14
- @trgt_info = [
15
- "02000c0044004f004d00410049004e00" +
16
- "01000c00530045005200560045005200" +
17
- "0400140064006f006d00610069006e00" +
18
- "2e0063006f006d000300220073006500" +
19
- "72007600650072002e0064006f006d00" +
20
- "610069006e002e0063006f006d000000" +
21
- "0000"
22
- ].pack("H*")
23
- end
24
-
25
- def test_lm_hash
26
- ahash = ["ff3750bcc2b22412c2265b23734e0dac"].pack("H*")
27
- assert_equal ahash, Net::NTLM::lm_hash(@passwd)
28
- end
29
-
30
- def test_ntlm_hash
31
- ahash = ["cd06ca7c7e10c99b1d33b7485a2ed808"].pack("H*")
32
- assert_equal ahash, Net::NTLM::ntlm_hash(@passwd)
33
- end
34
-
35
- def test_ntlmv2_hash
36
- ahash = ["04b8e0ba74289cc540826bab1dee63ae"].pack("H*")
37
- assert_equal ahash, Net::NTLM::ntlmv2_hash(@user, @passwd, @domain)
38
- end
39
-
40
- def test_lm_response
41
- ares = ["c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"].pack("H*")
42
- assert_equal ares, Net::NTLM::lm_response(
43
- {
44
- :lm_hash => Net::NTLM::lm_hash(@passwd),
45
- :challenge => @challenge
46
- }
47
- )
48
- end
49
-
50
- def test_ntlm_response
51
- ares = ["25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"].pack("H*")
52
- ntlm_hash = Net::NTLM::ntlm_hash(@passwd)
53
- assert_equal ares, Net::NTLM::ntlm_response(
54
- {
55
- :ntlm_hash => ntlm_hash,
56
- :challenge => @challenge
57
- }
58
- )
59
- end
60
-
61
- def test_lmv2_response
62
- ares = ["d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"].pack("H*")
63
- assert_equal ares, Net::NTLM::lmv2_response(
64
- {
65
- :ntlmv2_hash => Net::NTLM::ntlmv2_hash(@user, @passwd, @domain),
66
- :challenge => @challenge
67
- },
68
- { :client_challenge => @client_ch }
69
- )
70
- end
71
-
72
- def test_ntlmv2_response
73
- ares = [
74
- "cbabbca713eb795d04c97abc01ee4983" +
75
- "01010000000000000090d336b734c301" +
76
- "ffffff00112233440000000002000c00" +
77
- "44004f004d00410049004e0001000c00" +
78
- "53004500520056004500520004001400" +
79
- "64006f006d00610069006e002e006300" +
80
- "6f006d00030022007300650072007600" +
81
- "650072002e0064006f006d0061006900" +
82
- "6e002e0063006f006d00000000000000" +
83
- "0000"
84
- ].pack("H*")
85
- assert_equal ares, Net::NTLM::ntlmv2_response(
86
- {
87
- :ntlmv2_hash => Net::NTLM::ntlmv2_hash(@user, @passwd, @domain),
88
- :challenge => @challenge,
89
- :target_info => @trgt_info
90
- },
91
- {
92
- :timestamp => @timestamp,
93
- :client_challenge => @client_ch
94
- }
95
- )
96
- end
97
-
98
- def test_ntlm2_session
99
- acha = ["ffffff001122334400000000000000000000000000000000"].pack("H*")
100
- ares = ["10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"].pack("H*")
101
- session = Net::NTLM::ntlm2_session(
102
- {
103
- :ntlm_hash => Net::NTLM::ntlm_hash(@passwd),
104
- :challenge => @challenge
105
- },
106
- { :client_challenge => @client_ch }
107
- )
108
- assert_equal acha, session[0]
109
- assert_equal ares, session[1]
110
- end
111
- end