1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

Merge pull request #1854 from kevinykchan/ssh-agent

[joyent|compute] support for http-signature-auth using ssh-agent -- Closes #1854
This commit is contained in:
Kevin Chan 2013-06-02 02:37:02 -07:00
commit 558db911f1
5 changed files with 46 additions and 33 deletions

View file

@ -1,6 +1,7 @@
require 'fog/joyent'
require 'fog/joyent/errors'
require 'fog/compute'
require 'net/ssh'
module Fog
module Compute
@ -9,8 +10,10 @@ module Fog
recognizes :joyent_password
recognizes :joyent_url
recognizes :joyent_keyname
recognizes :joyent_keyfile
recognizes :joyent_keyphrase
recognizes :joyent_version
model_path 'fog/joyent/models/compute'
@ -100,12 +103,12 @@ module Fog
class Real
def initialize(options = {})
@connection_options = options[:connection_options] || {}
@persistent = options[:persistent] || false
@joyent_url = options[:joyent_url] || 'https://us-sw-1.api.joyentcloud.com'
@joyent_version = options[:joyent_version] || '~6.5'
@joyent_username = options[:joyent_username]
unless @joyent_username
@ -115,16 +118,15 @@ module Fog
if options[:joyent_keyname] && options[:joyent_keyfile]
if File.exists?(options[:joyent_keyfile])
@joyent_keyname = options[:joyent_keyname]
@joyent_key = File.read(options[:joyent_keyfile])
@joyent_keyfile = options[:joyent_keyfile]
@joyent_keyphrase = options[:joyent_keyphrase]
if @joyent_key.lines.first.include?('-----BEGIN DSA PRIVATE KEY-----')
@key = OpenSSL::PKey::DSA.new(@joyent_key)
elsif @joyent_key.lines.first.include?('-----BEGIN RSA PRIVATE KEY-----')
@key = OpenSSL::PKey::RSA.new(@joyent_key)
else
raise ArgumentError, "options[joyent_keyfile] provided must be an RSA or DSA private key"
end
@key_manager = Net::SSH::Authentication::KeyManager.new(nil, {
:keys_only => true,
:passphrase => @joyent_keyphrase
})
@key_manager.add(@joyent_keyfile)
@header_method = method(:header_for_signature_auth)
else
@ -133,7 +135,6 @@ module Fog
elsif options[:joyent_password]
@joyent_password = options[:joyent_password]
@header_method = method(:header_for_basic_auth)
else
raise ArgumentError, "Must provide either a joyent_password or joyent_keyname and joyent_keyfile pair"
@ -146,25 +147,23 @@ module Fog
)
end
def request(request = {})
request[:headers] = {
def request(opts = {})
opts[:headers] = {
"X-Api-Version" => @joyent_version,
"Content-Type" => "application/json",
"Accept" => "application/json"
}.merge(request[:headers] || {}).merge(@header_method.call)
}.merge(opts[:headers] || {}).merge(@header_method.call)
if request[:body]
request[:body] = Fog::JSON.encode(request[:body])
if opts[:body]
opts[:body] = Fog::JSON.encode(opts[:body])
end
response = @connection.request(request)
response = @connection.request(opts)
if response.headers["Content-Type"] == "application/json"
response.body = json_decode(response.body)
end
raise_if_error!(request, response)
response
rescue Excon::Errors::Error => e
raise_if_error!(e.request, e.response)
@ -185,22 +184,34 @@ module Fog
def header_for_signature_auth
date = Time.now.utc.httpdate
begin
signature = Base64.encode64(@key.sign("sha256", date)).delete("\r\n")
rescue OpenSSL::PKey::PKeyError => e
if e.message == 'wrong public key type'
puts 'ERROR: Your version of ruby/openssl does not suport DSA key signing'
puts 'see: http://bugs.ruby-lang.org/issues/4734'
puts 'workaround: Please use an RSA key instead'
end
raise
# Force KeyManager to load the key(s)
@key_manager.each_identity {}
key = @key_manager.known_identities.keys.first
sig = if key.kind_of? OpenSSL::PKey::RSA
@key_manager.sign(key, date)[15..-1]
else
key = OpenSSL::PKey::DSA.new(File.read(@joyent_keyfile), @joyent_keyphrase)
key.sign('sha1', date)
end
key_id = "/#{@joyent_username}/keys/#{@joyent_keyname}"
key_type = key.class.to_s.split('::').last.downcase.to_sym
unless [:rsa, :dsa].include? key_type
raise Joyent::Errors::Unauthorized.new('Invalid key type -- only rsa or dsa key is supported')
end
signature = Base64.encode64(sig).delete("\r\n")
{
"Date" => date,
"Authorization" => "Signature keyId=\"#{key_id}\",algorithm=\"rsa-sha256\" #{signature}"
"Authorization" => "Signature keyId=\"#{key_id}\",algorithm=\"#{key_type}-sha1\" #{signature}"
}
rescue Net::SSH::Authentication::KeyManagerError => e
raise Joyent::Errors::Unauthorized.new('SSH Signing Error: :#{e.message}', e)
end
def decode_time_attrs(obj)

View file

@ -20,9 +20,9 @@ module Fog
# https://us-west-1.api.joyentcloud.com/docs#cloudapi-http-responses
#
# HTTP Status Codes
#
#
# Your client should check for each of the following status codes from any API request:
#
#
# Response Code Description
# 400 Bad Request Invalid HTTP Request

View file

@ -26,7 +26,9 @@ module Fog
def get(machine_id)
data = service.get_machine(machine_id).body
new(data)
server = new(data)
server.tags = server.list_tags if server.tags.nil?
server
end
end

View file

@ -6,7 +6,7 @@ module Fog
request(
:path => "/my/machines/#{machine_id}",
:method => "DELETE",
:expects => [200, 204]
:expects => [200, 204, 410]
)
end
end

View file

@ -20,7 +20,7 @@ module Fog
request(
:method => "GET",
:path => "/my/machines/#{uuid}",
:expects => 200
:expects => [200, 410]
)
end
end