In my last post I used some bare-bones PHP code to explain how the Windows Azure AppFabric access control service works. Here, I’ll build on the ideas in that post to explain how to use some of the access control functionality that is available in the AppFabric SDK for PHP Developers. I will again build a barpatron.php client (i.e. a customer) that requests a token from the AppFabric access control service (ACS) (the bouncer). Upon receipt of a token, the client will present it to the bartender.php service (the bartender) to attempt to access a protected resource (drinks). If the service can successfully validate the token, the protected resource will be made available.

0. Set up ACS

In this post, I’ll assume that you have a Windows Azure subscription, that you have set up an access control service, and that you have created a token policy and scope as outlined in the “Hiring a Bartender (i.e. Setting Up ACS)” section of my last post. I’ll also assume you are familiar with the bouncer-bartender analogy I used in that post.

 

1. Install the AppFabric SDK for PHP Developers

You can download the AppFabric SDK for PHP developers from CodePlex here: http://dotnetservicesphp.codeplex.com/. After you have downloaded and extracted the files, update the include_path in your php.ini file to include the library directory of the downloaded package.

Note: I found what I think are a couple of bugs in the SDK. Here are the changes I had to make to get it working for me:

  1. Replace POST_METHOD with "POST" on line 113 of the SimpleApiAuthService.php file. Or, define the POST_METHOD constant as "POST".
  2. Add the following require_once directive to the SimpleApiAuthService.php file: require_once "util\curlRequest.php";

2. Enable the bartender.php service to verify tokens

When presented with a token, a service needs 3 pieces of information to validate it:

  1. The service namespace (which you created when you set up ACS).
  2. The signing key that is shared with ACS (this is the key associated with the token policy you created).
  3. The audience (which is the value of the appliesto parameter you used when creating a scope for the token policy).

As I examined in my last post, this information will be used to make comparisons with information that is presented in the token. Nicely, the AppFabric SDK for PHP Developers has a TokenValidator class that handles all of this comparison work for us – all we have to do is pass it the token and the 3 pieces of information above. So now my bartender.php service looks much cleaner than it did in my previous post (note that I’m assuming the token is passed to the service in an Authorization header):

require_once "ACS\TokenValidator.php";

define("SIGNING_KEY", "The_signing_key_for_your_token_policy");
define("SERVICE_NAMESPACE", "Your_service_namespace");
define("APPLIES_TO", "
http://localhost/bartender.php");

// Check for presence of Authorization header
if(!isset($_SERVER['HTTP_AUTHORIZATION']))
    Unauthorized("No authorization header.");
$token = $_SERVER['HTTP_AUTHORIZATION'];

// Validate token
try
{
    $tokenValidator = new TokenValidator(SERVICE_NAMESPACE,
                                         APPLIES_TO,
                                         SIGNING_KEY,
                                         $token);
    if($tokenValidator-> validate())
        echo "What would you like to drink?";
    else
        Unauthorized("Token validation failed.");
}
catch(Exception $e)
{
    throw($e);
}

function Unauthorized($reason)
{
    echo $reason." No drink for you!<br/>";
    die();
}
 

Note: The TokenValidator class does not expect the $token parameter to be in the same format as is issued by ACS. Instead, it expects a string prefixed by "WRAP access_token=" with the body of the token enclosed in double quotes. The following is an example of a token in the format expected by the TokenValidator class: WRAP access_token="Birthdate%3d1-1-70%26Issuer%3dhttps%253a%252f%252fbouncernamespace.accesscontrol.windows.net%252f%26Audience%3dhttp%253a%252f%252flocalhost%252fbartender.php%26ExpiresOn%3d1283981128%26HMACSHA256%3dzBux1nj9yPAMrqNqhmk%252fYvzyc75b3vK%252fqYp8K6DTah4%253d"

 

3. Enable the barpatron.php client to request a token

When requesting a token from ACS, a client needs 4 pieces of information:

  1. The service namespace (which you created when you set up ACS).
  2. The issuer name (which you set when creating an Issuer during ACS setup).
  3. The issuer secret key (this was generated when you created an Issuer during ACS setup).
  4. The audience (which is the value of the appliesto parameter you used when creating a scope for the token policy).

As with token validation, the AppFabric SDK for PHP makes creating the request, sending it, and retrieving the token very easy:

require_once "DotNetServicesEnvironment.php";
require_once "ACS\Scope.php";
require_once "ACS\SimpleApiAuthService.php";

define("SERVICE_NAMESPACE", "Your_service_namespace");
define("ISSUER_NAME", "Your_issuer_name");
define("ISSUER_SECRET", "The_key_associated_with_your_issuer");
define("APPLIES_TO", "
http://localhost/bartender.php");

try
{   
    //$acmHostName is accesscontrol.windows.net by default         
    $acmHostName = DotNetServicesEnvironment::getACMHostName();
    $serviceName = SERVICE_NAMESPACE;
    $scope = new Scope("simpleAPIAuth");

    $scope->setIssuerName(ISSUER_NAME);
    $scope->setIssuerSecret(ISSUER_SECRET);
    $scope->setAppliesTo(APPLIES_TO);
    $scope->addCustomInputClaim("DOB", "1-1-70");

    $simpleApiAuthService = new SimpleApiAuthService($acmHostName, $serviceName);
    $simpleApiAuthService->setScope($scope);
    $token = $simpleApiAuthService->getACSToken();

}   
catch(Exception $e)
{
    throw($e);
}

Now to send the token, we re-format it (see note about the TokenValidator class in the section above) and put it in an Authorization header (where the bartender.php service will expect it):

$token = 'WRAP access_token="'.$token.'"';

// Initialize cURL session for presenting token.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "
http://localhost/bartender.php");
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: ".urldecode($token)));
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,  true);

$bartenderResponse = curl_exec($ch);
curl_close($ch);

$responseParts = explode("\n", $bartenderResponse);
echo $responseParts[count($responseParts)-1];

That’s it! The bartender.php and barpatron.php files are attached to this post in case you want to play with the service. You should be able to modify the files (updated with your AppFabric service information) and then load the barpatron.php file in your browser.

Thanks.

-Brian

Share this on Twitter