net-ssh-kerberos 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,10 @@
1
1
  = net-ssh-kerberos
2
2
 
3
- Adds Kerberos support to Net::SSH
3
+ Adds Kerberos support to Net::SSH.
4
+
5
+ Windows support uses Microsoft SSPI for Kerberos integration.
6
+
7
+ Kerberos support for UNIX and OS X coming soon.
4
8
 
5
9
  == Copyright
6
10
 
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 0
3
3
  :minor: 1
4
- :patch: 0
4
+ :patch: 2
@@ -10,13 +10,15 @@ module Net
10
10
  class GssapiWithMic < Abstract
11
11
  include Net::SSH::Kerberos::Constants
12
12
 
13
- # OID 1.2.840.113554.1.2.2
14
- SUPPORTED_OID = #"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
15
- [ 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x1, 0x2, 0x2 ].pack("C*")
13
+ # OID 1.2.840.113554.1.2.2 - Kerberos 5 (RFC 1964)
14
+ SUPPORTED_OID = "\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
15
+ #[ 0x6, 0x9, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x1, 0x2, 0x2 ].pack("C*")
16
16
 
17
17
  # Attempts to perform gssapi-with-mic Kerberos authentication
18
18
  def authenticate(next_service, username, password=nil)
19
- sspi = nil
19
+ gss_klass = (defined?(Net::SSH::Kerberos::SSPI::Context) ?
20
+ Net::SSH::Kerberos::SSPI::Context : Net::SSH::Kerberos::GSS::Context)
21
+ gss = nil
20
22
 
21
23
  # Try to start gssapi-with-mic authentication.
22
24
  debug { "trying kerberos authentication" }
@@ -43,14 +45,14 @@ module Net
43
45
  end
44
46
 
45
47
  # Try to complete the handshake.
46
- sspi = Net::SSH::Kerberos::SSPI::GSSContext.new
47
- sspi.create username, hostname
48
+ gss = gss_klass.new
49
+ gss.create username, hostname
48
50
  debug { "gssapi-with-mic handshaking" }
49
- until sspi.established?
50
- token = sspi.init(token)
51
+ until gss.established?
52
+ token = gss.init(token)
51
53
  if token && token.length > 0
52
54
  send_message Net::SSH::Buffer.from(:byte, USERAUTH_GSSAPI_TOKEN, :string, token)
53
- unless sspi.established?
55
+ unless gss.established?
54
56
  message = session.next_message
55
57
  case message.type
56
58
  when USERAUTH_GSSAPI_ERROR
@@ -72,7 +74,7 @@ module Net
72
74
 
73
75
  # Attempt the actual authentication.
74
76
  debug { "gssapi-with-mic authenticating" }
75
- mic = sspi.get_mic Net::SSH::Buffer.from(:string, session_id, :byte, USERAUTH_REQUEST, :string, username,
77
+ mic = gss.get_mic Net::SSH::Buffer.from(:string, session_id, :byte, USERAUTH_REQUEST, :string, username,
76
78
  :string, next_service, :string, "gssapi-with-mic").to_s
77
79
  if mic.nil?
78
80
  info { "gssapi-with-mic failed (context#get_mic)" }
@@ -91,7 +93,7 @@ module Net
91
93
  raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
92
94
  end
93
95
  ensure
94
- sspi and sspi.dispose
96
+ gss and gss.dispose
95
97
  end
96
98
 
97
99
  private
@@ -1,7 +1,18 @@
1
1
  require 'net/ssh'
2
2
  require 'net/ssh/kerberos/constants'
3
3
  #require 'net/ssh/kerberos/kex'
4
- require 'net/ssh/kerberos/sspi'
4
+ if RUBY_PLATFORM.include?('win') && ! RUBY_PLATFORM.include?('dar'); then
5
+ begin
6
+ require 'net/ssh/kerberos/sspi'
7
+ rescue Exception => e
8
+ if RuntimeError === e and e.message =~ /^LoadLibrary: ([^\s]+)/
9
+ $stderr.puts "error: While loading Kerberos SSPI: failed to load library: #{$1}"
10
+ else
11
+ raise e
12
+ end
13
+ end
14
+ end
15
+ require 'net/ssh/kerberos/gss' unless defined?(Net::SSH::Kerberos::SSPI::Context)
5
16
  require 'net/ssh/authentication/methods/gssapi_with_mic'
6
17
 
7
18
  module Net
@@ -0,0 +1,7 @@
1
+ $stderr.puts "warning: Kerberos support for non-Windows systems is not yet implemented."
2
+
3
+ require 'net/ssh/kerberos/gss/api'
4
+ require 'net/ssh/kerberos/gss/context'
5
+
6
+ module Net; module SSH; module Kerberos; module GSS
7
+ end; end; end; end
@@ -0,0 +1,4 @@
1
+
2
+ module Net; module SSH; module Kerberos; module GSS; class API
3
+
4
+ end; end; end; end; end
@@ -0,0 +1,7 @@
1
+ require 'net/ssh/kerberos/gss/api'
2
+
3
+ module Net; module SSH; module Kerberos; module GSS; class Context
4
+
5
+ class GeneralError < StandardError; end
6
+
7
+ end; end; end; end; end
@@ -1,54 +1,5 @@
1
1
  require 'net/ssh/kerberos/sspi/api'
2
+ require 'net/ssh/kerberos/sspi/context'
2
3
 
3
- module Net; module SSH; module Kerberos
4
- module SSPI
5
-
6
- class State
7
- attr_accessor :name, :realm, :valid
8
- alias :valid? :valid
9
- end
10
-
11
- # Acquires credentials for SSPI (GSSAPI) authentication, and determines
12
- # the credential's username and realm.
13
- def sspi_acquire_credentials(state)
14
- #SecPkgCredentials_Names names
15
- #char *delimiter, *cp
16
-
17
- state.valid? and return true
18
-
19
- #sspi->from_server_token.BufferType = SECBUFFER_TOKEN | SECBUFFER_READONLY;
20
-
21
- # Acquire credentials
22
- sspi_acquire_credentials_handle
23
- names = sspi_query_credentials_names
24
- state.name, state.realm = *names.user_name.split('@')
25
-
26
- #debug((" FreeContextBuffer(%x)\n", names.sUserName));
27
- #result = SSPIResult.new(API::FreeContextBuffer(names.user.to_p))
28
- sspi_free_context_buffer names
29
- sspi_free_credentials_handle
30
-
31
- # Sometimes, Microsoft SSPI returns a UPN of the form "user@REALM@",
32
- # (Seen under WinXP pro after ksetup to a MIT realm). Deal with that.
33
- realm.chop if realm[-1] == '@'
34
-
35
- # Initialise the request flags.
36
- #sspi->request_flags = ISC_REQ_MUTUAL_AUTH |
37
- # ISC_REQ_INTEGRITY |
38
- # ISC_REQ_CONFIDENTIALITY |
39
- # ISC_REQ_ALLOCATE_MEMORY;
40
- #if (ssh->cfg.sspi_fwd_ticket)
41
- # sspi->request_flags |= ISC_REQ_DELEGATE;
42
-
43
- if ! sspi_construct_service_name state
44
- state.valid = true
45
- #if (!sspi_construct_service_name(ssh, sspi)) {
46
- #debug((" FreeCredentialsHandle(%s)\n", HDL(&sspi->credentials)));
47
- else
48
- sspi_free_credentials_handle
49
- end
50
- end
51
- end
52
- end; end; end
53
-
54
-
4
+ module Net; module SSH; module Kerberos; module SSPI
5
+ end; end; end; end
@@ -1,5 +1,5 @@
1
1
  require 'win32/sspi'
2
- require 'dl'
2
+ require 'dl'
3
3
 
4
4
  module Win32; module SSPI
5
5
 
@@ -77,9 +77,43 @@ module Win32; module SSPI
77
77
  CompleteAuthToken = Win32API.new("secur32", "CompleteAuthToken", 'pp', 'L')
78
78
  MakeSignature = Win32API.new("secur32", "MakeSignature", 'pLpL', 'L')
79
79
  FreeContextBuffer = Win32API.new("secur32", "FreeContextBuffer", 'P', 'L')
80
+
81
+ private
82
+
83
+ def self.method_missing(symbol, *args)
84
+ return super unless const_defined? symbol and Win32API === (api = const_get(symbol))
85
+ result = SSPIResult.new api.call(*args)
86
+ args = (1..(args.length)).inject([]) { |v,n| v << "a#{n}" }.join ', '
87
+ class_eval "def self.#{symbol}(#{args}); SSPIResult.new #{symbol}.call(#{args}) end"
88
+ result
89
+ end
80
90
  end
81
91
 
82
92
  SecPkgCredentialsNames = Struct.new(:user_name)
93
+
94
+ class SecurityHandle
95
+ def nil?; @struct.unpack('Q').first.zero? end
96
+ alias :to_str :to_p
97
+ end
98
+
99
+ class TimeStamp
100
+ def nil?; @struct.unpack('Q').first.zero? end
101
+ alias :to_str :to_p
102
+ end
103
+
104
+ class SSPIResult
105
+ def ok?; (value & 0x80000000).zero? end
106
+
107
+ def complete?; value.zero? end
108
+
109
+ def incomplete?; SEC_I_COMPLETE_NEEDED==value || SEC_I_COMPLETE_AND_CONTINUE==value end
110
+
111
+ def failure?; (value & 0x80000000).nonzero? end
112
+
113
+ def temporary_failure?
114
+ value==SEC_E_LOGON_DENIED || value==SEC_E_NO_AUTHENTICATING_AUTHORITY || value==SEC_E_NO_CREDENTIALS
115
+ end
116
+ end
83
117
 
84
118
  class SecPkgInfo
85
119
  attr_reader :struct
@@ -94,6 +128,7 @@ module Win32; module SSPI
94
128
  end
95
129
 
96
130
  def to_p; @struct ||= "\0" * 4 end
131
+ alias :to_str :to_p
97
132
  end
98
133
 
99
134
  class SecPkgSizes
@@ -109,6 +144,7 @@ module Win32; module SSPI
109
144
  end
110
145
 
111
146
  def to_p; @struct ||= "\0" * 16 end
147
+ alias :to_str :to_p
112
148
  end
113
149
 
114
150
  # Creates binary representaiton of a SecBufferDesc structure,
@@ -167,6 +203,7 @@ module Win32; module SSPI
167
203
  end.pack("LLP" * @bufferTokens.size)
168
204
  @struct ||= [SECBUFFER_VERSION, @bufferTokens.size, @sec_buffers].pack("LLP")
169
205
  end
206
+ alias :to_str :to_p
170
207
 
171
208
  private
172
209
 
@@ -189,94 +226,3 @@ module Win32; module SSPI
189
226
  end
190
227
 
191
228
  end; end
192
-
193
- module Net; module SSH; module Kerberos; module SSPI; class GSSContext
194
-
195
- class GeneralError < StandardError; end
196
-
197
- include Win32::SSPI
198
-
199
- def create(user, host)
200
- dispose if @credentials or @handle
201
- @credentials = CredHandle.new
202
- ts=TimeStamp.new
203
-
204
- result = SSPIResult.new(API::AcquireCredentialsHandle.call(
205
- nil, "Kerberos", SECPKG_CRED_OUTBOUND, nil, nil,
206
- nil, nil, @credentials.to_p, ts.to_p
207
- ))
208
- unless result.ok?
209
- @credentials = nil
210
- raise GeneralError, "Error acquiring credentials: #{result}"
211
- end
212
-
213
- buff = "\0\0\0\0"
214
- result = SSPIResult.new(API::QueryCredentialsAttributes.call(@credentials.to_p, SECPKG_CRED_ATTR_NAMES, buff))
215
- if result.ok?
216
- names = buff.to_ptr.ptr
217
- begin
218
- @cred_name = names.to_s.sub /^.*\\/, ''
219
- @cred_krb_name = @cred_name.gsub '@', '/';
220
- @server_name = Socket.gethostbyname(host)[0]
221
- @server_krb_name = "host/" + @server_name
222
- ensure
223
- API::FreeContextBuffer.call(names)
224
- end
225
- end
226
- cred_names = SecPkgCredentialsNames.new(names)
227
- end
228
-
229
- def init(token=nil)
230
- ctx = CtxtHandle.new
231
- ts = TimeStamp.new
232
- prev = @state[:handle].to_p if @state and @state[:handle]
233
- req = ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH | ISC_REQ_INTEGRITY
234
- output = SecurityBuffer.new
235
- input = SecurityBuffer.new(token) if token
236
- ctxAttr = "\0" * 4
237
- result = SSPIResult.new(API::InitializeSecurityContext.call(@credentials.to_p, prev, @server_krb_name,
238
- req, 0, SECURITY_NATIVE_DREP, input ? input.to_p : nil,
239
- 0, ctx.to_p, output.to_p, ctxAttr, ts.to_p))
240
- if SEC_I_COMPLETE_NEEDED == result || SEC_I_COMPLETE_AND_CONTINUE == result
241
- result = SSPIResult.new(API::CompleteAuthToken.call(ctx.to_p, output.to_p))
242
- end
243
- unless result.ok?
244
- input.token
245
- raise GeneralError, "Error initializing security context: #{result} #{input.inspect}"
246
- end
247
- @state = { :handle => ctx, :result => result, :token => output.token, :stamp => ts }
248
- if result.value == 0
249
- @sizes = SecPkgSizes.new
250
- result = SSPIResult.new(API::QueryContextAttributes.call(ctx.to_p, SECPKG_ATTR_SIZES, @sizes.to_p))
251
- @handle = @state[:handle]
252
- end
253
- @state[:token]
254
- end
255
-
256
- def established?
257
- @handle && (@handle.upper.nonzero? || @handle.lower.nonzero?) && (@state.nil? || @state[:result].value.zero?)
258
- end
259
-
260
- def get_mic(token=nil)
261
- buffers = SecurityBuffer.new 2
262
- buffers.set_buffer 0, SECBUFFER_DATA, token
263
- buffers.set_buffer 1, SECBUFFER_TOKEN, nil, @sizes.max_signature
264
- @state[:result] = SSPIResult.new(API::MakeSignature.call(@handle.to_p, 0, buffers.to_p, 0))
265
- unless @state[:result].ok?
266
- raise GeneralError, "Error creating the signature: #{result}"
267
- end
268
- return buffers.token(1).dup
269
- end
270
-
271
- def dispose()
272
- if @credentials
273
- API::FreeCredentialsHandle.call(@credentials.to_p)
274
- @credentials = nil
275
- end
276
- if @handle
277
- API::DeleteSecurityContext.call(@handle.to_p)
278
- @handle = nil
279
- end
280
- end
281
-
282
- end; end; end; end; end
@@ -0,0 +1,87 @@
1
+ require 'net/ssh/kerberos/sspi/api'
2
+
3
+ module Net; module SSH; module Kerberos; module SSPI; class Context
4
+
5
+ class GeneralError < StandardError; end
6
+
7
+ include Win32::SSPI
8
+
9
+ attr_reader :cred_name, :cred_krb_name, :server_name, :server_krb_name
10
+
11
+ def create(user, host)
12
+ dispose if @credentials or @handle
13
+ creds = CredHandle.new
14
+ ts = TimeStamp.new
15
+
16
+ result = API::AcquireCredentialsHandle nil, "Kerberos", SECPKG_CRED_OUTBOUND, nil, nil, nil, nil, creds, ts
17
+ result.ok? or raise GeneralError, "Error acquiring credentials: #{result}"
18
+
19
+ buff = "\0\0\0\0"
20
+ result = API::QueryCredentialsAttributes creds, SECPKG_CRED_ATTR_NAMES, buff
21
+ if result.ok?
22
+ names = buff.to_ptr.ptr
23
+ begin
24
+ @cred_name = names.to_s.sub(/^[^\\\/]*[\\\/]/, '')
25
+ @cred_krb_name = @cred_name.gsub('@', '/');
26
+ @server_name = Socket.gethostbyname(host)[0]
27
+ @server_krb_name = "host/" + @server_name
28
+
29
+ z = (user.include?('@') ? user.gsub('@','/') : user+'/')
30
+ unless z.downcase == @cred_krb_name[0,z.length].downcase
31
+ raise GeneralError, "Credentials mismatch: current is #{@cred_name}, requested is #{user}"
32
+ end
33
+ @credentials = creds
34
+ ensure
35
+ @credentials or API::FreeCredentialsHandle creds
36
+ API::FreeContextBuffer names
37
+ end
38
+ end
39
+ end
40
+
41
+ def credentials?; ! @credentials.nil? end
42
+
43
+ def init(token=nil)
44
+ ctx = CtxtHandle.new
45
+ ts = TimeStamp.new
46
+ prev = @state[:handle] if @state
47
+ req = ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH | ISC_REQ_INTEGRITY
48
+ output = SecurityBuffer.new
49
+ input = SecurityBuffer.new(token) if token
50
+ ctxAttr = "\0" * 4
51
+ result = API::InitializeSecurityContext @credentials, prev, @server_krb_name, req, 0,
52
+ SECURITY_NATIVE_DREP, input, 0, ctx, output, ctxAttr, ts
53
+ result = API::CompleteAuthToken ctx, output if result.incomplete?
54
+ if result.failure?
55
+ input.token and raise GeneralError, "Error initializing security context: #{result} #{input.inspect}"
56
+ end
57
+ @state = { :handle => ctx, :result => result, :token => output.token, :stamp => ts }
58
+ if result.complete?
59
+ result = API::QueryContextAttributes ctx, SECPKG_ATTR_SIZES, @sizes=SecPkgSizes.new
60
+ @handle = @state[:handle]
61
+ end
62
+ @state[:token]
63
+ end
64
+
65
+ def established?
66
+ ! @handle.nil? && (@state.nil? || @state[:result].value.zero?)
67
+ end
68
+
69
+ def get_mic(token=nil)
70
+ buffers = SecurityBuffer.new 2
71
+ buffers.set_buffer 0, SECBUFFER_DATA, token
72
+ buffers.set_buffer 1, SECBUFFER_TOKEN, nil, @sizes.max_signature
73
+ @state[:result] = API::MakeSignature @handle, 0, buffers, 0
74
+ unless @state[:result].ok?
75
+ raise GeneralError, "Error creating the signature: #{result}"
76
+ end
77
+ return buffers.token(1).dup
78
+ end
79
+
80
+ def dispose()
81
+ @credentials and API::FreeCredentialsHandle @credentials
82
+ @handle and API::DeleteSecurityContext @handle
83
+ ensure
84
+ @credentials = @handle = nil
85
+ end
86
+
87
+ end; end; end; end; end
@@ -1,7 +1,7 @@
1
- require 'test_helper'
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
2
 
3
3
  class NetSshKerberosTest < Test::Unit::TestCase
4
- def test_something_for_real
5
- flunk "hey buddy, you should probably rename this file and start testing for real"
4
+ def test_net_ssh_integration
5
+ flunk "write some unit tests for Net::SSH integration"
6
6
  end
7
7
  end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+
3
+ include Win32::SSPI
4
+
5
+ class SspiContextTest < Test::Unit::TestCase
6
+
7
+ if defined? Net::SSH::Kerberos::SSPI::Context
8
+
9
+ def setup
10
+ @gss = Net::SSH::Kerberos::SSPI::Context.new
11
+ end
12
+
13
+ def teardown
14
+ @gss.dispose
15
+ end
16
+
17
+ def test_create
18
+ @gss.create ENV['USER'], Socket.gethostbyname('localhost')[0]
19
+ assert @gss.credentials?, "Should have acquired credentials"
20
+ end
21
+
22
+ else
23
+ $stderr.puts "Skipping SSPI tests on this platform: Windows SSPI was not loaded."
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,70 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper.rb')
2
+
3
+ include Win32::SSPI
4
+
5
+ class SspiTest < Test::Unit::TestCase
6
+
7
+ if defined? Net::SSH::Kerberos::SSPI::Context
8
+
9
+ def test_query_security_package_info
10
+ pkg_info = SecPkgInfo.new
11
+ result = API::QuerySecurityPackageInfo "Kerberos", pkg_info
12
+ assert result.ok?, "QuerySecurityPackageInfo failed: #{result}"
13
+ assert_equal pkg_info.name, "Kerberos"
14
+ assert pkg_info.max_token >= 128, "The maximum token size is assumed to be greater than 128 bytes"
15
+ assert pkg_info.max_token <= 12288, "The maximum token size is assumed to be less than 12288 bytes"
16
+ result = API::FreeContextBuffer pkg_info
17
+ assert result.ok?, "FreeContextBuffer failed: #{result}"
18
+ end
19
+
20
+ def test_security_context_initialization
21
+ creds = SecurityHandle.new
22
+ ts = TimeStamp.new
23
+ result = API::AcquireCredentialsHandle nil, "Kerberos", SECPKG_CRED_OUTBOUND, nil, nil, nil, nil, creds, ts
24
+ unless result.temporary_failure?
25
+ assert result.ok?, "AcquireCredentialsHandle failed: #{result}"
26
+ assert ! creds.nil?, "Should acquire a credentials handle"
27
+ begin
28
+ buff = "\0\0\0\0"
29
+ result = API::QueryCredentialsAttributes creds, SECPKG_CRED_ATTR_NAMES, buff
30
+ assert result.ok?, "QueryCredentialsAttributes failed: #{result}"
31
+ names = buff.to_ptr.ptr
32
+ assert ! names.nil?, "Should return the user name."
33
+ begin
34
+ ts = TimeStamp.new
35
+ output = SecurityBuffer.new
36
+ ctx = CtxtHandle.new
37
+ ctxAttr = "\0" * 4
38
+ req = ISC_REQ_DELEGATE | ISC_REQ_MUTUAL_AUTH
39
+ result = API::InitializeSecurityContext creds, nil, 'host/'+Socket.gethostbyname('localhost')[0],
40
+ req, 0, SECURITY_NATIVE_DREP, nil, 0, ctx, output, ctxAttr, ts
41
+ unless result.temporary_failure?
42
+ assert result.ok?, "InitializeSecurityContext failed: #{result}"
43
+ begin
44
+ assert ! ctx.nil?, "Should initialize a context handle"
45
+ assert ! output.token.nil?, "Should output a token into the buffer"
46
+ assert output.bufferSize.nonzero?, "Should output a token into the buffer"
47
+ ensure
48
+ result = API::DeleteSecurityContext ctx
49
+ ctx = nil if result.ok?
50
+ end
51
+ assert ctx.nil?, "DeleteSecurityContext failed: #{result}"
52
+ end
53
+ ensure
54
+ result = API::FreeContextBuffer names
55
+ names = nil if result.ok?
56
+ end
57
+ assert names.nil?, "FreeContextBuffer failed: #{result}"
58
+ ensure
59
+ result = API::FreeCredentialsHandle creds
60
+ creds = nil if result.ok?
61
+ end
62
+ assert creds.nil?, "FreeCredentialsHandle failed: #{result}"
63
+ end
64
+ end
65
+ else
66
+ $stderr.puts "Skipping SSPI tests on this platform: Windows SSPI was not loaded."
67
+ end
68
+
69
+ end
70
+
@@ -3,7 +3,7 @@ require 'test/unit'
3
3
 
4
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
- require 'net_ssh_kerberos'
6
+ require 'net/ssh/kerberos'
7
7
 
8
8
  class Test::Unit::TestCase
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh-kerberos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Khoobyar
@@ -51,12 +51,18 @@ files:
51
51
  - lib/net/ssh/authentication/methods/gssapi_with_mic.rb
52
52
  - lib/net/ssh/kerberos.rb
53
53
  - lib/net/ssh/kerberos/constants.rb
54
+ - lib/net/ssh/kerberos/gss.rb
55
+ - lib/net/ssh/kerberos/gss/api.rb
56
+ - lib/net/ssh/kerberos/gss/context.rb
54
57
  - lib/net/ssh/kerberos/kex.rb
55
58
  - lib/net/ssh/kerberos/kex/krb5_diffie_hellman_group1_sha1.rb
56
59
  - lib/net/ssh/kerberos/kex/krb5_diffie_hellman_group_exchange_sha1.rb
57
60
  - lib/net/ssh/kerberos/sspi.rb
58
61
  - lib/net/ssh/kerberos/sspi/api.rb
62
+ - lib/net/ssh/kerberos/sspi/context.rb
59
63
  - test/net_ssh_kerberos_test.rb
64
+ - test/sspi_context_test.rb
65
+ - test/sspi_test.rb
60
66
  - test/test_helper.rb
61
67
  has_rdoc: true
62
68
  homepage: http://github.com/joekhoobyar/net-ssh-kerberos
@@ -88,4 +94,6 @@ specification_version: 3
88
94
  summary: Add Kerberos support to Net::SSH
89
95
  test_files:
90
96
  - test/net_ssh_kerberos_test.rb
97
+ - test/sspi_context_test.rb
98
+ - test/sspi_test.rb
91
99
  - test/test_helper.rb