Class: Net::SSH::Authentication::Session

Inherits:
Object
  • Object
show all
Includes:
Constants, Loggable, Transport::Constants
Defined in:
lib/net/ssh/authentication/session.rb

Overview

Represents an authentication session. It manages the authentication of a user over an established connection (the “transport” object, see Net::SSH::Transport::Session).

The use of an authentication session to manage user authentication is internal to Net::SSH (specifically Net::SSH.start). Consumers of the Net::SSH library will never need to access this class directly.

Constant Summary

Constants included from Transport::Constants

Transport::Constants::DEBUG, Transport::Constants::DISCONNECT, Transport::Constants::IGNORE, Transport::Constants::KEXDH_GEX_GROUP, Transport::Constants::KEXDH_GEX_INIT, Transport::Constants::KEXDH_GEX_REPLY, Transport::Constants::KEXDH_GEX_REQUEST, Transport::Constants::KEXDH_INIT, Transport::Constants::KEXDH_REPLY, Transport::Constants::KEXECDH_INIT, Transport::Constants::KEXECDH_REPLY, Transport::Constants::KEXINIT, Transport::Constants::NEWKEYS, Transport::Constants::SERVICE_ACCEPT, Transport::Constants::SERVICE_REQUEST, Transport::Constants::UNIMPLEMENTED

Constants included from Constants

Constants::USERAUTH_BANNER, Constants::USERAUTH_FAILURE, Constants::USERAUTH_METHOD_RANGE, Constants::USERAUTH_PASSWD_CHANGEREQ, Constants::USERAUTH_PK_OK, Constants::USERAUTH_REQUEST, Constants::USERAUTH_SUCCESS

Instance Attribute Summary collapse

Attributes included from Loggable

#logger

Instance Method Summary collapse

Methods included from Loggable

#debug, #error, #fatal, #info, #lwarn

Constructor Details

#initialize(transport, options = {}) ⇒ Session

Instantiates a new Authentication::Session object over the given transport layer abstraction.


45
46
47
48
49
50
51
52
53
# File 'lib/net/ssh/authentication/session.rb', line 45

def initialize(transport, options={})
  self.logger = transport.logger
  @transport = transport

  @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
  @options = options

  @allowed_auth_methods = @auth_methods
end

Instance Attribute Details

#allowed_auth_methodsObject (readonly)

the list of authentication methods that are allowed


38
39
40
# File 'lib/net/ssh/authentication/session.rb', line 38

def allowed_auth_methods
  @allowed_auth_methods
end

#auth_methodsObject (readonly)

the list of authentication methods to try


35
36
37
# File 'lib/net/ssh/authentication/session.rb', line 35

def auth_methods
  @auth_methods
end

#optionsObject (readonly)

a hash of options, given at construction time


41
42
43
# File 'lib/net/ssh/authentication/session.rb', line 41

def options
  @options
end

#transportObject (readonly)

transport layer abstraction


32
33
34
# File 'lib/net/ssh/authentication/session.rb', line 32

def transport
  @transport
end

Instance Method Details

#authenticate(next_service, username, password = nil) ⇒ Object

Attempts to authenticate the given user, in preparation for the next service request. Returns true if an authentication method succeeds in authenticating the user, and false otherwise.


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
# File 'lib/net/ssh/authentication/session.rb', line 58

def authenticate(next_service, username, password=nil)
  debug { "beginning authentication of `#{username}'" }

  transport.send_message(transport.service_request("ssh-userauth"))
  expect_message(SERVICE_ACCEPT)

  key_manager = KeyManager.new(logger, options)
  keys.each { |key| key_manager.add(key) } unless keys.empty?
  keycerts.each { |keycert| key_manager.add_keycert(keycert) } unless keycerts.empty?
  key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
  default_keys.each { |key| key_manager.add(key) } unless options.key?(:keys) || options.key?(:key_data)

  attempted = []

  @auth_methods.each do |name|
    begin
      next unless @allowed_auth_methods.include?(name)
      attempted << name

      debug { "trying #{name}" }
      begin
        auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
        method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
      rescue NameError
        debug {"Mechanism #{name} was requested, but isn't a known type.  Ignoring it."}
        next
      end

      return true if method.authenticate(next_service, username, password)
    rescue Net::SSH::Authentication::DisallowedMethod
    end
  end

  error { "all authorization methods failed (tried #{attempted.join(', ')})" }
  return false
ensure
  key_manager.finish if key_manager
end

#expect_message(type) ⇒ Object

Blocks until a packet is received, and returns it if it is of the given type. If it is not, an exception is raised.


129
130
131
132
133
# File 'lib/net/ssh/authentication/session.rb', line 129

def expect_message(type)
  message = next_message
  raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})" unless message.type == type
  message
end

#next_messageObject

Blocks until a packet is received. It silently handles USERAUTH_BANNER packets, and will raise an error if any packet is received that is not valid during user authentication.


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/net/ssh/authentication/session.rb', line 100

def next_message
  loop do
    packet = transport.next_message

    case packet.type
    when USERAUTH_BANNER
      info { packet[:message] }
    # TODO add a hook for people to retrieve the banner when it is sent

    when USERAUTH_FAILURE
      @allowed_auth_methods = packet[:authentications].split(/,/)
      debug { "allowed methods: #{packet[:authentications]}" }
      return packet

    when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
      return packet

    when USERAUTH_SUCCESS
      transport.hint :authenticated
      return packet

    else
      raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
    end
  end
end