class Net::SSH::Authentication::Session

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.

Attributes

allowed_auth_methods[R]

the list of authentication methods that are allowed

auth_methods[R]

the list of authentication methods to try

options[R]

a hash of options, given at construction time

transport[R]

transport layer abstraction

Public Class Methods

new(transport, options={}) click to toggle source

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

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

Public Instance Methods

authenticate(next_service, username, password=nil) click to toggle source

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.

# File lib/net/ssh/authentication/session.rb, line 54
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?
  key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?

  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) click to toggle source

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

# File lib/net/ssh/authentication/session.rb, line 123
def expect_message(type)
  message = next_message
  unless message.type == type
    raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})"
  end
  message
end
next_message() click to toggle source

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.

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