This appendix provides sample code for generating request signatures. For more information about signatures and how to generate them, see Working with Signatures.
You can use the programming language of your choice to implement the HMAC algorithm that generates a signature. If you are a Java, PHP, Perl, or Ruby developer, you can use one of the following code samples as is to generate a signature. You can also download samples from the Amazon FPS Developer Resource Center.
The following Java example demonstrates how to create an RFC 2104-compliant HMAC signature. For more information about HMAC, go to http://www.ietf.org/rfc/rfc2104.txt.
/*
Copyright 2007 Amazon Technologies, Inc. Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the License at:
http://aws.amazon.com/apache2.0
This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
*/
package amazon.webservices.common;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* This class defines common routines for generating
* a signed dynamic Amazon Payments 'Pay Now' widget form.
*/
public class PayNowWidgetUtils {
private static final String accessKey = "<insert-your-access-key-here>";
private static final String secretKey = "<insert-your-secret-key-here>";
public static String getPayNowWidgetForm(String amount, String description, String referenceId,
String immediateReturn, String returnUrl, String abandonUrl)
throws java.security.SignatureException{
//Create a Map of the hidden inputs in the form
Map<String, String> formHiddenInputs = new HashMap<String, String>();
formHiddenInputs.put("accessKey", accessKey);
formHiddenInputs.put("amount", amount);
formHiddenInputs.put("referenceId ", referenceId);
if (referenceId != null) formHiddenInputs.put("referenceId ", referenceId);
if (immediateReturn != null) formHiddenInputs.put("immediateReturn", immediateReturn);
if (returnUrl != null) formHiddenInputs.put("returnUrl", returnUrl);
if (abandonUrl != null) formHiddenInputs.put("abandonUrl", abandonUrl);
//Calculate the signature and add the signature as a hidden input
String stringToSign = getStringToSign(formHiddenInputs);
String signature = calculateRFC2104HMAC(stringToSign);
formHiddenInputs.put("signature", signature);
//Generate the HTML code for the form and return
return getPayNowWidgetForm(formHiddenInputs);
}
/**
* @param formHiddenInputs
* Map of the hidden input fields in the 'Pay Now' widget form
* This map should have key = name of the hidden input and value = value of the hidden input
* @return
* The HTML code for the 'Pay Now' widget form
*/
public static String getPayNowWidgetForm(Map<String, String> formHiddenInputs) {
StringBuilder form = new StringBuilder("<form action=\"https://authorize.payments.amazon.com/pba/paypipeline\" method=\"post\">\n");
form.append("<input type=\"image\" src=\"https://authorize.payments.amazon.com/pba/images/amazonPaymentsButton.jpg\" border=\"0\"/>\n");
Set<String> formHiddenInputNames = formHiddenInputs.keySet();
for (String formHiddenInputName : formHiddenInputNames) {
form.append("<input type=\"hidden\" name=\"" + formHiddenInputName +
"\" value=\"" + formHiddenInputs.get(formHiddenInputName)+ "\" />\n");
}
form.append("</form>\n");
return form.toString();
}
/**
* Computes RFC 2104-compliant HMAC signature.
*
* @param data
* The data to be signed.
* @return
* The base64-encoded RFC 2104-compliant HMAC signature.
* @throws
* java.security.SignatureException when signature generation fails
*/
public static String calculateRFC2104HMAC(String data)
throws java.security.SignatureException
{
String result;
try {
// get an hmac_sha1 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes(),"HmacSHA1");
// get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes());
/*
base64-encode the hmac: NOTE THAT YOU WILL HAVE TO PROVIDE YOUR OWN Base64 ENCODING METHOD!
A public version is available at http://iharder.net/base64
*/
result = Base64.encodeBytes(rawHmac);
}
catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
/**
*
* @param formHiddenInputs
* Map of the hidden input fields in the 'Pay Now' widget form
* This map should have key = name of the hidden input and value = value of the hidden input
* @return
* The signature for the 'Pay Now' widget form
*/
public static String getStringToSign(Map<String, String> parameters) {
StringBuilder stringToSign = new StringBuilder();
//Create a List of parameter names
Set<String> paramNames = parameters.keySet();
List<String> params = new ArrayList<String>(paramNames.size());
for (String param : paramNames) {
params.add(param);
}
//Sort the parameter names in a case insensitive way
Collections.sort(params, String.CASE_INSENSITIVE_ORDER);
//Create the string to sign
for (String param : params) {
stringToSign.append(param);
stringToSign.append(parameters.get(param));
}
return stringToSign.toString();
}
public static void main(String[] args)
{
try {
String payNowWidgetForm = getPayNowWidgetForm("USD 1.00", "Celtic Folk Song", "cfg385", "0",
"http://yourwebsite.com/return.html", "http://yourwebsite.com/cancel.html");
System.out.println(payNowWidgetForm);
} catch (java.security.SignatureException e) {
System.err.println("Encountered a SignatureException.");
}
}
} The following is a PHP example that demonstrates how to create an RFC 2104-compliant HMAC signature. For more information about HMAC, go to http://www.ietf.org/rfc/rfc2104.txt.
<?
#PHP Sample Code for creating a 'Pay Now' widget
#To use this sample, replace the values of $accessKey and $secretKey with the values for your account
require_once 'Crypt/HMAC.php'; #see http://pear.php.net/package/Crypt_HMAC
require_once 'HTTP/Request.php'; #see http://pear.php.net/package/HTTP_Request
$accessKey = "<insert-your-access-key-here>";
$secretKey = "<insert-your-secret-key-here>";
function getPayNowButtonForm($amount, $description, $referenceId,
$immediateReturn, $returnUrl, $abandonUrl) {
global $accessKey;
$formHiddenInputs['accessKey'] = $accessKey;
$formHiddenInputs['amount'] = $amount;
$formHiddenInputs['description'] = $description;
if ($referenceId) $formHiddenInputs['referenceId'] = $referenceId;
if ($immediateReturn) $formHiddenInputs['immediateReturn'] = $immediateReturn;
if ($returnUrl) $formHiddenInputs['returnUrl'] = $returnUrl;
if ($abandonUrl) $formHiddenInputs['abandonUrl'] = $abandonUrl;
#sort the array elements in a case-insensitive way
natcasesort($formHiddenInputs);
$stringToSign = "";
foreach ($formHiddenInputs as $formHiddenInputName => $formHiddenInputValue) {
$stringToSign = $stringToSign . $formHiddenInputName . $formHiddenInputValue;
}
$formHiddenInputs['signature'] = getSignature($stringToSign, $secretKey);
$form = "<form action=\"https://authorize.payments.amazon.com/pba/paypipeline\" method=\"post\">\n";
foreach ($formHiddenInputs as $formHiddenInputName => $formHiddenInputValue) {
$form = $form . "<input type=\"hidden\" name=\"$formHiddenInputName\" value=\"$formHiddenInputValue\" />\n";
}
$form = $form . "<input type=\"image\" src=\"https://authorize.payments.amazon.com/pba/images/amazonPaymentsButton.jpg\" border=\"0\" alt=\"Pay Using Amazon\" />\n";
$form = $form . "</form>\n";
return $form;
}
function getSignature($stringToSign) {
global $secretKey;
$hmac = new Crypt_HMAC($secretKey,"sha1");
$binary_hmac = pack("H40", $hmac->hash(trim($stringToSign)));
return base64_encode($binary_hmac);
}
?>
<html>
<body>
<?=getPayNowButtonForm("USD 1.00", "e-Card", "i123n", "1", "http://yourwebsite.com/return.html",
"http://yourwebsite.com/abandon.htm") ?>
</body>
</html>The following Perl example demonstrates how to create an RFC 2104-compliant HMAC signature. For more information about HMAC, go to http://www.ietf.org/rfc/rfc2104.txt.
=pod
Copyright 2007 Amazon Technologies, Inc. Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy of the License at:
http://aws.amazon.com/apache2.0
This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
=cut
use Digest::HMAC_SHA1;
use MIME::Base64;
# Please use perl version 5.8 or above to run this sample.
# You will also need the "Digest::HMAC_SHA1", and "MIME::Base64" perl modules
# 1. Save this file as 'PayNowWidgetUtils.pl' without the quotes.
# 2. Run as: perl PayNowWidgetUtils.py
# 3. You'll see a sample HTML Form as output.
# 4. You can make a call to the 'generate_signed_form' subroutine as shown at the end of this file
# 5. In order to generate your own HTML Form, change the parameters as required at the end of this file
# 6. This sample, by default, generates a form which points to the Amazon Simple Pay Sandbox.
# In order to start pointing to Pay Now Widget Production, do the following:
# Replace "authorize.payments-sandbox.amazon.com" with "authorize.payments.amazon.com" in the generated HTML
#
sub generate_signed_form {
my ($access_key, $aws_secret_key, $form_params) = @_;
# Amount and description are required before
# a button can be signed and displayed to user
die "Amount and Description are required\n"
unless $form_params->{amount} and $form_params->{description};
# AWS Key is also a form parameter, called accessKey, and hence has to be signed
$form_params->{accessKey} = $access_key;
# keep params in a case-insensitive sorted order
my $str_to_sign = "";
$str_to_sign .= $_ . $form_params->{$_} for (sort keys {lc $a cmp lc $b} (%$form_params));
# calculate the signature of the above canonicalized string
my $hmac = Digest::HMAC_SHA1->new($aws_secret_key);
$hmac->add($str_to_sign);
my $signature = encode_base64($hmac->digest);
chomp($signature);
$form_params->{signature} = $signature;
# construct a Amazon Payments button form with all the parameters and signature
my $signed_form =<<STARTFORM;
<form action="https://authorize.payments-sandbox.amazon.com/pba/paypipeline" method="post">
STARTFORM
while(my ($k, $v) = each(%$form_params)){
next unless $k and $v;
$signed_form .=<<"FORMELEM";
<input type="hidden" name="$k" value="$v" >
FORMELEM
}
$signed_form .=<<"ENDFORM";
<input type="image" src="https://authorize.payments-sandbox.amazon.com/pba/images/amazonPaymentsButton.jpg" border="0" >
</form>
ENDFORM
return $signed_form;
}
# The main program. Change the parameters here to get your own customized form
use constant ACCESS_KEY => '<insert-your-access-key-here>';
use constant SECRET_KEY => '<insert-your-secret-key-here>';
print generate_signed_form(ACCESS_KEY, SECRET_KEY, {amount => 'USD 10.99',
description => 'Test button',
referenceId => 'txn1103',
returnUrl => 'http://yourwebsite.com/return.html',
abandonUrl => 'http://yourwebsite.com/abandon.html'})
The following Ruby example demonstrates how to create an RFC 2104-compliant HMAC signature. For more information about HMAC, go to http://www.ietf.org/rfc/rfc2104.txt.
# Copyright 2007 Amazon Technologies, Inc. Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy of the License at:
#
# http://aws.amazon.com/apache2.0
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.
require 'base64'
require 'openssl'
# Please use ruby version 1.8.3 or later to run this sample.
# 1. Save this code in a file, PayNowWidgetUtils.rb.
# 2. Run as: ruby PayNowWidgetUtils.rb
# 3. You'll see a sample HTML form
# 4. You can make a call to the 'generate_signed_form' subroutine as demonstrated at the end of this file.
# 5. Change the parameters at the end of this file, to generate your own HTML Form
# 6. This sample, by default, generates a form which points to the Pay Now Widget Sandbox.
# In order to start pointing to Pay Now Widget Production, do the following:
# Replace "authorize.payments-sandbox.amazon.com" with "authorize.payments.amazon.com" in the generated HTML
#
module PayNowWidgetUtils
def generate_signed_form(access_key, aws_secret_key, form_params)
form_params['accessKey'] = access_key
# lexicographically sort the form parameters in a case-insensitive way
# and create the canonicalized string
str_to_sign = ""
form_params.keys.sort{|a,b| a.downcase <=> b.downcase}.each
{|k| str_to_sign += "#{k}#{params[k]}" }
# calculate signature of the above string
digest = OpenSSL::Digest::Digest.new('sha1')
hmac = OpenSSL::HMAC.digest(digest, aws_secret_key, str_to_sign)
form_params['signature'] = Base64.encode64(hmac).chomp
# construct the form
signed_form =<<-STARTFORM
<form action="https://authorize.payments-sandbox.amazon.com/pba/paypipeline"
method="post">
STARTFORM
form_params.each do |key, value|
next unless key and value
signed_form +=<<-"FORMELEM"
<input type="hidden" name="#{key}" value="#{value}" >
FORMELEM
end
signed_form +=<<-ENDFORM
<input type="image"
src="https://authorize.payments-sandbox.amazon.com/pba/images/amazonPaymentsButton.jpg"
border="0" >
</form>
ENDFORM
return signed_form
end
end
include PayNowWidgetUtils
ACCESS_KEY = 'put-your-access-key-here'
SECRET_KEY = 'put-your-secret-key-here'
print generate_signed_form(ACCESS_KEY, SECRET_KEY,
'amount' => 'USD 10.99',
'description' => 'Test Button',
'referenceId' => 'txn1102',
'returnUrl' => 'http://yourwebsite.com/return.html',
'abandonUrl' => 'http://yourwebsite.com/abandon.html')