Browse files

Switching to Amazon FPS example code for URL encoding on VerifySignat…

…ure requests
  • Loading branch information...
1 parent 4bc875b commit 5b954d57279a48c7459a180cd64ef02b4bf5995d @pboling pboling committed Oct 31, 2010
View
20 lib/remit.rb
@@ -17,6 +17,7 @@
require 'remit/data_types'
require 'remit/common'
require 'remit/error_codes'
+require 'remit/signature_utils_for_outbound'
require 'remit/verify_signature'
require 'remit/inbound_request'
require 'remit/ipn_request'
@@ -129,22 +130,3 @@ def query(request)
end
end
-#Hack on Hash to make it s rocket
-class Hash
- def to_url_params
- elements = []
- keys.size.times do |i|
- elements << "#{(keys[i])}=#{Remit::SignedQuery.escape_value(values[i])}"
- end
- elements.join('&')
- end
-
- def self.from_url_params(url_params)
- result = {}.with_indifferent_access
- url_params.split('&').each do |element|
- element = element.split('=')
- result[element[0]] = element[1]
- end
- result
- end
-end
View
20 lib/remit/common.rb
@@ -127,3 +127,23 @@ def sign
end
end
end
+
+#Hack on Hash to make it s rocket
+class Hash
+ def to_url_params
+ elements = []
+ keys.size.times do |i|
+ elements << "#{(keys[i])}=#{Remit::SignedQuery.escape_value(values[i])}"
+ end
+ elements.join('&')
+ end
+
+ def self.from_url_params(url_params)
+ result = {}
+ url_params.split('&').each do |element|
+ element = element.split('=')
+ result[element[0]] = element[1]
+ end
+ result
+ end
+end
View
26 lib/remit/get_pipeline.rb
@@ -244,11 +244,27 @@ def pipeline_name
Remit::PipelineName::EDIT_TOKEN
end
end
-
- %w( single_use multi_use recipient recurring_use postpaid prepaid edit_token ).each do |pipeline|
- define_method("get_#{pipeline}_pipeline") do |options|
- get_pipeline("Remit::GetPipeline::#{pipeline.classify}Pipeline".constantize, options)
- end
+
+ def get_single_use_pipeline(options)
+ get_pipeline(Remit::GetPipeline::SingleUsePipeline, options)
+ end
+ def get_multi_use_pipeline(options)
+ get_pipeline(Remit::GetPipeline::MultiUsePipeline, options)
+ end
+ def get_recipient_pipeline(options)
+ get_pipeline(Remit::GetPipeline::RecipientPipeline, options)
+ end
+ def get_recurring_use_pipeline(options)
+ get_pipeline(Remit::GetPipeline::RecurringUsePipeline, options)
+ end
+ def get_postpaid_pipeline(options)
+ get_pipeline(Remit::GetPipeline::PostpaidPipeline, options)
+ end
+ def get_prepaid_pipeline(options)
+ get_pipeline(Remit::GetPipeline::PrepaidPipeline, options)
+ end
+ def get_edit_token_pipeline(options)
+ get_pipeline(Remit::GetPipeline::EditTokenPipeline, options)
end
def get_pipeline(pipeline_subclass, options)
View
10 lib/remit/inbound_request.rb
@@ -4,14 +4,16 @@ module Remit
class InboundRequest
include ConvertKey
+ extend SignatureUtilsForOutbound
+
protected :convert_key
attr_reader :supplied_signature
attr_reader :allow_sigv1
# signature key name
SIGNATURE_KEY = 'signature'
-
+
##
# +request_url+ is the full request path up to the query string, as from request.url in the controller
# +params+ is the full params hash from the controller
@@ -31,9 +33,11 @@ def initialize(request_url, params, client, options = {})
def valid?
if @params['signatureVersion'].to_i == 2
+ return false unless InboundRequest.check_parameters(@params)
verify_request = Remit::VerifySignature::Request.new(
- :url_end_point => @request_url,
- :http_parameters => @params.to_url_params
+ :url_end_point => InboundRequest.urlencode(@request_url),
+ :version => Remit::API::API_VERSION,
+ :http_parameters => InboundRequest.urlencode(InboundRequest.get_http_params(@params))
)
result = @client.verify_signature(verify_request)
result.verify_signature_result.verification_status == 'Success'
View
74 lib/remit/signature_utils_for_outbound.rb
@@ -0,0 +1,74 @@
+require 'base64'
+require 'cgi'
+#require 'openssl'
+#require 'net/http'
+#require 'net/https'
+
+#Lifted From Amazon FPSRuby Code example and then refactored for remit
+module Remit
+ module SignatureUtilsForOutbound
+ # Convert a string into URL encoded form.
+ def urlencode(plaintext)
+ CGI.escape(plaintext.to_s).gsub("+", "%20").gsub("%7E", "~")
+ end
+
+# def get_http_data(url)
+# #2. fetch certificate if not found in cache
+# uri = URI.parse(url)
+# http_session = Net::HTTP.new(uri.host, uri.port)
+# http_session.use_ssl = true
+# http_session.ca_file = 'ca-bundle.crt'
+# http_session.verify_mode = OpenSSL::SSL::VERIFY_PEER
+# http_session.verify_depth = 5
+#
+# res = http_session.start {|http_session|
+# req = Net::HTTP::Get.new(url, {"User-Agent" => USER_AGENT_STRING})
+# http_session.request(req)
+# }
+#
+# return res.body
+# end
+#
+# def starts_with(string, prefix)
+# prefix = prefix.to_s
+# string[0, prefix.length] == prefix
+# end
+
+ def get_http_params(params)
+ params.map do |(k, v)|
+ urlencode(k) + "=" + urlencode(v)
+ end.join("&")
+ end
+
+ SIGNATURE_KEYNAME = "signature"
+ SIGNATURE_METHOD_KEYNAME = "signatureMethod"
+ SIGNATURE_VERSION_KEYNAME = "signatureVersion"
+ CERTIFICATE_URL_KEYNAME = "certificateUrl"
+ SIGNATURE_VERSION_2 = "2"
+
+ #Will raise an error if there are obvious problems with the request (indicating it was forged or corrupted)
+ def check_parameters(params)
+# begin
+ raise ":parameters must be enumerable" unless params.kind_of? Enumerable
+
+ signature = params[SIGNATURE_KEYNAME];
+ raise "'signature' is missing from the parameters." if (signature.nil?)
+
+ signature_version = params[SIGNATURE_VERSION_KEYNAME];
+ raise "'signatureVersion' is missing from the parameters." if (signature_version.nil?)
+ raise "'signatureVersion' present in parameters is invalid. Valid values are: 2" if (signature_version != SIGNATURE_VERSION_2)
+
+ signature_method = params[SIGNATURE_METHOD_KEYNAME]
+ raise "'signatureMethod' is missing from the parameters." if (signature_method.nil?)
+
+ certificate_url = params[CERTIFICATE_URL_KEYNAME]
+ raise "'certificate_url' is missing from the parameters." if (certificate_url.nil?)
+ return true
+# rescue
+# puts "There was a problem with parameters being invalid or missing."
+# return false
+# end
+ end
+
+ end
+end
View
7 spec/integrations/ipn_request_spec.rb
@@ -5,7 +5,7 @@
# The signature does not match the one calculated for these req params by amazon. Need to get a fresh example.
# So it is currently a test that a bad signature will be verified as BAD
before(:each) do
- @request_params = {
+ @bad_request_params = {
"action" => "notice",
"buyerName" => "Fps Buyer",
"callerReference" => "4-8-1-3.5",
@@ -14,7 +14,7 @@
"paymentMethod" => "CC",
"recipientEmail" => "recipient@email.url",
"recipientName" => "Fps Business",
- "signatureVersion" => Remit::API::SIGNATURE_VERSION,
+ "signatureVersion" => Remit::API::SIGNATURE_VERSION.to_s,
"signatureMethod" => "RSA-SHA1",
"certificateUrl" => "https://fps.sandbox.amazonaws.com/certs/090909/PKICert.pem",
Remit::IpnRequest::SIGNATURE_KEY => "This-is-a-bad-sig",
@@ -24,7 +24,7 @@
"transactionId" => "13KIGL9RC25853BGPPOS2VSKBKF2JERR3HO"
}
- @request = Remit::IpnRequest.new('http://example.com/ipn/processor', @request_params, remit)
+ @request = Remit::IpnRequest.new('http://example.com/ipn/processor', @bad_request_params, remit)
end
it 'should not be a valid request' do
@@ -37,3 +37,4 @@
@request.transactionId.should == '13KIGL9RC25853BGPPOS2VSKBKF2JERR3HO'
end
end
+
View
27 spec/integrations/pipeline_response_spec.rb
@@ -0,0 +1,27 @@
+require File.dirname(__FILE__) + '/integrations_helper'
+#require 'uri'
+#require 'remit/common'
+
+#TODO: Turn this into an integration test...
+#describe "Pipeline Response should work" do
+#
+# before(:each) do
+# params = { :status => "SA",
+# :tokenID => "foo",
+# :callerReference => "bar",
+# :awsSignature => "7QrCpQ1nMng3Usaj8LFkeo4zorM="}
+# url = URI.parse("http://example.com/payment?#{params.to_url_params}")
+# @pipeline_response = Remit::PipelineResponse.new(url.path, url.query, SECRET_KEY)
+# end
+#
+#
+# it "should be valid" do
+# puts "#{@pipeline_response.inspect}"
+# @pipeline_response.should be_valid
+# end
+#
+# it "should be successful" do
+# @pipeline_response.successful?.should == true
+# end
+#
+#end
View
25 spec/integrations/verify_signature_spec.rb
@@ -0,0 +1,25 @@
+require File.dirname(__FILE__) + '/integrations_helper'
+
+
+#TODO: Need to get a positive test in here...
+#describe 'a VerifySignature Request fails on bad signature' do
+#
+# before(:each) do
+# verify_request = Remit::VerifySignature::Request.new(
+# :url_end_point => "http://vamsik.desktop.amazon.com:8080/ipn.jsp",
+# :version => "2008-09-17",
+# :http_parameters =>
+#"expiry%3D08%252F2015%26signature%3DynDukZ9%252FG77uSJVb5YM0cadwHVwYKPMKOO3PNvgADbv6VtymgBxeOWEhED6KGHsGSvSJnMWDN%252FZl639AkRe9Ry%252F7zmn9CmiM%252FZkp1XtshERGTqi2YL10GwQpaH17MQqOX3u1cW4LlyFoLy4celUFBPq1WM2ZJnaNZRJIEY%252FvpeVnCVK8VIPdY3HMxPAkNi5zeF2BbqH%252BL2vAWef6vfHkNcJPlOuOl6jP4E%252B58F24ni%252B9ek%252FQH18O4kw%252FUJ7ZfKwjCCI13%252BcFybpofcKqddq8CuUJj5Ii7Pdw1fje7ktzHeeNhF0r9siWcYmd4JaxTP3NmLJdHFRq2T%252FgsF3vK9m3gw%253D%253D%26signatureVersion%3D2%26signatureMethod%3DRSA-SHA1%26certificateUrl%3Dhttps%253A%252F%252Ffps.sandbox.amazonaws.com%252Fcerts%252F090909%252FPKICert.pem%26tokenID%3DA5BB3HUNAZFJ5CRXIPH72LIODZUNAUZIVP7UB74QNFQDSQ9MN4HPIKISQZWPLJXF%26status%3DSC%26callerReference%3DcallerReferenceMultiUse1&AWSAccessKeyId=AKIAJGC2KB2QP7MVBLYQ&Timestamp=2010-02-26T19:48:05.000Z&version=2008-09-17&signatureVersion=2&signatureMethod=RSA-SHA1&signature=fKRGL42K7nduDA47g6bJCyUyF5ZvkBotXE5jVcgyHvE%3D"
+# )
+# @live_response = remit.verify_signature(verify_request)
+#
+# doc = File.read("spec/mocks/errors/InvalidParams_certificateUrl.xml")
+#
+# @prerecorded_response = Remit::VerifySignature::Response.new(doc)
+# end
+#
+# it "should not be a valid request" do
+# @live_response.errors.first.message.should == @prerecorded_response.errors.first.message
+# end
+#
+#end
View
10 spec/mocks/errors/InvalidParameterValue.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<Response>
+ <Errors>
+ <Error>
+ <Code>InvalidParameterValue</Code>
+ <Message>Value (2010-02-26 T19:48:05.000Z) for parameter Timestamp is invalid. Must be in ISO8601 format.</Message>
+ </Error>
+ </Errors>
+ <RequestID>794c2c9f-2d0e-4a9b-9ade-e80a58d09956</RequestID>
+</Response>
View
2 spec/mocks/errors/InvalidParams_certificateUrl.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<Response><Errors><Error><Code>InvalidParams</Code><Message>certificateUrl is missing in 'HttpParameters'.</Message></Error></Errors><RequestID>edac86c2-d488-4cdd-a069-cfe217b5c4af</RequestID></Response>
View
10 spec/mocks/errors/RequestExpired.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<Response>
+ <Errors>
+ <Error>
+ <Code>RequestExpired</Code>
+ <Message>Request has expired. Timestamp date is 2010-02-26T19:48:05.000Z</Message>
+ </Error>
+ </Errors>
+ <RequestID>465f3304-acc4-4831-9e58-bc07f80c8b50</RequestID>
+</Response>
View
4 spec/spec_helper.rb
@@ -26,8 +26,8 @@
require File.expand_path(File.dirname(__FILE__) + '/../lib/remit')
-def remit
- @remit ||= Remit::API.new(ACCESS_KEY, SECRET_KEY, true)
+def remit(access_key = ACCESS_KEY, seret_key = SECRET_KEY)
+ @remit ||= Remit::API.new(access_key, seret_key, true)
end
describe 'a successful response', :shared => true do

0 comments on commit 5b954d5

Please sign in to comment.