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.



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

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



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

def allowed_auth_methods
  @allowed_auth_methods
end

#auth_methodsObject (readonly)

the list of authentication methods to try



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

def auth_methods
  @auth_methods
end

#optionsObject (readonly)

a hash of options, given at construction time



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

def options
  @options
end

#transportObject (readonly)

transport layer abstraction



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

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.



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

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|
    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],
                              pubkey_algorithms: options[:pubkey_algorithms] || nil)
    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

  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
134
# 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