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_INIT, Transport::Constants::KEXDH_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.



36
37
38
39
40
41
42
43
44
# File 'lib/net/ssh/authentication/session.rb', line 36

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

  @auth_methods = options[:auth_methods] || %w(publickey hostbased password keyboard-interactive)
  @options = options

  @allowed_auth_methods = @auth_methods
end

Instance Attribute Details

#allowed_auth_methodsObject (readonly)

the list of authentication methods that are allowed



29
30
31
# File 'lib/net/ssh/authentication/session.rb', line 29

def allowed_auth_methods
  @allowed_auth_methods
end

#auth_methodsObject (readonly)

the list of authentication methods to try



26
27
28
# File 'lib/net/ssh/authentication/session.rb', line 26

def auth_methods
  @auth_methods
end

#optionsObject (readonly)

a hash of options, given at construction time



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

def options
  @options
end

#transportObject (readonly)

transport layer abstraction



23
24
25
# File 'lib/net/ssh/authentication/session.rb', line 23

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.



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

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

  transport.send_message(transport.service_request("ssh-userauth"))
  message = 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|
    next unless @allowed_auth_methods.include?(name)
    attempted << name

    debug { "trying #{name}" }
    method = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join).new(self, :key_manager => key_manager)

    return true if method.authenticate(next_service, username, password)
  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.



109
110
111
112
113
114
115
# File 'lib/net/ssh/authentication/session.rb', line 109

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_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.



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

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