Parent

Included Modules

Class Index [+]

Quicksearch

Net::SSH::Authentication::Agent

This class implements an agent for JRuby + Pageant.

Written by Artūras Šlajus


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

Constants

SSH2_AGENT_REQUEST_VERSION
SSH2_AGENT_REQUEST_IDENTITIES
SSH2_AGENT_IDENTITIES_ANSWER
SSH2_AGENT_SIGN_REQUEST
SSH2_AGENT_SIGN_RESPONSE
SSH2_AGENT_FAILURE
SSH2_AGENT_VERSION_RESPONSE
SSH_COM_AGENT2_FAILURE
SSH_AGENT_REQUEST_RSA_IDENTITIES
SSH_AGENT_RSA_IDENTITIES_ANSWER1
SSH_AGENT_RSA_IDENTITIES_ANSWER2
SSH_AGENT_FAILURE

Attributes

socket[R]

The underlying socket being used to communicate with the SSH agent.

Public Class Methods

connect(logger=nil) click to toggle source

Instantiates a new agent object, connects to a running SSH agent, negotiates the agent protocol version, and returns the agent object.

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 22
22:     def self.connect(logger=nil)
23:       agent = new(logger)
24:       agent.connect!
25:       agent
26:     end
connect(logger=nil) click to toggle source

Instantiates a new agent object, connects to a running SSH agent, negotiates the agent protocol version, and returns the agent object.

    # File lib/net/ssh/authentication/agent/socket.rb, line 45
45:     def self.connect(logger=nil)
46:       agent = new(logger)
47:       agent.connect!
48:       agent.negotiate!
49:       agent
50:     end
new(logger=nil) click to toggle source

Creates a new Agent object, using the optional logger instance to report status.

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 30
30:     def initialize(logger=nil)
31:       self.logger = logger
32:     end
new(logger=nil) click to toggle source

Creates a new Agent object, using the optional logger instance to report status.

    # File lib/net/ssh/authentication/agent/socket.rb, line 54
54:     def initialize(logger=nil)
55:       self.logger = logger
56:     end

Public Instance Methods

close() click to toggle source

Simulate agent close. This agent reference is no longer able to query the agent.

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 69
69:     def close
70:       @agent_proxy = nil
71:     end
close() click to toggle source

Closes this socket. This agent reference is no longer able to query the agent.

     # File lib/net/ssh/authentication/agent/socket.rb, line 106
106:     def close
107:       @socket.close
108:     end
connect!() click to toggle source

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

    # File lib/net/ssh/authentication/agent/socket.rb, line 62
62:     def connect!
63:       begin
64:         debug { "connecting to ssh-agent" }
65:         @socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
66:       rescue
67:         error { "could not connect to ssh-agent" }
68:         raise AgentNotAvailable, $!.message
69:       end
70:     end
connect!() click to toggle source

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

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 38
38:     def connect!
39:       debug { "connecting to Pageant ssh-agent (via java connector)" }
40:       @agent_proxy = JRubyPageant.create
41:       unless @agent_proxy.is_running
42:         raise AgentNotAvailable, "Pageant is not running!"
43:       end
44:       debug { "connection to Pageant ssh-agent (via java connector) succeeded" }
45:     rescue AgentProxyException => e
46:       error { "could not connect to Pageant ssh-agent (via java connector)" }
47:       raise AgentNotAvailable, e.message, e.backtrace
48:     end
identities() click to toggle source

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.

     # File lib/net/ssh/authentication/agent/socket.rb, line 88
 88:     def identities
 89:       type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
 90:       raise AgentError, "could not get identity count" if agent_failed(type)
 91:       raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
 92: 
 93:       identities = []
 94:       body.read_long.times do
 95:         key = Buffer.new(body.read_string).read_key
 96:         key.extend(Comment)
 97:         key.comment = body.read_string
 98:         identities.push key
 99:       end
100: 
101:       return identities
102:     end
identities() click to toggle source

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.

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 53
53:     def identities
54:       debug { "getting identities from Pageant" }
55:       @agent_proxy.get_identities.map do |identity|
56:         blob = identity.get_blob
57:         key = Buffer.new(String.from_java_bytes(blob)).read_key
58:         key.extend(Key)
59:         key.java_blob = blob
60:         key.comment = String.from_java_bytes(identity.get_comment)
61:         key
62:       end
63:     rescue AgentProxyException => e
64:       raise AgentError, "Cannot get identities: #{e.message}", e.backtrace
65:     end
negotiate!() click to toggle source

Attempts to negotiate the SSH agent protocol version. Raises an error if the version could not be negotiated successfully.

    # File lib/net/ssh/authentication/agent/socket.rb, line 74
74:     def negotiate!
75:       # determine what type of agent we're communicating with
76:       type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
77: 
78:       if type == SSH2_AGENT_VERSION_RESPONSE
79:         raise NotImplementedError, "SSH2 agents are not yet supported"
80:       elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
81:         raise AgentError, "unknown response from agent: #{type}, #{body.to_s.inspect}"
82:       end
83:     end
sign(key, data) click to toggle source

Using the agent and the given public key, sign the given data. The signature is returned in SSH2 format.

     # File lib/net/ssh/authentication/agent/socket.rb, line 112
112:     def sign(key, data)
113:       type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
114: 
115:       if agent_failed(type)
116:         raise AgentError, "agent could not sign data with requested identity"
117:       elsif type != SSH2_AGENT_SIGN_RESPONSE
118:         raise AgentError, "bad authentication response #{type}"
119:       end
120: 
121:       return reply.read_string
122:     end
sign(key, data) click to toggle source

Using the agent and the given public key, sign the given data. The signature is returned in SSH2 format.

    # File lib/net/ssh/authentication/agent/java_pageant.rb, line 75
75:     def sign(key, data)
76:       signed = @agent_proxy.sign(key.java_blob, data.to_java_bytes)
77:       String.from_java_bytes(signed)
78:     rescue AgentProxyException => e
79:       raise AgentError,
80:         "agent could not sign data with requested identity: #{e.message}",
81:         e.backtrace
82:     end

Private Instance Methods

agent_failed(type) click to toggle source

Returns true if the parameter indicates a “failure” response from the agent, and false otherwise.

     # File lib/net/ssh/authentication/agent/socket.rb, line 163
163:     def agent_failed(type)
164:       type == SSH_AGENT_FAILURE ||
165:         type == SSH2_AGENT_FAILURE ||
166:         type == SSH_COM_AGENT2_FAILURE
167:     end
agent_socket_factory() click to toggle source

Returns the agent socket factory to use.

     # File lib/net/ssh/authentication/agent/socket.rb, line 127
127:     def agent_socket_factory
128:       if Net::SSH::Authentication::PLATFORM == :win32
129:         Pageant::socket_factory
130:       else
131:         UNIXSocket
132:       end
133:     end
read_packet() click to toggle source

Read the next packet from the agent. This will return a two-part tuple consisting of the packet type, and the packet’s body (which is returned as a Net::SSH::Buffer).

     # File lib/net/ssh/authentication/agent/socket.rb, line 146
146:     def read_packet
147:       buffer = Net::SSH::Buffer.new(@socket.read(4))
148:       buffer.append(@socket.read(buffer.read_long))
149:       type = buffer.read_byte
150:       debug { "received agent packet #{type} len #{buffer.length-4}" }
151:       return type, buffer
152:     end
send_and_wait(type, *args) click to toggle source

Send the given packet and return the subsequent reply from the agent. (See # and #).

     # File lib/net/ssh/authentication/agent/socket.rb, line 156
156:     def send_and_wait(type, *args)
157:       send_packet(type, *args)
158:       read_packet
159:     end
send_packet(type, *args) click to toggle source

Send a new packet of the given type, with the associated data.

     # File lib/net/ssh/authentication/agent/socket.rb, line 136
136:     def send_packet(type, *args)
137:       buffer = Buffer.from(*args)
138:       data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
139:       debug { "sending agent request #{type} len #{buffer.length}" }
140:       @socket.send data, 0
141:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.