File: gssapi_with_mic.rb

package info (click to toggle)
ruby-net-ssh-krb 0.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 156 kB
  • sloc: ruby: 277; makefile: 4
file content (108 lines) | stat: -rw-r--r-- 4,286 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
require 'net/ssh/authentication/methods/abstract'
require 'net/ssh/kerberos/constants'
require 'gssapi'

module Net
  module SSH
    module Authentication
      module Methods

        # Implements the Kerberos 5 SSH authentication method.
        class GssapiWithMic < Abstract
          include Net::SSH::Kerberos::Constants
          
          # Attempts to perform gssapi-with-mic Kerberos authentication
          def authenticate(next_service, username, password=nil)
              gss = nil
            
            # Try to start gssapi-with-mic authentication.
	          debug { "trying kerberos authentication" }
	          req = userauth_request(username, next_service, "gssapi-with-mic")
	          req.write_long(1)
	          supported_oid = (6.chr + GSS_KRB5_MECH.length.chr + GSS_KRB5_MECH).force_encoding(Encoding::ASCII_8BIT)
	          req.write_string(supported_oid)
	          send_message req
	          message = session.next_message
	          case message.type
	            when USERAUTH_GSSAPI_RESPONSE
	              debug { "gssapi-with-mic proceeding" }
	            when USERAUTH_FAILURE
	              info { "gssapi-with-mic failed (USERAUTH_FAILURE)" }
	              return false
	            else
	              raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
	          end
	          
	          # Try to match the OID.
	          oid = message.read_string.force_encoding(Encoding::ASCII_8BIT)
	          if oid != supported_oid
              info { "gssapi-with-mic failed (USERAUTH_GSSAPI_RESPONSE)" }
              return false
	          end
	          
	          # Try to complete the handshake.
	          gss = GSSAPI::Simple.new hostname

              established = false
			      debug { "gssapi-with-mic handshaking" }
	          until established
	            # :delegate => true always forwards tickets.  This may or may not be a good idea, and should really be a user-specified option.
	            token = gss.init_context(token, :delegate => true)
	            break if token === true
	            if token && token.length > 0
					      send_message Net::SSH::Buffer.from(:byte, USERAUTH_GSSAPI_TOKEN, :string, token)
	            
	                message = session.next_message
				          case message.type
				          when USERAUTH_GSSAPI_ERROR
			              message = session.next_message
			              message.get_long
			              message.get_long
				            info { "gssapi-with-mic error (USERAUTH_GSSAPI_ERROR) (#{message.read_string})" }
				          when USERAUTH_GSSAPI_ERRTOK
			              message = session.next_message
				            info { "gssapi-with-mic error (USERAUTH_GSSAPI_ERRTOK) (#{message.read_string})" }
				          when USERAUTH_FAILURE
				            info { "gssapi-with-mic failed (USERAUTH_FAILURE)" }
				            return false
				          end
	                token = message.read_string
	              
	            end
	          end
	          
	          # Attempt the actual authentication.
			      debug { "gssapi-with-mic authenticating" }
					  mic = gss.get_mic Net::SSH::Buffer.from(:string, session_id, :byte, USERAUTH_REQUEST, :string, username, 
				                                             :string, next_service, :string, "gssapi-with-mic").to_s
            if mic.nil?
              info { "gssapi-with-mic failed (context#get_mic)" }
              return false
            end
			      send_message Net::SSH::Buffer.from(:byte, USERAUTH_GSSAPI_MIC, :string, mic)
            message = session.next_message
	          case message.type
	            when USERAUTH_SUCCESS
	              info { "gssapi-with-mic success" }
	              return true
	            when USERAUTH_FAILURE
	              info { "gssapi-with-mic partial failure (USERAUTH_FAILURE)" }
	              return false
	            else
	              raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
	          end
          end

          private

            # Returns the hostname as reported by the underlying socket.
            def hostname
              session.transport.host
            end

        end

      end
    end
  end
end