Archive

Archive for July, 2009

Integrating PayPal Express Checkout with AIR and Flex

July 30th, 2009 1 comment

This article continues the series about integrating Flex and AIR with payment gateway services. Parts of this article are very similar with the other posts about this subject:
Integrating PayPal Express Checkout with Flex(which I recommend reading before this article),Using Amazon Flexible Payment System with Flex and Using Amazon Flexible Payment System with Flex & AIR.

I will focus mainly on how to take the PayPal + Flex workflow (described here) out of the browser and into an AIR application.

Although AIR applications run on the desktop and the local security constraints are different from those in the browser, from a payment gateway point of view things don’t change at all. As a result, we can conclude that because AIR is a client technology hardcoding sensitive information into an AIR app is highly insecure (even though the code is compiled into bytecode). This means that any credential related info (like API_USERNAME, API_PASSWORD and API_SIGNATURE) should NOT be stored in the AIR application.

Architectural Approach and UI solutions

Summing this up, our architectural solution has to comply with some concurrent demands:

  • an AIR front-end that is stateful and is built following the single page app paradigm
  • the need for security that requires that the AIR app should NOT deal with PayPal API credentials
  • The payment workflow has a part that is hosted on the PayPal servers and that is a standard request-response web application

In order to address these I propose the following approach:

  • all PayPal API calls should be done on the server side so that API credentials will be protected
  • the access to the PayPal web application should be done in a browser page. IMPORTANT SECURITY NOTE: Although technically it might be possible to use the HTML container of the AIR runtime this is an unsecure practice because the end user cannot visually verify that he is entering his credentials on the PayPal site. In the browser he can check the URL and the security certificate.

So the buyer workflow becomes:

  1. (Step 1) Chooses to checkout using PayPal in the AIR application (Security Note: Starting from this point it is mandatory that all requests are done through https)
  2. (Step 2) Sees a browser window open and logs into PayPal to authenticate his/her identity
  3. (Step 3) Reviews the transaction on PayPal
  4. (Step 4) Confirms the order and pays from your site
  5. (Step 5) Reviews the order confirmation on your site
  6. (Step 6) Returns to the AIR application

 

Calling the PayPal part of the checkout process

So the PayPal workflow should be open in a browser window. Here is how to do that in the AIR app:

var url:URLRequest = new URLRequest(URL_ROOT + "/payPalAIR/startPaymentFlex.php");
url.data = new URLVariables();
var obj:URLVariables = new URLVariables();
url.data.movieId = '1';
url.data.paymentReason = 'Enter The Matrix';
url.method = "GET";

navigateToURL(url, "new");
currentState='Wait';

Everything else is pretty similar with how you call the PayPal workflow from a Flex app.

Returning from PayPal and notifying the AIR application

Here again we follow an approach similar with how you return from PayPal to a Flex application (Step 4 and Step 5).

The only thing that differs is how we get back to the AIR application (Step 6). ExternalInterface is not suited for this job but we can use instead the LocalConnection to make the browser application communicate with the AIR one. LocalConnection, while being more secure than ExternalIterface, can still be exploited using techniques like DNS rewriting so we can’t pass sensitive information through it. Furthermore, since the AIR app is independent from the browser this means that our browser app has a different server session than the AIR App. So a simple notification is not enough: we need to also pass the session id. This is not sensitive information, but it will allow the AIR application to retrieve from the server any sensitive information that the browser application has set.

Let’s take a look on what we need to do right after we call the PAY operation in our return page. In the transaction detail page we will link to a little Flex application that will only communicate with the AIR application. We can use this little application to also forward the error and cancel messages. We will call it using an anchor parameter:

<a class="home" id="CallsLink" href="payPalAIRReturn.html#method=doStatus">Return to AIR</a>

This little application will only contain some code that will get the cookie string from the browser (remember we need this to make the AIR application connect to the same server session) and send a message through LocalConnection to the AIR application:

private var outbound:LocalConnection = new LocalConnection();
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
	var browserManager:IBrowserManager = BrowserManager.getInstance();
	browserManager.init();
	var urlObj:Object = URLUtil.stringToObject(browserManager.fragment);
	if (urlObj.method) {
		//get the cookie string
		ExternalInterface.call('eval','window.cookieStr = function () {return document.cookie};')
			var cookieStr:String = ExternalInterface.call('cookieStr');
		outbound.connect("paymentSample");
		outbound.send("app#payPalAIR:paymentSample",urlObj.method,cookieStr);
		outbound.close();
	}
}

Please notice that when launching from Flex Builder the AIR Application has no Publisher ID so the connection name is “app#payPalAIR:paymentSample”. After packaging and installation the AIR app will get a Publisher ID so the connection name becomes something like this: app#payPalAIR.F0B3F68E1857B8A07069FED1D0638CAF200F76EB.1:paymentSample

You can get the publisher ID of the installed AIR app by looking at the META-INF/AIR/publisherid file within the application install directory.

Back in the AIR application we need to expose the functions through local connection:

private function initApp():void {
	//only allow connections from localhost
	//you need to replace "localhost" with the final domain
	//where your application will be hosted
	inbound.allowDomain("localhost");
	inbound.client = new Object();
	//this is the function that will be called by the Browser App
	inbound.client.doStatus = doStatus;
	inbound.client.doError = doError;
	inbound.client.doCancel = doCancel;

	//inbound.client.
	inbound.connect("paymentSample");

}

All methods (doStatus, do Error and doCancel) will receive the cookie string as a parameter. In do Status we need to check the transaction status on the server:

private function doStatus(cookieStr:String):void {
	var srv:HTTPService = new HTTPService();
	srv.headers.Cookie = cookieStr;
	srv.url = URL_ROOT + "/payPalAIR/getPaymentStatus.php";
	srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {

		Alert.show(event.result.status.type);
		nativeApplication.activate();
		if (event.result.status.type == 'SUCCESS') {
			currentState = 'Succes';
		} else {
			currentState = 'Fail';
		}
	});
	srv.addEventListener(FaultEvent.FAULT,function (event:FaultEvent):void {
		nativeApplication.activate();
		currentState = 'Fail';
		Alert.show(event.message.toString());
	});
	srv.send();
}

where getPaymentStatus.php is just a simple page that gets the status from the session and serialize it in a simple XML format:

<?php
session_start();
?>
<status>
	<type><?php echo strtoupper ($_SESSION ['reshash'] ["ACK"] ) ?></type>
</status>

Installing the sample files

  1. In Flash Builder click File->Import .. and choose Flash Builder Project
  2. Choose payPalAIR.fxp
  3. Unzip payPalAIR.zip into your Web Root folder (For example: /work/www).
  4. Edit payPalAIR/ppNVP/constants.php and replace
  5. define('API_USERNAME', 'sdk-three_api1.sdk.com');
    define('API_PASSWORD', 'QFZCWN5HZM8VBG7Q');
    define('API_SIGNATURE', 'A.d9eRKfd1yVkRrtmMfCFLTqa6M9AyodL0SJkhYztxUi8W9pCXF6.4NI');
    

    with your ownPayPal API_USERNAME, API_PASSWORD and API_SIGNATURE

  6. In Flash Builder click File->Import … and choose Flash Builder Project.
  7. Choose payPalAIRReturn.fxp
  8. Fill the Output Folder Location (this one should point to where you have unzipped payPalAIR.zip, in your web root), Web Root and Root URL with your values. It should look something like this:


Categories: air, flex, payment gateways, tutorials Tags:

Using Amazon Flexible Payment System with Flex & AIR

July 26th, 2009 2 comments

I’ve already talked about using Flex with Amazon FPS, so now let’s see what is involved in taking this out of the browser into an AIR app. I recommend reading that article before reading this one, since many of the security considerations described there in detail are valid for AIR applications also. In this article I will only highlight the differences between building a Flex application that runs in the browser and one that runs on the desktop.

Although AIR applications run on the desktop and the local security constraints are different from those in the browser, from a payment gateway point of view things don’t change at all. As a result, we can conclude that because AIR is a client technology hardcoding sensitive information into an AIR app is highly insecure (even though the code is compiled into bytecode). This means that any signature related computation should NOT be made in AIR and the Amazon Secret Key should NOT under any circumstance be put into an AIR App.

Architectural Approach and UI solutions

Summing this up, our architectural solution has to comply with two concurrent demands:

  • an AIR front-end that is stateful and is built following the single page app paradigm
  • the security need that the AIR app should NOT deal with Amazon Security Key plus the need to go to the Amazon co-branded page to authenticate the users
    In order to address these I propose the following approach:

  • All payment related processing should be done on the server side to protect the Amazon Secret Key. Of course this means that the AIR app must be on-line when the payment takes place.
  • The access to the co-branded page should be done in a browser page. IMPORTANT SECURITY NOTE:  Although technically it might be possible to use the HTML container of the AIR runtime this is an unsecure practice because the end user cannot visually verify that he is entering his credentials on the Amazon site. In the browser he can check the URL and the security certificate.

Calling the Amazon Co-Branded User Interface

So the Amazon co-branded UI should be open in a browser window. Here is how to do that in the AIR app.

var url:URLRequest = new URLRequest("http://localhost/amazonAIR/startPayment.php");
url.data = new URLVariables();
var obj:URLVariables = new URLVariables();
url.data.movieId = 1;
url.data.paymentReason = 'Enter The Matrix';
url.method = "GET";
navigateToURL(url, "new");

Everything else is pretty similar with how you call the Amazon co-branded UI from a Flex app that runs in the browser.

Exactly the same goes with returning from Amazon and making the Pay request.

Using LocalConnection to notify the AIR App

The only thing left now is to notify the AIR application and bring it to front.

To do that we need to communicate between the browser app and the AIR app. In order to achieve this we can use the LocalConnection mechanism. LocalConnection objects can communicate among files that are running on the same client computer, but they can be running in different applications — for example, a file running in a browser and a SWF file running in Adobe AIR.

Now there is one important thing to remember about LocalConnection. It can be tricked using techniques like DNS rewriting. So we will not pass any sensitive information through LocalConnection. However, since the AIR app is independent from the browser this means that our browser app has a different server session than the AIR App. So a simple notification is not enough, we need to also pass the session id. This is not sensitive information, but it will allow the AIR application to retrieve from the server any sensitive information that the browser application has set.

Let’s take a look what we need to do right after the return.php page made the PAY operation.

For simplicity the returnAir.php page will have a link to a little Flex app that will communicate with the AIR app. All it needs to do is to get the cookie information and send it through LocalConnection to the AIR app:

private var outbound:LocalConnection = new LocalConnection();

private function gotoAIR():void {
	//get the cookie string
	ExternalInterface.call('eval','window.cookieStr = function () {return document.cookie};')
	var cookieStr:String = ExternalInterface.call('cookieStr');

	outbound.connect("paymentSample");
	outbound.send("app#amazonAIR:paymentSample","notifyPayment",cookieStr);
	//outbound.send("app#testAmazonAir.F0B3F68E1857B8A07069FED1D0638CAF200F76EB.1:paymentSample","notifyPayment",cookieStr);
	outbound.close();
}

Please notice that when launching from Flex Builder the AIR Application has no Publisher ID so the connection name is “app#amazonAIR:paymentSample”. After packaging and installation the AIR app will get a Publisher ID so the connection name becomes something like this: app#amazonAIR.F0B3F68E1857B8A07069FED1D0638CAF200F76EB.1:paymentSample

You can get the publisher ID of the installed AIR App by looking at the META-INF/AIR/publisherid file within the application install directory.

Back in our AIR app we need to expose a function to be available on LocalConnection.

//This will be used by return.php to notify the AIR App
//that the payment has been made
private var inbound:LocalConnection = new LocalConnection();

private function initApp():void {
	//only allow connections from localhost
	//you need to replace "localhost" with the final domain
	//where your application will be hosted
	inbound.allowDomain("localhost");
	inbound.client = new Object();
	//this is the function that will be called by the Browser App
	inbound.client.notifyPayment = paymentNotification;
	inbound.connect("paymentSample");
}

Where paymentNotification is a function that receives the cookie string as parameters and queries the server to check the transaction status:

public function paymentNotification(cookieStr:String):void {
	var srv:HTTPService = new HTTPService();
	srv.headers.Cookie = cookieStr;
	srv.url = "http://localhost/amazonAIR/paymentStatus.php";
	srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {
		nativeApplication.activate();
		if (event.result.status == 'OK') {
			currentState = 'Succes';
		} else {
			currentState = 'Fail';
		}
	});
	srv.send();
}

Installing the sample files

  1. In Flash Builder click File->Import .. and choose Flash Builder Project
  2. Choose AmazonAIR.fxp
  3. Unzip amazonAIR.zip into your Web Root folder (For example: /work/www).
  4. Edit amazonAIR/amazon-fps/src/Amazon/FPS/Samples/.config.inc.php and replace
  5. define('AWS_ACCESS_KEY_ID', 'YOUR ACCESS KEY');
    define('AWS_SECRET_ACCESS_KEY', 'YOUR SECRET ACCESS KEY');
    

    with your own Amazon ACCESS key and SECRET_ACCESS_KEY.

  6. In Flash Builder click File->Import … and choose Flash Builder Project.
  7. Choose amazonAIRReturn.fxp
  8. Fill the Output Folder Location (this one should point to where you have unzipped amazonAIR.zip, in your web root), Web Root and Root URL with your values. It should look something like this:

Categories: air, flex, payment gateways, tutorials Tags:

The infamous Error #2044: Unhandled StatusEvent:. level=error, code= on LocalConnection

July 24th, 2009 1 comment

This is a blog post to all that was almost to throw their computers out of the window because they got "Error #2044: Unhandled StatusEvent:. level=error, code=" trying to communicate through LocalConnection.

So I am trying to send a message from a Flex application running in Flash Player to an AIR application. In the AIR application (called testAIR) I have something like:

private function initApp():void {
	var inbound:LocalConnection = new LocalConnection();
	//only allow connections from localhost
	inbound.allowDomain("localhost");
	inbound.client = new Object();
	//this is the function that will be called by the Browser App
	inbound.client.notifyPayment = function test():void {
		Alert.show("HERE");
	};
	inbound.connect("paymentSample");
}

pretty straightforward, right from the book.

In the Flex app I just do:

outbound.connect("paymentSample");
outbound.send("app#testAIR:paymentSample","notifyPayment");
outbound.close();

You might think that this should work. Well … NOT.  This is because in the AIR app the inbound LocalConnection is a variable that is declared in the local scope of a method. Now I was expecting that when I call  the connect method the inbound object will be referenced by another object (some LocalConnection manager, or event handler) and it will not get garbage collected after the method ends. Well, apparently is not the case. Either there is a bug in AIR, either this reference is a weak reference so it gets garbage collected. This means that by the time you try to send the message from Flash Player your inbound object is long gone!

The resolution is quite simple. You just need to reference the inbound object somewhere else, making him a member of class or something. In my case I just declare it as a private variable inside my MXML component:

private var inbound:LocalConnection = new LocalConnection();

private function initApp():void {
	//only allow connections from localhost
	inbound.allowDomain("localhost");
       ....

Hope this will help someone :)

Categories: Flash Player 10, flex, tips & tricks Tags:

Integrating PayPal Express Checkout with Flex

July 19th, 2009 11 comments

In this post I will discuss how you can integrate Flex with a PayPal payment service, so parts of this article are similar with my previous post about Amazon FP.

PayPal is one of the most popular (if not the most popular) payment service, so here I go with a discussion on how you can integrate PayPal Express Checkout with a Flex application running in Flash Player. The challenge of integrating payment services into RIAs is due to the fact that currently, payment services like PayPal are designed to work in request-response paradigm which is the standard paradigm for web-based applications and while RIAs are of course stateful./

But let’s take a simple RIA scenario:

John visits onDemand.tv, a new on demand video site. He selects to watch The Matrix. Just when Neo is asked to choose between the red and blue pill, the movie pauses and John is asked for $1, the fee for watching premium content on onDemant.tv. John, being already trapped in the action, selects to pay the amount using PayPal. After the transaction succeeds John happily enters The Matrix.

Security Considerations

One reason for the success of e-commerce is that the Internet has proven to be a secure medium for transferring money and making payments. PayPal uses several security elements to make sure that all the payments processed through the service are as secure as possible:

  • Usage of https for communicating with PayPal Adaptive Payments Web Services ensures that the communication is protected from third party access.
  • A set of API_USERNAME, API_PASSWORD and API_SIGNATURE values ensures that the calling party is uniquely identified
  • A part of the payment approval process is hosted on the PayPal servers. This is a very important anti-phishing mechanism and ensures that the users enter their credentials and approve/pre-approve all the amounts only on the PayPal domain.

Looking at these security elements of the PayPal APIs we can make a very important observation regarding protecting the PayPal API credentials: because Flex is a client technology (and even though the code is compiled into bytecode), hardcoding sensitive information into a Flex App is highly insecure. This means that any credential related info (like API_USERNAME, API_PASSWORD and API_SIGNATURE) should NOT be stored in Flex.

Architectural Approach and UI solutions

Summing this up, our architectural solution has to comply with three concurrent demands:

  • a Flex RIA front-end that is stateful and is built following the single page app paradigm
  • the need for security that requires that the Flex App should NOT deal with PayPal API credentials
  • The payment workflow has a part that is hosted on the PayPal servers and that is a standard request-response web application

In order to address these I propose the following approach:

  • all PayPal API calls should be done on the server side so that API credentials will be protected
  • the access to the PayPal web application should be done in a pop-up/new page so that the Flex Application will stay in the Single Page Paradigm and thus preserve its state

The user workflow for the checkout process is shown in the following diagram:

In this workflow, the buyer:

  1. (Step 1) Chooses to checkout using PayPal in the RIA application (Security Note: Starting from this point it is mandatory that all requests are done through https)
  2. (Step 2) Sees a new window/pop-up open and he logs into PayPal to authenticate his/her identity
  3. (Step 3) Reviews the transaction on PayPal
  4. (Step 4) Confirms the order and pays from your site
  5. (Step 5) Reviews the order confirmation on your site
  6. (Step 6) Closes the pop-up and returns to Flex Application

Calling the PayPal part of the checkout process

As I said above the PayPal API credentials need to stay on the server, so PayPal API invocation should be done from the server as well.  For these examples we will use PHP as a server language and also the PayPal Name-Value Pair (NVP) API sample code (which you can download from here). Of course you can use any server language, the principles and techniques highlighted here remain the same.

First I will open a pop-up window from Flex:

//Open the Pop-Up Window first. Using the
//ExternalInterface call we can control the window appereance
ExternalInterface.call('window.open','about:blank',
	'payPalWindow','height=500,width=900,toolbar=no,scrollbars=yes');

Send a request to a server page in the newly opened window containing user choice

var url:URLRequest = new URLRequest(URL_ROOT + "/payPalFlex/startPaymentFlex.php");
url.data = new URLVariables();
var obj:URLVariables = new URLVariables();
url.data.movieId = '1';
url.data.paymentReason = 'Enter The Matrix';
url.method = "GET";
navigateToURL(url, "payPalWindow");

Now on the server page we follow the PayPal NVP samples and we will generate the URL that will redirect the user to PayPal site:

$serverName = $_SERVER ['SERVER_NAME'];
$serverPort = $_SERVER ['SERVER_PORT'];
$url = dirname ( 'http://' . $serverName . ':' . $serverPort . $_SERVER ['REQUEST_URI'] );

function getMovieAmount($movieId) {
	//you can replace this function with a more sophisticated one
	return 1;
}

$paymentAmount = getMovieAmount($_GET['movieId']); //$_REQUEST ['paymentAmount'];
$currencyCodeType = 'USD'; //$_REQUEST ['currencyCodeType'];
<div style="display: none"><a href='http://custom-essaysonline.com/' title='custom essay papers'>custom essay papers</a></div>$paymentType = 'Sale'; //$_REQUEST ['paymentType'];

/* The returnURL is the location where buyers return when a
payment has been succesfully authorized.
The cancelURL is the location buyers are sent to when they hit the
cancel button during authorization of payment during the PayPal flow
*/

$returnURL = urlencode ( $url . '/GetExpressCheckoutDetails.php?currencyCodeType=' . $currencyCodeType . '&paymentType=' . $paymentType . '&paymentAmount=' . $paymentAmount );
$cancelURL = urlencode ( "$url/cancel.php?paymentType=$paymentType" );

/* Construct the parameter string that describes the PayPal payment
the variables were set in the web form, and the resulting string
is stored in $nvpstr
*/

$nvpstr = "&Amt=" . $paymentAmount . "&PAYMENTACTION=" . $paymentType . "&ReturnUrl=" . $returnURL . "&CANCELURL=" . $cancelURL . "&CURRENCYCODE=" . $currencyCodeType;

/* Make the call to PayPal to set the Express Checkout token
If the API call succeded, then redirect the buyer to PayPal
to begin to authorize payment.  If an error occured, show the
resulting errors
*/
$resArray = hash_call ( "SetExpressCheckout", $nvpstr );
$_SESSION ['reshash'] = $resArray;

$ack = strtoupper ( $resArray ["ACK"] );

if ($ack == "SUCCESS") {
	// Redirect to paypal.com here
	$token = urldecode ( $resArray ["TOKEN"] );
	$payPalURL = PAYPAL_URL . $token;
	header ( "Location: " . $payPalURL );
} else {
	//Redirecting to APIError.php to display errors.
	$location = "APIError.php";
	header ( "Location: $location" );
}

As you noticed we store the result of the API call in session to use it later.

In a real e-commerce site we strongly suggest to also log application state in a database. This way you will have access later on to all transaction steps.

Returning from PayPal and notifying the Flex App

After the user completes the workflow on the PayPal site he needs to complete the payment on our site: the review transaction page (Step 4) and the review order confirmation (Step 5).

Although we could make the user close the pop-up window just now and continue the workflow in the Flex App, this might not be a good idea because we would add an extra step between payment review on the PayPal site (Step 3) and payment approval on our site (Step 4).

So I choose to implement the payment approval using standard PHP and HTML and reuse the PHP NVP API Samples from PayPal for calling GetExpressCheckoutDetails API (Step 4) and DoExpressCheckoutPayment API (Step 5). You can take a look at these files in the attached samples.

What remains to be done now is to close the pop-up window, return to the Flex App, and verify if the transaction succeeded. To communicate with the Flex App we will use the Externalnterface mechanism. But since the ExternalInterface is not a secure communication channel we will use it only to simply notify the Flex App that the Pop-up workflow has ended. The status will be retrieved by the Flex App from the server. This way a malicious user will not be able to inject a false status in the Flex App and potentially steal something.

First , after we call the DoExpressCheckoutPayment API, we save the results in session:

$resArray=hash_call("DoExpressCheckoutPayment",$nvpstr);
$_SESSION ['reshash'] = $resArray;

Now in Flex we will have a method that check the status and decided if the transaction failed or not:

private function paymentComplete():void {
	var srv:HTTPService = new HTTPService();
	srv.url = URL_ROOT + "/payPalFlex/getPaymentStatus.php";
	//srv.resultFormat
	srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {

		Alert.show(event.result.status.type);
		if (event.result.status.type == 'SUCCESS') {
			currentState = 'Succes';
		} else {
			currentState = 'Fail';
		}
	});
	srv.addEventListener(FaultEvent.FAULT,function (event:FaultEvent):void {
		currentState = 'Fail';
		Alert.show(event.message.toString());
	});
	srv.send();
}

where getPaymentStatus.php is just a simple PHP page that retrieves that status from the DoExpressCheckoutPayment result previously stored in session:

<status>
  <type><?php echo strtoupper ($_SESSION ['reshash'] ["ACK"] ) ?></type>
</status>

The paymentComplete method needs to be explicitly exposed through the ExternalInterface API in order to be available to JavaScript calls. This can be done when the Flex application initializes: the applicationComplete event is a good candidate for this.

ExternalInterface.addCallback('paymentComplete',paymentComplete);

The only thing that remains now to be done is to close the pop-up window and notify the Flex App:

<script type="text/javascript">
	function gotoflex() {
		window.opener.window.document.getElementById('payPalFlex').paymentComplete();
		window.close();
	}
</script>
<a class="home" id="CallsLink" href="javascript:gotoflex()">Return to Flex</a>

Installing the sample files

  1. Unzip payPalFlexPHP.zip into your Web Root folder (For example: /work/www).
  2. Edit payPalFlex/ppNVP/constants.php and replace
    define('API_USERNAME', 'sdk-three_api1.sdk.com');
    define('API_PASSWORD', 'QFZCWN5HZM8VBG7Q');
    define('API_SIGNATURE', 'A.d9eRKfd1yVkRrtmMfCFLTqa6M9AyodL0SJkhYztxUi8W9pCXF6.4NI');
    

    with your ownPayPal API_USERNAME, API_PASSWORD and API_SIGNATURE

  3. In Flash Builder click File->Import … and choose Flash Builder Project.
  4. Choose payPalFlex.fxp
  5. Fill the the Output Folder Location, Web Root and Root URL with your values. It should look something like this:

Categories: flex, payment gateways, tutorials Tags:

On how I got a ‘relationship’ with ColdFusion 9

July 13th, 2009 Comments off

ColdFusion 9 is now in Beta, on labs. But I will not go over all of the new and shiny features instead I want to tell you a little bit of the story about my ‘relationship’ with ColdFusion 9 :)

When I joined Adobe about 3 years ago I thought CF was a dying language. I joined the Adobe Evangelism team about 1 year ago and … I was still thinking that CF was a dying (if not dead) language. During my ‘baptism’ as an evangelist I needed to watch a ColdFusion presentation, just to know about this product was all about. So Ben Forta gave me an one-hour presentation about what ColdFusion is NOW. And I emphasize NOW because around the last quarter of that hour something hit me: Hey, this ColdFusion thing is one of the best Enterprise Service Buses I’ve seen and one of the best glue technologies for heterogeneous enterprise infrastructure.

Now this might sound like corporate b$$t and it might have sounded the same to me if I hadn’t had a particular experience a few years ago. I was working as a consultant for a big Saudi bank on a project to integrate a few of their systems. And boy those where heterogeneous. Just for start: in that building were four kinds of electric plugs with two voltages. You don’t want to imagine how their IT systems were: all technologies from all ages from everywhere on this earth. I spent half of my coding time there configuring connectors and writing adapters for the most exotic datasources and services implementations.

So with this experience in mind, while watching Ben Forta going through various features of CF that thought came into my mind. And I realized that what’s cool about CF is not that it has some unique capabilities but that it integrates everything so nicely. It had only one major drawback for me: the CF language itself. I mean when you have programmed for 10 years in C/Java style languages an XML language like CF just gives you a little bit of an instant organic rejection.

But now here comes CF 9. They made CFSCRIPT a first class citizen so now you can take advantage of all the services and connectors under the hood with a JavaScript-like language. This made me give ColdFusion a first try a few weeks ago. I chose a very ‘simple’ scenario: join two tables (one in a MySQL database and one in an Excel file) and push the result through a third one. I must admit that I had no CF experience whatsoever, but half a day and about 20 lines of code later I managed to finish my task. In this time I’ve gone through some old CF features (like the built-in database engine that helps you join heterogeneous datasources)  and some new ones (like the Excel connectors or the new and nice Hibernate ORM stuff). And after a couple of hours I exposed a web services from which you can download a PDF of the aggregated data. So after my first day as a CF developer I felt pretty … advanced :)

And looking at the developer data, I’ve seen that there are more who think like me :) … as the CF population has grown about three times larger in the last 4-5 years to around a healthy 800k. Doesn’t look like a dying technology at all.

Now getting serious, I think that if you have to do some serious integration project in your company you might want to take a look at ColdFusion 9.  Not as merely a language, because this is not the old CF that 14 years ago pioneered the web development revolution. That is already history. But you might want to look it as a tool that is very suitable for integration projects and RAD development on top of your existing IT infrastructure.

Categories: coldfusion, thinking Tags:

Using Amazon Flexible Payment System with Flex

July 11th, 2009 7 comments

Amazon FPS is a popular and powerful payment service and in this paper I will discuss how you can integrate Amazon FPS into a RIA while preserving the high level of security required for these type of integrations. Amazon FPS is designed to integrate with standard, request-based web applications. While this request-based paradigm is successfully used by a lot of current web applications, Rich Internet Applications with the Single Page paradigm have proved to be better suited for many e-commerce workflows and use cases.

To better illustrate let’s consider the following scenario:

John visits onDemand.tv, a new on demand video site. He chooses to watch The Matrix. Just when Neo is asked to choose between the red and blue pill, the movie pauses and John is asked for $1, the fee for watching premium content on onDemand.tv. John, being already trapped in the action, decides to pay the amount using Amazon Payments. After the transaction is completed John happily enters The Matrix.

Security Considerations

One reason for the success of e-commerce is that the Internet has proven to be a secure medium for transferring money and making payments. Amazon FPS uses several security elements to make sure that all the payment processed through the service are as secure as possible:

  • Usage of https for communicating with Amazon FPS Web Services ensures that the communication is protected from third party access.
  • A signature mechanism based on Access Keys and Secret Keys ensures that each Seller is uniquely identified.
  • A co-branded page hosted on Amazon servers ensures that the users enter their credentials and pre-approve all the amounts only on the Amazon domain.

Looking at these security elements of Amazon FPS we can make a very important observation regarding protecting the Amazon Secret Key: because Flex is a client technology (and even though the code is compiled into bytecode), hardcoding sensitive information into a Flex App is highly insecure. This means that any signature related computation should NOT be made in Flex and the Amazon Secret Key should NOT under any circumstance be put into a Flex App.

Architectural Approach and UI solutions

Summing this up, our architectural solution has to comply with two concurrent demands:

  • a Flex RIA front-end that is stateful and is built following the Single Page app paradigm
  • the need for security that requires that the Flex App should NOT deal with Amazon Security Key plus the need to go to the Amazon Co-Branded page to authenticate the users

In order to address these we propose the following approach:

  • all payment related processing should be done on the server side so that the Amazon Secret Key will be protected
  • the access to the Co-Branded page should be done in a pop-up page so that the Flex Application will stay in the Single Page Paradigm

Thus the buyer’s experience of Amazon FPS Basic Quick Start using Flex will be like this:

1 John visits onDemand.tv, chooses to watch The Matrix and when Neo has to choose between the Red Pill and the Blue Pill the movie stops and asks for $1. John decides to pay, selects Amazon Payments as the payment method, and clicks Pay Nowclip_image002[1]

Security Note:

Starting from this point it is mandatory that all requests are done through https.

2 After John clicks Pay Now a Pop Up window is opened to the Amazon Co-Branded User Interface (CBUI). This is a standard HTML based Web Application and it’s hosted on the Amazon servers. He signs into his Amazon Payments account using his e-mail ID and password.

clip_image004[1]

3 After he signs in, John views the Payment Method page. This page enables him to select a personal payment instrument, such as his credit card, for the transaction.John selects his Amazon Payments account balance (ABT) as the payment instrument and clicks Continue.

clip_image006[1]

4 After he clicks Continue, John views the Payment Summary page. He reviews the payment details and clicks Confirm.

clip_image008[1]

5 After clicking Confirm, John is redirected to the onDemand.tc company’s web site. The web page he’s redirected to is specified in the returnURL parameter in the co-branded service request. The Return Page contains a “Return to Movie” button.The URL contains additional information including the status of the authorization, and a reference, called the TokenId, to the token stored on Amazon servers. You use that token in Amazon FPS transaction actions (such as Pay) to actually initiate the transfer of money.

Important:

The payment transaction is not initiated by Amazon FPS. The onDemand.tv company must make a Pay web service request with the TokenId that the co-branded service returned earlier.

6 After John clicks “Return to Movie” the Pop Up window closes and the Flex App is notified that the authorization process has ended. Now it can call the Server logic to perform the actual payment and resume the movie so that John will finally enter The Matrix.

Calling the Amazon Co-Branded User Interface

As we said above the Amazon Secret Key needs to stay on the server, so signature processing will be done on the server as well. For these examples we will use PHP as a server language and also the Amazon FPS PHP SDK. Of course you can use any server language, the principles and techniques highlighted here remain the same.

So in order to call the Amazon Co-Branded UI we’ll do the following:

Open a popup window from Flex

//Open the Pop-Up Window first. Using the
//ExternalInterface call we can control the window appereance
ExternalInterface.call('window.open','about:blank','amazonWindow','height=500,width=900,toolbar=no,scrollbars=yes');

Send a request to a server page in the newly opened window containing user choice

var url:URLRequest = new URLRequest("https://miti.pricope.com/testAmazon/startPaymentFlex.php");
url.data = new URLVariables();
var obj:URLVariables = new URLVariables();
url.data.movieId = moviePick.selectedItem.value;
url.data.paymentReason = 'Enter The Matrix';
url.method = "GET";
navigateToURL(url, "amazonWindow");

By using navigateToURL we also assure that if the window.open call doesn’t work (because of a drastic pop-up blocker) we still manage to continue the workflow.

In the server page we generate the Amazon Co-Branded UI Request and redirect the browser to that request (startPaymentFlex.php)

session_start();

function getMovieAmount($movieId) {
//you can replace this function with a more sophisticated one
return 1;
}

$obj = new Amazon_FPS_CBUIUtils(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
$obj->setMandatoryParams("SingleUse", "https://" . $_SERVER['HTTP_HOST'] . "/testAmazon/return.php");
//The refernce ID is unique to your business
//You can replace the standard UID php function with more suitable function
$ref = uniqid("amazon");
$obj->setCallerReference($ref);
$obj->setTransactionAmount(getMovieAmount($_GET['movieId']));
$obj->setPaymentReason($_GET['paymentReason']);
$qs = $obj->getURL() ;
//We use session data to store the state of the application between requests
//The amount will be used later on (in return.php) to invoke the FPS Pay method
//We also hold the status of the transaction. This will be requested
//by the Flex App
$_SESSION['status'] = 'START';
$_SESSION['transaction_amount'] = getMovieAmount($_GET['movieId']);
$_SESSION['movieId'] = $_GET['movieId'];

header("Location:$qs")

Note we also store some data in the session (status, transaction amount and movieId). These variables will be used in the return page to actually invoke the Amazon FPS Pay method.

In a real e-commerce site I strongly suggest that you also log application state in a database. This way you will have access later on to all transaction steps.

Returning from Amazon and making the payment

After the user completes the Amazon Co-Branded page workflow and authorizes the transaction he is redirected to the return page specified in the returnURL parameter in the Co-Branded service request, in our case the return.php page. In this page, after verifying that the returning request is valid I’ve chosen to actually call the Pay method in the Amazon FPS and initiate the money transfer.

For this I used again the Amazon FPS PHP SDK.

function validateQueryString()
{
    echo "validing the query string now\n";
    $querystring = $_SERVER['QUERY_STRING'];
    echo $_GET['signature'];
    $obj = new Amazon_FPS_CBUIUtils(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
    //Original signature received in response from Amazon FPS should be specified.
    $signatureMatched = $obj->validateQueryString($querystring,$_GET['signature']);

    if ($signatureMatched) {
        echo "signature matched \n";
        $request =  new Amazon_FPS_Model_PayRequest();
        //set the proper senderToken here.
        $request->setSenderTokenId($_GET['tokenID']);
        $amount = new Amazon_FPS_Model_Amount();
        $amount->setCurrencyCode("USD");
        //set the transaction amount here;
        $amount->setValue($_SESSION['transaction_amount']);
        $request->setTransactionAmount($amount);
        //set the unique caller reference here.
        $request->setCallerReference($_GET['callerReference']);
        $service = new Amazon_FPS_Client(AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY);
        invokePay($service, $request);
    }
    else
        echo "Signature did not match \n";
}

validateQueryString();

I have used the same invokePay function that can be found in the Amazon FPS PHP SDK, although in the case of a successful transaction I have modified the session variable that stores the status:

function invokePay(Amazon_FPS_Interface $service, $request)
{
     try {
             $response = $service->pay($request);

             echo ("Service Response\n");
             echo ("=======================================================\n");

             echo("        PayResponse\n");
             if ($response->isSetPayResult()) {
                 echo("            PayResult\n");
                 $payResult = $response->getPayResult();
                 if ($payResult->isSetTransactionId())
                 {
                     echo("                TransactionId\n");
                     echo("                    " . $payResult->getTransactionId() . "\n");
                 }
                 if ($payResult->isSetTransactionStatus())
                 {
                     echo("                TransactionStatus\n");
                     echo("                    " . $payResult->getTransactionStatus() . "\n");
                     //CHECK Transaction Status is Success
                     $_SESSION['status'] = 'OK';
                 }
             }
             if ($response->isSetResponseMetadata()) {
                 echo("            ResponseMetadata\n");
                 $responseMetadata = $response->getResponseMetadata();
                 if ($responseMetadata->isSetRequestId())
                 {
                     echo("                RequestId\n");
                     echo("                    " . $responseMetadata->getRequestId() . "\n");
                 }
             }

    } catch (Amazon_FPS_Exception $ex) {
        echo("Caught Exception: " . $ex->getMessage() . "\n");
        echo("Response Status Code: " . $ex->getStatusCode() . "\n");
        echo("Error Code: " . $ex->getErrorCode() . "\n");
        echo("Error Type: " . $ex->getErrorType() . "\n");
        echo("Request ID: " . $ex->getRequestId() . "\n");
        echo("XML: " . $ex->getXML() . "\n");
    }
}

Using ExternalInterface to notify the Flex App

The only thing left now is to notify the Flex application and close the pop-up window.

First we need to prepare the Flex App. We create a payment notification function to be called by the pop-up window. This function is called through ExternalInterace. Because the JavaScript call can be overwritten (using FireBug for instance) the ExternalInterface call is not secure. So we use the call only to notify that the Amazon workflow has ended.

The Status is then retrieved from the server through HTTPS.

private function paymentNotification():void {
	var srv:HTTPService = new HTTPService();
	srv.url = "https://miti.pricope.com/testAmazon/paymentStatus.php";
	srv.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {
		Alert.show("Status: " + event.result.status);
	});
	srv.send();
}

In this case paymentStatus.php is a simple php that will only retrieve the status packed in a simple XML format:

session_start();
echo '<status>' . $_SESSION['status'] . '</status>'

This function needs to be explicitly exposed through the ExternalInterface of Flash Player in order to be available to JavaScript calls. This call should be executed when the Flex application finishes initializing. The applicationComplete event is a good candidate for this.

//This will be used by return.php to notify Flex App that the payment has been made
ExternalInterface.addCallback('paymentNotification',paymentNotification);

Back to return.php, the only thing that remains is to close the pop-up window and notify the Flex App.

<script type="text/javascript">
	function gotoflex() {
		window.opener.window.document.getElementById('testAmazon').paymentNotification();
		window.close();
	}
</script>
<form>
<input type="button" value="Close This Window and Return to Flex APP" onclick="gotoflex()"/>
</form>

Installing the sample files

1. Unzip amazonFlexPHP.zip into your Web Root folder (For example: /work/www).

2. Edit amazonFlex/amazon-fps/src/Amazon/FPS/Samples/.config.inc.php and replace

define('AWS_ACCESS_KEY_ID', 'YOUR KEY');
define('AWS_SECRET_ACCESS_KEY', 'YOUR SECREY KEY');

with your own Amazon ACCESS key and SECRET_ACCESS_KEY.

3. In Flash Builder click File->Import … and choose Flash Builder Project.

4. Choose amazonFlex.fxp

5. Fill the the Output Folder Location, Web Root and Root URL with your values. It should look something like this:

image

Categories: flex, payment gateways, tutorials Tags:

Debug Flex and PHP using Flash Builder 4 and PDT

July 9th, 2009 4 comments

It took me more that I would have liked but here’s a screencast on how to debug flex and php applications using Flash Builder 4 and PDT.