"The human factor is truly security's weakest link" Kevin D. Mitnick

ZendService_Api, a micro HTTP framework to consume generic API calls in PHP

Posted: May 10th, 2013 | Author: | Filed under: API, PHP, Zend Framework | Tags: , , | No Comments »

How many times did you write code to perform HTTP calls for an API service? This can be a tedious and repetitive task that can take some time. You need to prepare the HTTP call, check the response code to understand if the call was successfull, extract some information from the Header, format the output and so on.

Some months ago I started to implement the ZF2 component for the new API of OpenStack and I decided to build a class to reduce the amount of code needed for the invocations of HTTP calls, and I wrote the ZendService_Api.

This component can be considered a “micro framework” because the aim is to create a lightweight and complete solution to manage API calls, from a prospective of a PHP client. It uses the Zend\Http component of Zend Framework 2.

Basically, the ZendService_Api component is able to prepare the HTTP call (mapping PHP parameters), to execute the HTTP call (using a Zend\Http\Client object), and to convert the HTTP output according to a specific format (JSON, XML or simple text). Moreover, the component is able to manage HTTP status code and assign it as error or successfull operations, according to the API specification.

Installation

You can easly install ZendService_Api component using composer. You need to add the following to your composer.json to enable the ZF2 repository:

"repositories": [
    {
        "type": "composer",
        "url": "https://packages.zendframework.com/"
    }
],

You can then add the ZendService_Api packages to your require list. For example:

"require": {
    "zendframework/zendservice-api": "dev-master"
},

The ZendService_Api package is still in development, you need to use the “dev-master” release.
After that, you can run the install command to resolve and download the dependencies:

$ php composer.phar install

Usage

During the development of ZendService_Api component, I tried to simplify the API with a class containing only few methods and simple parameters. I mapped the HTTP calls using the __call magic function of PHP. In this way an API call is managed with a single function (e.g. $api->listUsers(); will execute the listUser HTTP call of an API service). The specification of the HTTP call is provided using a closure or an external PHP file that returns the configuration (using a simple array). You can configure the HTTP call with the following parameters:

  • URL;
  • Headers;
  • Body;
  • Method (GET,POST,PUT,DELETE);
  • HTTP status codes for the successfully operations;
  • format of the output: JSON, XML or nothing (simple text).

You can set the API parameters using the setApi method. This method accepts two parameters: the name of the API and a closure (callback) that returns the configuration with a PHP array.

Let see an example, image you need to consume an authentication API call with a POST HTTP request using a JSON data format with the following parameters: username and password. The HTTP request can be represented as follow:

PUT /v1/auth HTTP/1.1
Host: localhost
Connection: close
Content-Type: application/json
Content-Length: 57
 
{ 'auth' : { 'username' : 'admin', 'password' : 'test' }}

A valid response will be a 200 HTTP code with a JSON representation of the authentication token.
You can to configure the API call using the setApi method in this way (I used the auth name for this API):

use ZendService\Api\Api;
 
$api = new Api();
$api->setApi('auth', function ($params) {
    return array(
        'uri' => 'http://localhost/v1/auth',
        'header' => array(
            'Content-Type' => 'application/json'
        ),
        'method' => 'POST',
        'body' => json_encode(array(
            'auth' => array(
                'username' => $params[0],
                'password' => $params[1]
            )
        )),
        'response' => array(
            'format' => 'json',
            'valid_codes' => array('200')
        )
    );
});

After that you can execute the API call using the function auth (this function is managed by the magic __call function of PHP):

$result = $api->auth('username', 'password');
if ($api->isSuccess()) {
    if (isset($result['token'])) {
        printf("The authentication token is %s\n", $result['token']);
    } else {
        var_dump($result);
    }
} else {
    printf("Error (%d): %s\n", $api->getStatusCode(), $api->getErrorMsg());
}

The mapping with the auth arguments and the API specification is managed using the array $params. You have to use the numerical index of the $params to match the order of the arguments in the function. Using the configuration array you can specify all the HTTP data for the API request (headers, body, uri, etc). You can also specify the HTTP status code for the successful requests using the valid_codes parameter in the response section. The format of the HTTP body response is specified by the key ['response']['format']. If you specify the response format the result will be an array.

You can also use a configuration file for the API calls instead of using the setApi method. You need to create a PHP file with the same name of the API call. This file contains the API configuration array. For instance, for the previous example you have to create a auth.php file containing the following array:

return array(
    'uri' => 'http://localhost/v1/auth',
    'header' => array(
        'Content-Type' => 'application/json'
    ),
    'method' => 'POST',
    'body' => json_encode(array(
        'auth' => array(
            'username' => $params[0],
            'password' => $params[1]
        )
    )),
    'response' => array(
        'format' => 'json',
        'valid_codes' => array('200')
    )
);

You need to set the directory containing this configuration file using the setApiPath as follow:

use ZendService\Api\Api;
 
$api = new Api();
$api->setApiPath('path/to/api/config');
$result = $api->auth('username', 'password');
if ($api->isSuccess()) {
    if (isset($result['token'])) {
        printf("The authentication token is %s\n", $result['token']);
    } else {
        var_dump($result);
    }
} else {
    printf("Error (%d): %s\n", $api->getStatusCode(), $api->getErrorMsg());
}

If you need to call different API from the same base URL you can use the setUrl function. This function set the base URL and you can use relative URI for the specific API calls, for instance imagine you need to consume the authentication API v.2.0 of OpenStack according to the specification reported here.
We can set the following configuration, using the main address as base URL and use relative address for each API call.

use ZendService\Api\Api;
 
$api = new Api();
$api->setUri('http://identity.api.openstack.org');
$api->setApi('authentication', function ($params) {
    return array(
        'url' => '/v2.0/tokens',
        'header' => array(
            'Content-Type' => 'application/json'
        ),
        'method' => 'POST',
        'body' => json_encode(array(
            'auth' => array(
                'passwordCredentials' => array(
                    'username' => $params[0],
                    'password' => $params[1]
                )
            )
        )),
        'response' => array(
            'format' => 'json',
            'valid_codes' => array('200', '203')
        )
    );
});
$result = $api->authentication('username', 'password');
if ($api->isSuccess()) {
    printf("Authentication token: %s\n", $result['access']['token']['id']);
} else {
    printf("Error (%d): %s\n", $api->getStatusCode(), $api->getErrorMsg());
}

Note the usage of the relative address in the url parameter of the API configuration.

If you need to pass a query string for an API HTTP call you can use the setQueryParams method of the Api class. For instance, imagine you need to pass the HTTP query string ?auth=strong in the previous example, you can use the following code:

use ZendService\Api\Api;
 
$api = new Api();
$api->setQueryParams(array( 'auth' => 'strong' ));
$result = $api->authenticate('username', 'password');
if ($api->isSuccess()) {
    printf("OK!\n");
} else {
    printf("Error (%d): %s\n", $api->getStatusCode(), $api->getErrorMsg());
}

You can reset the query string calling the setQueryParams() function without a parameter.

You can specify a default HTTP headers to be used for all the HTTP calls. For instance, if you need to call a vendor API passing an authentication token using a special header field you can use this feature to set a default headers to be used for all the next API calls.

To set a default headers you can use the setHeaders function, below is reported an example:

use ZendService\Api\Api;
 
$api = new Api();
$api->setApiPath('path/to/api/config');
$api->setHeaders(array( 'X-Auth-Token' => 'token' ));
$result = $api->test('foo');
if ($api->isSuccess()) {
    var_dump($result);
} else {
    printf("Error (%d): %s\n", $api->getStatusCode(), $api->getErrorMsg());
}

The test API will execute a HTTP request using the headers specified in the test.php configuration file plus the X-Auth-Token header. Basically, the headers specified in the configuration file are merged with the default one specified using the setHeaders function. You can overwrite the default headers using the same header key in the configuration file.

Conclusion

I hope that the ZendService_Api component can help PHP developers to consume HTTP API calls and to write PHP libraries for API vendors with a minimum effort. I’m using this class in some ZendService components of the Zend Framework 2 project and I can say that I have drastically reduced the development time of these libraries.

The actual implementation of ZendService_Api is a working progress version, so if you want to contribute to the development or just give some comments or feedbacks you are more than welcome. To contribute use the official github repository of the component that is https://github.com/zendframework/ZendService_Api.


ZF 2.1.0, new security features and more

Posted: January 31st, 2013 | Author: | Filed under: Cryptography, PHP, Zend Framework | Tags: , , , , | No Comments »

Yesterday we released the 2.1.0 (and 2.0.7) version of Zend Framework. I’m excited about this release because we introduced new features and we fixed more than 150 bugs. Some of the new features includes:

  • new Zend\Permissions\Rbac component, that offer a new approach to build an authorization schema, more oriented to roles and their permissions rather than objects (resources as in Zend\Permission\Acl);
  • new Zend\Test component, providing the ability to perform functional or integration testing;
  • new Zend\Crypt\Password\Apache component to encrypt/decrypt password in Apache format (htpasswd);
  • Apache password adapter for Zend\Authentication, based on the new component Zend\Crypt\Password\Apache;
  • scrypt algorithm support provided by Zend\Crypt\Key\Derivation\Scrypt
  • new Oracle and IBM DB2 adapters for Zend\Db;
  • new FirePHP, ChromePHP, MongoDB, and FingersCrossed adapters for Zend\Log;
  • new MongoDB adapter for Zend\Session

Here the official release announcment.

This new release of Zend Framework contains interesting new features related to security and cryptography. I mentioned the new Zend\Permission\Rbac component that can facilitate the implementation of a classic authorization system. Below I reported a simple use case:

use Zend\Permissions\Rbac\Rbac;
use Zend\Permissions\Rbac\Role;
 
$rbac = new Rbac();
$foo  = new Role('foo');
$foo->addPermission('bar');
 
var_dump($foo->hasPermission('bar')); // true
 
$rbac->addRole($foo);
$rbac->isGranted('foo', 'bar'); // true
$rbac->isGranted('foo', 'baz'); // false
 
$rbac->getRole('foo')->addPermission('baz');
$rbac->isGranted('foo', 'baz'); // true

I’m sure this component will simplify most of the existing use cases of web applications where tipically we have users, roles and permissions.

Regarding the new cryptographic features, we implemented the scrypt algorithm and, as far I know, this is the first open source implementation of scrypt in pure PHP (we also supported the PHP scrypt module provided by Dominic Black).
The scrypt algorithm provides the most secure way, so far, to generate a key from a user’s password. It uses a new idea to prevent brute force attacks consuming CPU time and high memory space (Sequential Memory-Hard Functions). This algorithm has been proposed as Internet Draft on 2012-09-17 by the IETF. The usage of the Zend\Crypt\Key\Derivation\Scrypt component is very simple, here an example:

use Zend\Crypt\Key\Derivation\Scrypt;
use Zend\Math\Rand;
 
$pass = 'password';
$salt = Rand::getBytes(strlen($pass), true);
$key  = Scrypt::calc($pass, $salt, 2048, 2, 1, 64);
 
printf ("Original password: %s\n", $pass);
printf ("Derived key (hex): %s\n", bin2hex($key));

In this example, the parameters of Scrypt::calc are: $pass the input password, $salt the salt of the algorithm, 2048 is the CPU cost, 2 is the memory cost, 1 is the paralization cost and 64 is the length of the output hash to be generated.
More information on the scrypt implementation of ZF2 can be found here.

In ZF 2.1.0 we also released a new component Zend\Crypt\Password\Apache. This component supports all the Apache password formats (htpasswd).
The password formats supported by Apache are reported here. We can use this component to generate or verify a user’s password using a simple API, here an example:

use Zend\Crypt\Password\Apache;
 
$apache   = new Apache();
$password = 'password';
 
$formats = array('crypt', 'sha1', 'md5', 'digest');
foreach ($formats as $format) {
    $apache->setFormat($format);
    if ($format === 'digest') {
        $apache->setUserName('enrico');
        $apache->setAuthName('test');
    }
    $hash = $apache->create($password);
    $result = $apache->verify($password, $hash) ? 'OK' : 'FAILED';
    printf ("%s output: %s (%s)\n", $format, $hash, $result);
}

A possible output for that script is as follow:

crypt output: hHbcSkUv7q7kI (OK)
sha1 output: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g= (OK)
md5 output: $apr1$3HKJdb5X$VNpmjgqNEKQ5S4JXlI8pW/ (OK)
digest output: 7f14e93e793186c46fc3e078cd777da9 (OK)

We used the Apache password component to implement a new adapter for Zend\Authentication. It’s the ApacheResolver that can be found under the namespace Zend\Authentication\Adapter\Http. Using this component we can easly provide user’s authentication using the password file produced by Apache (e.g. using the htpasswd command).

As you can see the number of functionalities of Zend Framework 2 is growing very fast and the security components too. We are exiting to offer such set of security features to the PHP community. If you want to have more information about all the security aspects covered by ZF2 I suggest to watch the recorded video of my webinar “Building Secure Web Applications with ZF2″.


ZFTool, a command line tool for ZF2

Posted: January 18th, 2013 | Author: | Filed under: PHP, Zend Framework | No Comments »

ZFTool is a command line tool to manage applications written in Zend Framework 2. This tool is still in development and we just released an early version that you can start to use. With this version of the tool you can:

  • create a ZF2 project, installing a skeleton application;
  • create a new module inside an existing application;
  • get the list of all the modules installed inside an application;
  • get the configuration file of a ZF2 application;
  • install the ZF2 library choosing a specific version.

You can install ZFTool using composer or github. Moreover, we compiled it in a PHAR file. You can download the zftool.phar from this address https://packages.zendframework.com/zftool.phar. If you want to use the zftool.phar I suggest to add it in your PATH environment. In this way you can execute the zftool.phar script wherever you are.

To install using composer you have to execute the following command in a shell environment:

$ composer require zendframework/zftool:dev-master

You can also install manually using github, following the next steps:

  1. clone using “git clone https://github.com/zendframework/ZFTool.git” or download zipball;
  2. extract to “vendor/ZFTool” in your ZF2 application;
  3. edit your “config/application.config.php” and add “ZFTool” to modules array key.

After the installation you can execute the zf.php file inside the root folder of ZFTool or you can use the zftool.phar (if you have installed ZFTool using composer or github you need to compile the zftool.phar executing the script “bin/create-phar”).

Create a new ZF2 project

You can create a new ZF2 project using the following command:

$ zf.php create project <path>
// or
$ zftool.phar create project <path>

This command will install the Zend Skeleton Application inside the specified path.

Create a new module

Imagine that you want to create a new module “Test” on a local ZF2 application, you can execute the following command:

$ zf.php create module Test
// or
$ zftool.phar create module Test

If you want to create a new module inside an application installed in a different path, you can add the path as last parameter:

$ zf.php create module Test <path>
// or
$ zftool.phar create module Test <path>

Get the list of installed modules

You can get the list of all the modules installed in a ZF2 project using the following command:

$ zf.php modules<path>
// or
$ zftool.phar modules<path>

This command must be executed from the root folder of a ZF2 application.

Get the configuration file of a ZF2 application

You can read the configuration file (application.config.php) of a ZF2 application using the command:

$ zf.php config<path>
// or
$ zftool.phar config<path>

The output configuration is reported using the print_r function of PHP.

Install the ZF2 library

Using ZFTool you can install the Zend Fraemework 2 library choosing a specific version.
For instance, you can install the latest version of ZF in a specific path using the following command:

$ zf.php install zf <path>
// or
$ zftool.phar install zf <path>

If you want to install a specific version, you need to specify the version as last parameter.
For instance, you can install the 2.0.4 version of ZF using the following command:

$ zf.php install zf <path> 2.0.4
// or
$ zftool.phar install zf <path> 2.0.4

Basically, you can install all the tag version specified in the ZF2 github repository
(the name used for the version is obtained removing the “release-” string from the tag name; for instance, the tag “release-2.0.0″ is equivalent to the version number “2.0.0″).

Compile the zftool.phar

You can compile the zftool.phar file executing the following command:

$ bin/create-phar

This command will compile the ZFTool project in the zftool.phar file under the bin folder.

For more information about ZFTool you can read the README.md in github.