net-ssh-kerberos 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Joe Khoobyar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ = net-ssh-kerberos
2
+
3
+ Adds Kerberos support to Net::SSH
4
+
5
+ == Copyright
6
+
7
+ Copyright (c) 2009 Joe Khoobyar. See LICENSE for details.
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "net-ssh-kerberos"
8
+ gem.summary = %Q{Add Kerberos support to Net::SSH}
9
+ gem.description = <<-EOTEXT
10
+ Adds support for Microsoft Kerberos (SSPI) with the Net:SSH gem.
11
+ EOTEXT
12
+ gem.email = "joe@ankhcraft.com"
13
+ gem.homepage = "http://github.com/joekhoobyar/net-ssh-kerberos"
14
+ gem.authors = ["Joe Khoobyar"]
15
+ gem.rubyforge_project = 'net-ssh-krb'
16
+ gem.add_runtime_dependency(%q<net-ssh>, [">= 2.0"])
17
+ gem.add_runtime_dependency(%q<rubysspi>, [">= 1.3"])
18
+
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/*_test.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/*_test.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/rdoctask'
49
+ Rake::RDocTask.new do |rdoc|
50
+ if File.exist?('VERSION.yml')
51
+ config = YAML.load(File.read('VERSION.yml'))
52
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
53
+ else
54
+ version = ""
55
+ end
56
+
57
+ rdoc.rdoc_dir = 'rdoc'
58
+ rdoc.title = "Net-ssh-kerberos #{version}"
59
+ rdoc.rdoc_files.include('README*')
60
+ rdoc.rdoc_files.include('lib/**/*.rb')
61
+ end
62
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 0
@@ -0,0 +1,109 @@
1
+ require 'net/ssh/authentication/methods/abstract'
2
+ require 'net/ssh/kerberos/constants'
3
+
4
+ module Net
5
+ module SSH
6
+ module Authentication
7
+ module Methods
8
+
9
+ # Implements the Kerberos 5 SSH authentication method.
10
+ class GssapiWithMic < Abstract
11
+ include Net::SSH::Kerberos::Constants
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*")
16
+
17
+ # Attempts to perform gssapi-with-mic Kerberos authentication
18
+ def authenticate(next_service, username, password=nil)
19
+ sspi = nil
20
+
21
+ # Try to start gssapi-with-mic authentication.
22
+ debug { "trying kerberos authentication" }
23
+ req = userauth_request(username, next_service, "gssapi-with-mic")
24
+ req.write_long 1
25
+ req.write_string SUPPORTED_OID
26
+ send_message req
27
+ message = session.next_message
28
+ case message.type
29
+ when USERAUTH_GSSAPI_RESPONSE
30
+ debug { "gssapi-with-mic proceeding" }
31
+ when USERAUTH_FAILURE
32
+ info { "gssapi-with-mic failed (USERAUTH_FAILURE)" }
33
+ return false
34
+ else
35
+ raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
36
+ end
37
+
38
+ # Try to match the OID.
39
+ oid = message.read_string
40
+ if oid != SUPPORTED_OID
41
+ info { "gssapi-with-mic failed (USERAUTH_GSSAPI_RESPONSE)" }
42
+ return false
43
+ end
44
+
45
+ # Try to complete the handshake.
46
+ sspi = Net::SSH::Kerberos::SSPI::GSSContext.new
47
+ sspi.create username, hostname
48
+ debug { "gssapi-with-mic handshaking" }
49
+ until sspi.established?
50
+ token = sspi.init(token)
51
+ if token && token.length > 0
52
+ send_message Net::SSH::Buffer.from(:byte, USERAUTH_GSSAPI_TOKEN, :string, token)
53
+ unless sspi.established?
54
+ message = session.next_message
55
+ case message.type
56
+ when USERAUTH_GSSAPI_ERROR
57
+ message = session.next_message
58
+ message.get_long
59
+ message.get_long
60
+ info { "gssapi-with-mic error (USERAUTH_GSSAPI_ERROR) (#{message.read_string})" }
61
+ when USERAUTH_GSSAPI_ERRTOK
62
+ message = session.next_message
63
+ info { "gssapi-with-mic error (USERAUTH_GSSAPI_ERRTOK) (#{message.read_string})" }
64
+ when USERAUTH_FAILURE
65
+ info { "gssapi-with-mic failed (USERAUTH_FAILURE)" }
66
+ return false
67
+ end
68
+ token = message.read_string
69
+ end
70
+ end
71
+ end
72
+
73
+ # Attempt the actual authentication.
74
+ debug { "gssapi-with-mic authenticating" }
75
+ mic = sspi.get_mic Net::SSH::Buffer.from(:string, session_id, :byte, USERAUTH_REQUEST, :string, username,
76
+ :string, next_service, :string, "gssapi-with-mic").to_s
77
+ if mic.nil?
78
+ info { "gssapi-with-mic failed (context#get_mic)" }
79
+ return false
80
+ end
81
+ send_message Net::SSH::Buffer.from(:byte, USERAUTH_GSSAPI_MIC, :string, mic)
82
+ message = session.next_message
83
+ case message.type
84
+ when USERAUTH_SUCCESS
85
+ info { "gssapi-with-mic success" }
86
+ return true
87
+ when USERAUTH_FAILURE
88
+ info { "gssapi-with-mic partial failure (USERAUTH_FAILURE)" }
89
+ return false
90
+ else
91
+ raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
92
+ end
93
+ ensure
94
+ sspi and sspi.dispose
95
+ end
96
+
97
+ private
98
+
99
+ # Returns the hostname as reported by the underlying socket.
100
+ def hostname
101
+ session.transport.host
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,12 @@
1
+ require 'net/ssh'
2
+ require 'net/ssh/kerberos/constants'
3
+ #require 'net/ssh/kerberos/kex'
4
+ require 'net/ssh/kerberos/sspi'
5
+ require 'net/ssh/authentication/methods/gssapi_with_mic'
6
+
7
+ module Net
8
+ module SSH
9
+ module Kerberos
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Net; module SSH; module Kerberos
2
+ module Constants
3
+
4
+
5
+ #--
6
+ # GSSAPI Key exchange method specific messages
7
+ #++
8
+
9
+ KEXGSS_INIT = 30
10
+ KEXGSS_CONTINUE = 31
11
+ KEXGSS_COMPLETE = 32
12
+ KEXGSS_HOSTKEY = 33
13
+ KEXGSS_ERROR = 34
14
+ KEXGSS_GROUPREQ = 40
15
+ KEXGSS_GROUP = 41
16
+
17
+ #--
18
+ # GSSAPI User authentication method specific messages
19
+ #++
20
+
21
+ USERAUTH_GSSAPI_RESPONSE = 60
22
+ USERAUTH_GSSAPI_TOKEN = 61
23
+ USERAUTH_GSSAPI_EXCHANGE_COMPLETE = 63
24
+ USERAUTH_GSSAPI_ERROR = 64
25
+ USERAUTH_GSSAPI_ERRTOK = 65
26
+ USERAUTH_GSSAPI_MIC = 66
27
+
28
+ end
29
+ end; end; end
30
+
@@ -0,0 +1,17 @@
1
+ require 'net/ssh/kerberos/kex/krb5_diffie_hellman_group1_sha1'
2
+ require 'net/ssh/kerberos/kex/krb5_diffie_hellman_group_exchange_sha1'
3
+
4
+ module Net; module SSH; module Kerberos
5
+ module Kex
6
+
7
+ GSS_MAP = {
8
+ 'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==' => KRB5DiffieHellmanGroup1SHA1,
9
+ 'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==' => KRB5DiffieHellmanGroupExchangeSHA1
10
+ }
11
+
12
+ Net::SSH::Transport::Kex::MAP.update GSS_MAP
13
+ Net::SSH::Transport::ALGORITHMS[:kex] << GSS_MAP.keys
14
+
15
+ end
16
+ end; end; end
17
+
@@ -0,0 +1,9 @@
1
+ module Net; module SSH; module Kerberos; module Kex
2
+
3
+ class KRB5DiffieHellmanGroup1SHA1 < Net::SSH::Transport::Kex::DiffieHellmanGroup1SHA1
4
+
5
+ end
6
+
7
+
8
+ end; end; end; end
9
+
@@ -0,0 +1,9 @@
1
+ module Net; module SSH; module Kerberos; module Kex
2
+
3
+ class KRB5DiffieHellmanGroupExchangeSHA1 < Net::SSH::Transport::Kex::DiffieHellmanGroupExchangeSHA1
4
+
5
+ end
6
+
7
+
8
+ end; end; end; end
9
+
@@ -0,0 +1,54 @@
1
+ require 'net/ssh/kerberos/sspi/api'
2
+
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
+
@@ -0,0 +1,282 @@
1
+ require 'win32/sspi'
2
+ require 'dl'
3
+
4
+ module Win32; module SSPI
5
+
6
+ SECPKG_CRED_ATTR_NAMES = 1
7
+
8
+ ISC_REQ_DELEGATE = 0x00000001
9
+ ISC_REQ_MUTUAL_AUTH = 0x00000002
10
+ ISC_REQ_INTEGRITY = 0x00010000
11
+
12
+ SECPKG_ATTR_AUTHORITY = 6
13
+ SECPKG_ATTR_CONNECTION_INFO = 90
14
+ SECPKG_ATTR_ISSUER_LIST = 80
15
+ SECPKG_ATTR_ISSUER_LIST_EX = 89
16
+ SECPKG_ATTR_KEY_INFO = 5
17
+ SECPKG_ATTR_LIFESPAN = 2
18
+ SECPKG_ATTR_LOCAL_CERT_CONTEXT = 84
19
+ SECPKG_ATTR_LOCAL_CRED = 82
20
+ SECPKG_ATTR_NAMES = 1
21
+ SECPKG_ATTR_PROTO_INFO = 7
22
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT = 83
23
+ SECPKG_ATTR_REMOTE_CRED = 81
24
+ SECPKG_ATTR_SIZES = 0
25
+ SECPKG_ATTR_STREAM_SIZES = 4
26
+
27
+ # Buffer types
28
+ SECBUFFER_EMPTY = 0
29
+ SECBUFFER_DATA = 1
30
+ SECBUFFER_TOKEN = 2
31
+ SECBUFFER_PKG_PARAMS = 3
32
+ SECBUFFER_MISSING = 4
33
+ SECBUFFER_EXTRA = 5
34
+ SECBUFFER_STREAM_TRAILER = 6
35
+ SECBUFFER_STREAM_HEADER = 7
36
+ SECBUFFER_PADDING = 9
37
+ SECBUFFER_STREAM = 10
38
+ SECBUFFER_MECHLIST = 11
39
+ SECBUFFER_MECHLIST_SIGNATURE = 12
40
+ SECBUFFER_TARGET = 13
41
+ SECBUFFER_CHANNEL_BINDINGS = 14
42
+ SECBUFFER_CHANGE_PASS_RESPONSE = 15
43
+ SECBUFFER_TARGET_HOST = 16
44
+ SECBUFFER_READONLY = 0x80000000
45
+ SECBUFFER_READONLY_WITH_CHECKSUM = 0x10000000
46
+ SECBUFFER_ATTRMASK = 0xf0000000
47
+
48
+ # Good results
49
+ SEC_E_OK = 0x00000000
50
+ SEC_I_RENEGOTIATE = 590625;
51
+ SEC_I_COMPLETE_AND_CONTINUE = 590612;
52
+ SEC_I_COMPLETE_NEEDED = 590611;
53
+ SEC_I_CONTINUE_NEEDED = 590610;
54
+ SEC_I_INCOMPLETE_CREDENTIALS = 590624;
55
+
56
+ # These are generally returned by InitializeSecurityContext
57
+ SEC_E_INSUFFICIENT_MEMORY = 0x80090300
58
+ SEC_E_INTERNAL_ERROR = 0x80090304
59
+ SEC_E_INVALID_HANDLE = 0x80090301
60
+ SEC_E_INVALID_TOKEN = 0x80090308
61
+ SEC_E_LOGON_DENIED = 0x8009030C
62
+ SEC_E_NO_AUTHENTICATING_AUTHORITY = 0x80090311
63
+ SEC_E_NO_CREDENTIALS = 0x8009030E
64
+ SEC_E_TARGET_UNKNOWN = 0x80090303
65
+ SEC_E_UNSUPPORTED_FUNCTION = 0x80090302
66
+ SEC_E_WRONG_PRINCIPAL = 0x80090322
67
+
68
+ # These are generally returned by AcquireCredentialsHandle
69
+ SEC_E_NOT_OWNER = 0x80090306
70
+ SEC_E_SECPKG_NOT_FOUND = 0x80090305
71
+ SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D
72
+
73
+ module API
74
+ QuerySecurityPackageInfo = Win32API.new("secur32", "QuerySecurityPackageInfoA", 'pp', 'L')
75
+ QueryCredentialsAttributes = Win32API.new("secur32", "QueryCredentialsAttributesA", 'pLp', 'L')
76
+ QueryContextAttributes = Win32API.new("secur32", "QueryContextAttributesA", 'pLp', 'L')
77
+ CompleteAuthToken = Win32API.new("secur32", "CompleteAuthToken", 'pp', 'L')
78
+ MakeSignature = Win32API.new("secur32", "MakeSignature", 'pLpL', 'L')
79
+ FreeContextBuffer = Win32API.new("secur32", "FreeContextBuffer", 'P', 'L')
80
+ end
81
+
82
+ SecPkgCredentialsNames = Struct.new(:user_name)
83
+
84
+ class SecPkgInfo
85
+ attr_reader :struct
86
+
87
+ def capabilities; unpacked[0] end
88
+ def max_token; unpacked[2] end
89
+ def name; unpacked[3] end
90
+ def comment; unpacked[4] end
91
+
92
+ def unpacked;
93
+ @unpacked ||= @struct.to_ptr.ptr.to_a("LLL", 3) + (@struct.to_ptr.ptr + 12).to_a("SS", 2)
94
+ end
95
+
96
+ def to_p; @struct ||= "\0" * 4 end
97
+ end
98
+
99
+ class SecPkgSizes
100
+ attr_reader :struct
101
+
102
+ def max_token; unpacked[0] end
103
+ def max_signature; unpacked[1] end
104
+ def block_size; unpacked[2] end
105
+ def security_trailer; unpacked[3] end
106
+
107
+ def unpacked;
108
+ @unpacked ||= @struct.unpack("LLLL")
109
+ end
110
+
111
+ def to_p; @struct ||= "\0" * 16 end
112
+ end
113
+
114
+ # Creates binary representaiton of a SecBufferDesc structure,
115
+ # including the SecBuffer contained inside.
116
+ class SecurityBuffer
117
+
118
+ def initialize(buffers=nil)
119
+ case buffers
120
+ when String
121
+ @bufferTokens = [ buffers.dup ]
122
+ @bufferSizes = [ buffers.length ]
123
+ @bufferTypes = [ SECBUFFER_TOKEN ]
124
+ when Fixnum
125
+ @bufferTokens = [ "\0" * TOKENBUFSIZE ] * buffers
126
+ @bufferSizes = [ TOKENBUFSIZE ] * buffers
127
+ @bufferTypes = [ SECBUFFER_TOKEN ] * buffers
128
+ when NilClass
129
+ @bufferTokens = [ "\0" * TOKENBUFSIZE ]
130
+ @bufferSizes = [ TOKENBUFSIZE ]
131
+ @bufferTypes = [ SECBUFFER_TOKEN ]
132
+ else
133
+ raise ArgumentError
134
+ end
135
+ end
136
+
137
+ def bufferSize(n=0)
138
+ unpack
139
+ @bufferSizes[n]
140
+ end
141
+
142
+ def bufferType(n=0)
143
+ unpack
144
+ @bufferTypes[n]
145
+ end
146
+
147
+ def token(n=0)
148
+ unpack
149
+ @bufferTokens[n]
150
+ end
151
+
152
+ def set_buffer(n=0, type=SECBUFFER_TOKEN, token=nil, size=nil)
153
+ @bufferTypes[n] = type
154
+ @bufferSizes[n] = size || (token.nil? ? 0 : token.length)
155
+ @bufferTokens[n] = (token.nil? && size && size > 0) ? "\0" * (size+1) : token
156
+ end
157
+
158
+ def to_p
159
+ # Assumption is that when to_p is called we are going to get a packed structure. Therefore,
160
+ # set @unpacked back to nil so we know to unpack when accessors are next accessed.
161
+ @unpacked = nil
162
+ # Assignment of inner structure to variable is very important here. Without it,
163
+ # will not be able to unpack changes to the structure. Alternative, nested unpacks,
164
+ # does not work (i.e. @struct.unpack("LLP12")[2].unpack("LLP12") results in "no associated pointer")
165
+ @sec_buffers ||= @bufferTokens.inject([]) do |v,t|
166
+ v.push @bufferSizes[v.size / 3], @bufferTypes[v.size / 3], t
167
+ end.pack("LLP" * @bufferTokens.size)
168
+ @struct ||= [SECBUFFER_VERSION, @bufferTokens.size, @sec_buffers].pack("LLP")
169
+ end
170
+
171
+ private
172
+
173
+ # Unpacks the SecurityBufferDesc structure into member variables. We
174
+ # only want to do this once per struct, so the struct is deleted
175
+ # after unpacking.
176
+ def unpack
177
+ if ! @unpacked && @sec_buffers && @struct
178
+ d = @sec_buffers.unpack("LLL" * @bufferTokens.size)
179
+ k = ''; 0.upto(@bufferTokens.size - 1) do |n| k << "LLP#{d[n * 3]}" end
180
+ d = @sec_buffers.unpack(k)
181
+ 0.upto(@bufferTokens.size - 1) do |n| @bufferSizes[n] = d[n * 3] end
182
+ 0.upto(@bufferTokens.size - 1) do |n| @bufferTypes[n] = d[n * 3 + 1] end
183
+ 0.upto(@bufferTokens.size - 1) do |n| @bufferTokens[n] = d[n * 3 + 2] end
184
+ @struct = nil
185
+ @sec_buffers = nil
186
+ @unpacked = true
187
+ end
188
+ end
189
+ end
190
+
191
+ 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,7 @@
1
+ require 'test_helper'
2
+
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"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ require 'net_ssh_kerberos'
7
+
8
+ class Test::Unit::TestCase
9
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-ssh-kerberos
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Joe Khoobyar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-13 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: net-ssh
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "2.0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rubysspi
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "1.3"
34
+ version:
35
+ description: |
36
+ Adds support for Microsoft Kerberos (SSPI) with the Net:SSH gem.
37
+
38
+ email: joe@ankhcraft.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - LICENSE
45
+ - README.rdoc
46
+ files:
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION.yml
51
+ - lib/net/ssh/authentication/methods/gssapi_with_mic.rb
52
+ - lib/net/ssh/kerberos.rb
53
+ - lib/net/ssh/kerberos/constants.rb
54
+ - lib/net/ssh/kerberos/kex.rb
55
+ - lib/net/ssh/kerberos/kex/krb5_diffie_hellman_group1_sha1.rb
56
+ - lib/net/ssh/kerberos/kex/krb5_diffie_hellman_group_exchange_sha1.rb
57
+ - lib/net/ssh/kerberos/sspi.rb
58
+ - lib/net/ssh/kerberos/sspi/api.rb
59
+ - test/net_ssh_kerberos_test.rb
60
+ - test/test_helper.rb
61
+ has_rdoc: true
62
+ homepage: http://github.com/joekhoobyar/net-ssh-kerberos
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --charset=UTF-8
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ requirements: []
83
+
84
+ rubyforge_project: net-ssh-krb
85
+ rubygems_version: 1.3.4
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Add Kerberos support to Net::SSH
89
+ test_files:
90
+ - test/net_ssh_kerberos_test.rb
91
+ - test/test_helper.rb