Skip to content

Instantly share code, notes, and snippets.

@dodeja
Created January 24, 2009 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dodeja/51546 to your computer and use it in GitHub Desktop.
Save dodeja/51546 to your computer and use it in GitHub Desktop.
# Amazon FPS Plugin
require 'net/https'
require 'time'
require 'openssl'
require 'base64'
require 'yaml'
module AWS_FPS
# Load AWS config
path = File.expand_path "#{RAILS_ROOT}/config/amazon_fps.yml"
file = YAML.load_file path
config = file[RAILS_ENV].symbolize_keys
# Set default params and AWS keys
$KCODE = "u"
RETURN_BASE = config[:return_base]
PIPELINE = config[:pipeline]
ENDPOINT = config[:endpoint]
VERSION = config[:version]
ACCESS_KEY = config[:access_key]
SECRET_ACCESS_KEY = config[:secret_access_key]
SIGNATURE_VERSION = "1"
module Signature
# Case-insensitive sort by Hash key
def fps_sort(params)
params.sort_by { |key,value| key.downcase }
end
# HMAC SHA1 sign a string
def fps_sign(string)
digest = OpenSSL::Digest::Digest.new('sha1')
hmac = OpenSSL::HMAC.digest(digest, SECRET_ACCESS_KEY, string)
Base64.encode64(hmac).chomp
end
# Params are URL-encoded, also add '=' and '&'
def fps_urlencode(params)
params.collect {|key, value| key+"="+CGI.escape(value)}.join("&")
end
def fps_join(params)
params.collect {|key, value| key+"="+value}.join("&")
end
end # Signature module
class Pipeline
class << self
include AWS_FPS::Signature
def make_url(pipeline_params, return_params, return_path)
# Create URL-encoded return_url param
return_url = RETURN_BASE + "/" + return_path + "?" + fps_join(return_params)
# Add already URL-encoded 'returnURL' and Amazon Web Services Access Key
params = { 'returnURL' => return_url, 'callerKey' => ACCESS_KEY }.merge pipeline_params
params = fps_sort(params)
params = fps_urlencode(params)
# Sign path and URL-encoded params
sig_path = "/cobranded-ui/actions/start?" + params
signature = fps_sign(sig_path)
url = PIPELINE + params + "&awsSignature=" + CGI.escape(signature)
return url
end
end
end
class Query
class << self
include AWS_FPS::Signature
# Accepts Amazon FPS parameters. Returns false if HTTP error received.
# Otherwise, returns XML service response.
def do(params)
query = build_query params
xml_response = send_query query
return xml_response
end
def build_query(params)
defaults = { 'AWSAccessKeyId' => ACCESS_KEY,
'SignatureVersion' => SIGNATURE_VERSION,
'Version' => VERSION,
'Timestamp' => Time.now.gmtime.iso8601 }
params = params.merge defaults
# Sort params by Hash key, returns Array
params = fps_sort(params)
# Create digest of concatenated params
signature = fps_sign(params.to_s)
# URL-encode and join params with "&" and "=" to form full request
query = '/?' + fps_urlencode(params).to_s + "&Signature=" + CGI.escape(signature)
end
# Queries Amazon FPS service and returns XML service response
def send_query(query)
url = ENDPOINT + query
# Send Amazon FPS query to endpoint
url = URI.parse(url)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
req = Net::HTTP::Get.new(query)
response = http.start { |http| http.request(req) }
xml_response = response.body.to_s
xml_response.gsub! "ns3:", ""
xml_response.gsub! "ns2:", ""
# 200s and 401s HTTP responses return XML
case response
when Net::HTTPSuccess then
return xml_response
when Net::HTTPUnauthorized then
return xml_response
when Net::HTTPInternalServerError then
return xml_response
when Net::HTTPBadRequest then
return xml_response
else
false
end
end
end
end # Query class
class Tokens
class << self
def get_caller_token
unique_id = (Time.now.to_i + rand(1000)).to_s
call = { 'Action' => 'InstallPaymentInstruction',
'PaymentInstruction' => "MyRole == 'Caller' orSay 'Role does not match';",
'CallerReference' => unique_id,
'TokenType' => 'Unrestricted' }
# Make the FPS call
@fps_response = AWS_FPS::Query.do(call)
response_xml = REXML::Document.new(@fps_response)
elements = response_xml.root.elements
unless elements["Status"].nil?
@status = elements["Status"].text
return elements["TokenId"].text if @status == "Success"
end
end
def get_recipient_token
unique_id = (Time.now.to_i + rand(1000)).to_s
call = {'Action' => 'InstallPaymentInstruction',
'PaymentInstruction' => "MyRole == 'Recipient' orSay 'Roles do not match';",
'CallerReference' => unique_id,
'TokenType' => 'Unrestricted' }
# Make the FPS call
@fps_response = AWS_FPS::Query.do(call)
response_xml = REXML::Document.new(@fps_response)
elements = response_xml.root.elements
# Return the recipient token
unless elements["Status"].nil?
@status = elements["Status"].text
return elements["TokenId"].text if @status == "Success"
end
end
end
end # Tokens class
end # AWS_FPS module
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment