Created
January 24, 2009 20:40
-
-
Save dodeja/51546 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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