rubyntlm 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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