Class: Net::SSH::Authentication::Agent
- Inherits:
-
Object
- Object
- Net::SSH::Authentication::Agent
- Includes:
- Loggable
- Defined in:
- lib/net/ssh/authentication/agent.rb
Overview
This class implements a simple client for the ssh-agent protocol. It does not implement any specific protocol, but instead copies the behavior of the ssh-agent functions in the OpenSSH library (3.8).
This means that although it behaves like a SSH1 client, it also has some SSH2 functionality (like signing data).
Defined Under Namespace
Modules: Comment
Constant Summary collapse
- SSH2_AGENT_REQUEST_VERSION =
1
- SSH2_AGENT_REQUEST_IDENTITIES =
11
- SSH2_AGENT_IDENTITIES_ANSWER =
12
- SSH2_AGENT_SIGN_REQUEST =
13
- SSH2_AGENT_SIGN_RESPONSE =
14
- SSH2_AGENT_ADD_IDENTITY =
17
- SSH2_AGENT_REMOVE_IDENTITY =
18
- SSH2_AGENT_REMOVE_ALL_IDENTITIES =
19
- SSH2_AGENT_LOCK =
22
- SSH2_AGENT_UNLOCK =
23
- SSH2_AGENT_ADD_ID_CONSTRAINED =
25
- SSH2_AGENT_FAILURE =
30
- SSH2_AGENT_VERSION_RESPONSE =
103
- SSH_COM_AGENT2_FAILURE =
102
- SSH_AGENT_REQUEST_RSA_IDENTITIES =
1
- SSH_AGENT_RSA_IDENTITIES_ANSWER1 =
2
- SSH_AGENT_RSA_IDENTITIES_ANSWER2 =
5
- SSH_AGENT_FAILURE =
5
- SSH_AGENT_SUCCESS =
6
- SSH_AGENT_CONSTRAIN_LIFETIME =
1
- SSH_AGENT_CONSTRAIN_CONFIRM =
2
- SSH_AGENT_RSA_SHA2_256 =
0x02
- SSH_AGENT_RSA_SHA2_512 =
0x04
Instance Attribute Summary collapse
-
#socket ⇒ Object
readonly
The underlying socket being used to communicate with the SSH agent.
Attributes included from Loggable
Class Method Summary collapse
-
.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil) ⇒ Object
Instantiates a new agent object, connects to a running SSH agent, negotiates the agent protocol version, and returns the agent object.
Instance Method Summary collapse
-
#add_identity(priv_key, comment, lifetime: nil, confirm: false) ⇒ Object
Adds the private key with comment to the agent.
-
#close ⇒ Object
Closes this socket.
-
#connect!(agent_socket_factory = nil, identity_agent = nil) ⇒ Object
Connect to the agent process using the socket factory and socket name given by the attribute writers.
-
#identities ⇒ Object
Return an array of all identities (public keys) known to the agent.
-
#initialize(logger = nil) ⇒ Agent
constructor
Creates a new Agent object, using the optional logger instance to report status.
-
#lock(password) ⇒ Object
lock the ssh agent with password.
-
#negotiate! ⇒ Object
Attempts to negotiate the SSH agent protocol version.
-
#remove_all_identities ⇒ Object
Removes all identities from the agent.
-
#remove_identity(key) ⇒ Object
Removes key from the agent.
-
#sign(key, data, flags = 0) ⇒ Object
Using the agent and the given public key, sign the given data.
-
#unlock(password) ⇒ Object
unlock the ssh agent with password.
Methods included from Loggable
#debug, #error, #fatal, #info, #lwarn
Constructor Details
#initialize(logger = nil) ⇒ Agent
Creates a new Agent object, using the optional logger instance to report status.
77 78 79 |
# File 'lib/net/ssh/authentication/agent.rb', line 77 def initialize(logger = nil) self.logger = logger end |
Instance Attribute Details
#socket ⇒ Object (readonly)
The underlying socket being used to communicate with the SSH agent.
64 65 66 |
# File 'lib/net/ssh/authentication/agent.rb', line 64 def socket @socket end |
Class Method Details
.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil) ⇒ Object
Instantiates a new agent object, connects to a running SSH agent, negotiates the agent protocol version, and returns the agent object.
68 69 70 71 72 73 |
# File 'lib/net/ssh/authentication/agent.rb', line 68 def self.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil) agent = new(logger) agent.connect!(agent_socket_factory, identity_agent) agent.negotiate! agent end |
Instance Method Details
#add_identity(priv_key, comment, lifetime: nil, confirm: false) ⇒ Object
Adds the private key with comment to the agent. If lifetime is given, the key will automatically be removed after lifetime seconds. If confirm is true, confirmation will be required for each agent signing operation.
170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/net/ssh/authentication/agent.rb', line 170 def add_identity(priv_key, comment, lifetime: nil, confirm: false) constraints = Buffer.new if lifetime constraints.write_byte(SSH_AGENT_CONSTRAIN_LIFETIME) constraints.write_long(lifetime) end constraints.write_byte(SSH_AGENT_CONSTRAIN_CONFIRM) if confirm req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key), :string, comment, :raw, constraints) raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS end |
#close ⇒ Object
Closes this socket. This agent reference is no longer able to query the agent.
150 151 152 |
# File 'lib/net/ssh/authentication/agent.rb', line 150 def close @socket.close end |
#connect!(agent_socket_factory = nil, identity_agent = nil) ⇒ Object
Connect to the agent process using the socket factory and socket name given by the attribute writers. If the agent on the other end of the socket reports that it is an SSH2-compatible agent, this will fail (it only supports the ssh-agent distributed by OpenSSH).
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/net/ssh/authentication/agent.rb', line 85 def connect!(agent_socket_factory = nil, identity_agent = nil) debug { "connecting to ssh-agent" } @socket = if agent_socket_factory agent_socket_factory.call elsif identity_agent unix_socket_class.open(File.(identity_agent)) elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class unix_socket_class.open(File.(ENV['SSH_AUTH_SOCK'])) elsif Gem.win_platform? && RUBY_ENGINE != "jruby" Pageant::Socket.open else raise AgentNotAvailable, "Agent not configured" end rescue StandardError => e error { "could not connect to ssh-agent: #{e.}" } raise AgentNotAvailable, $!. end |
#identities ⇒ Object
Return an array of all identities (public keys) known to the agent. Each key returned is augmented with a comment
property which is set to the comment returned by the agent for that key.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/net/ssh/authentication/agent.rb', line 122 def identities type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES) raise AgentError, "could not get identity count" if agent_failed(type) raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER identities = [] body.read_long.times do key_str = body.read_string comment_str = body.read_string begin key = Buffer.new(key_str).read_key if key.nil? error { "ignoring invalid key: #{comment_str}" } next end key.extend(Comment) key.comment = comment_str identities.push key rescue NotImplementedError => e error { "ignoring unimplemented key:#{e.} #{comment_str}" } end end return identities end |
#lock(password) ⇒ Object
lock the ssh agent with password
197 198 199 200 |
# File 'lib/net/ssh/authentication/agent.rb', line 197 def lock(password) type, = send_and_wait(SSH2_AGENT_LOCK, :string, password) raise AgentError, "could not lock agent" if type != SSH_AGENT_SUCCESS end |
#negotiate! ⇒ Object
Attempts to negotiate the SSH agent protocol version. Raises an error if the version could not be negotiated successfully.
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/net/ssh/authentication/agent.rb', line 106 def negotiate! # determine what type of agent we're communicating with type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION) raise AgentNotAvailable, "SSH2 agents are not yet supported" if type == SSH2_AGENT_VERSION_RESPONSE if type == SSH2_AGENT_FAILURE debug { "Unexpected response type==#{type}, this will be ignored" } elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2 raise AgentNotAvailable, "unknown response from agent: #{type}, #{body.to_s.inspect}" end end |
#remove_all_identities ⇒ Object
Removes all identities from the agent.
191 192 193 194 |
# File 'lib/net/ssh/authentication/agent.rb', line 191 def remove_all_identities type, = send_and_wait(SSH2_AGENT_REMOVE_ALL_IDENTITIES) raise AgentError, "could not remove all identity from agent" if type != SSH_AGENT_SUCCESS end |
#remove_identity(key) ⇒ Object
Removes key from the agent.
185 186 187 188 |
# File 'lib/net/ssh/authentication/agent.rb', line 185 def remove_identity(key) type, = send_and_wait(SSH2_AGENT_REMOVE_IDENTITY, :string, key.to_blob) raise AgentError, "could not remove identity from agent" if type != SSH_AGENT_SUCCESS end |
#sign(key, data, flags = 0) ⇒ Object
Using the agent and the given public key, sign the given data. The signature is returned in SSH2 format.
156 157 158 159 160 161 162 163 |
# File 'lib/net/ssh/authentication/agent.rb', line 156 def sign(key, data, flags = 0) type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, flags) raise AgentError, "agent could not sign data with requested identity" if agent_failed(type) raise AgentError, "bad authentication response #{type}" if type != SSH2_AGENT_SIGN_RESPONSE return reply.read_string end |
#unlock(password) ⇒ Object
unlock the ssh agent with password
203 204 205 206 |
# File 'lib/net/ssh/authentication/agent.rb', line 203 def unlock(password) type, = send_and_wait(SSH2_AGENT_UNLOCK, :string, password) raise AgentError, "could not unlock agent" if type != SSH_AGENT_SUCCESS end |