Logaholic.de

Avatar

web development

How to add transparent SoapHeader authentication as decorator to any existing service class

This should not be limited to it, but I’d like to show how I implemented this inside the Zend Framework and its Zend_Soap_* components.

SoapHeader authentication is a widely used method to secure access to soap Webservices where the credentials are in the request header.

Activating this type of authentication is for me down to a change from this:

$soap = new Zend_Soap_Server($uri.'&wsdl', $serverOptions);
$soap->setClass('My_Service_'.$serviceName);

to this:

$soap = new Zend_Soap_Server($uri.'&wsdl', $serverOptions);
$soap->setClass('My_Soap_Decorator_Secure', 'My_Service_'.$serviceName);

This is the basic decorator code:

/**
 * This class decorates Soap service classes, provides and enforces authentication via soap header 'authenticate'
 *
 * @author Karsten Deubert <karsten@deubert.net>
 */
class My_Soap_Decorator_Secure
{
    /**
     * @var bool
     */
    protected $_authenticationHeaderPresent = false;

    /**
     * @var mixed
     */
    protected $_authenticatedUser = null;

    /**
     * @var mixed
     */
    protected $_serviceClass = null;

    public function __construct($class)
    {
        if (!class_exists($class))
        {
            throw new Exception('invalid class: '.$class);
        }
        $this->_serviceClass = new $class();
    }

    /**
     * @param mixed $data
     * @return void
     */
    public function authenticate($data)
    {
        $this->_authenticationHeaderPresent = true;

        // authentication code which checks if credentials are valid

        $this->_authenticatedUser = $yourAuthenticatedUser;
    }

    public function __call($name, $arguments)
    {
        if (!$this->isAuthenticationHeaderPresent() || is_null($this->_authenticatedUser))
        {
            throw new Exception('authentication failed');
        }
        if (!is_callable(array($this->_serviceClass, $name)))
        {
            throw new Exception('invalid service class method');
        }

        return call_user_func_array(array($this->_serviceClass, $name), $arguments);
    }
}

The usual soap request with authentication header should now look like this:

$authData = new stdClass();
$authData->user = 'foo';
$authData->secret = 'bar';

$authHeader = new SoapHeader($namespace, 'authenticate', $authData);

$soapClient = new SoapClient('http://foo.bar/asdf?wsdl',
    array(
        'cache_wsdl' => 0,
        'soap_version' => SOAP_1_1
    )
);
$soapClient->__setSoapHeaders(array($authHeader));
$soapClient->fooMethod();

With this header the soap server will first execute the authenticate method from the decorator, then (if successful) pass the method call via magic __call to the inner service class and its fooMethod() in this example.

Voila, transparent SoapHeader authentication separated from your service classes ;)

What I haven’t researched fully yet is if there is a way to specify the authenticate header in the WSDL – every comment appreciated.

Zend Studio 7 and Zend Framework 1.9.0 released

Zend Studio 7.0 brings a host of new features and enhancements that will help you develop faster, resolve defects more quickly, and take advantage of the latest PHP technologies directly from your development environment.

With full support for PHP 5.3, greatly enhanced source code editing, easy debugging through  integration with Zend Server, code generation through integration with Zend Framework, and improved performance, Zend Studio maintains its position as the leading solution for professional PHP developers.

Zend Studio

New features in Zend Framework 1.9:

  • Complete support for PHP 5.3 as well as 5.2 means developers can use the latest PHP language features in their Zend Framework-based apps
  • RESTful web services: now made easier through automated routing/detection
  • Message queues: useful for offload processing (credit card transactions, media uploads), cross-platform communication, user messaging features, and more.
  • LDAP: Microsoft ActiveDirectory & Novell, plus searching, filtering, and tree features
  • RSS & Atom: consume these popular feed formats using a common API and higher performance cached HTTP
  • DBUnit support: DBUnit’s test data setup and teardown make unit testing Zend Framework applications much easier

Zend Framework 1.9 Features PHP 5.3 Readiness and New Professional Components

Downloads are running, Testsuites will show if ZF 1.9 breaks anything, and I will take the opportunity to fix some plugin issues with Zend Studio while upgrading ;)

Zend Framework 1.8.0 released

“I’m pleased to announce the Zend Framework 1.8.0 release, the first in our 1.8 series of releases. This release marks the culmination of several long-standing projects, as well as a formalization of many of our recommended practices. There are two major stories in this release: first, the addition of several components designed to provide and promote Rapid Application Development; second, two offerings that make using Zend Framework in the cloud easier.” [1]

Some thoughts, in no particular order:

If you know Amazon S3 (Amazon Simple Storage Soluation, a web-service for storing and receiving files, scalable, fast, safe) then you should have a look at Zend_Service_Amazon_S3. The Zend Framework not only offers a nice object oriented implementation, but also provides a PHP Stream Wrapper. Why is this so nice? Because one could add Amazon S3 support to existing applications by simply prefixing any standard file-operation with ’s3://’. This is the code sample from the documentation:

<?php
require_once 'Zend/Service/Amazon/S3.php';

$s3 = new Zend_Service_Amazon_S3($my_aws_key, $my_aws_secret_key);

$s3->registerStreamWrapper("s3");

mkdir("s3://my-own-bucket");
file_put_contents("s3://my-own-bucket/testdata", "mydata");

echo file_get_contents("s3://my-own-bucket/testdata");

Support for Amazon EC2 (Amazon Elastic Comput Cloud) has also been added (Zend_Service_Amazon_Ec2).

“Amazon EC2 provides a web service to allow launching and managing server instances within Amazon’s data centers. These server instances may be used at any time for any length of time — allowing you to scale your site only when you need to handle extra traffic, or run your services entirely from the EC2 platform.” [1]

Zend Framework jumped the train for “the” cli interface to the framework via Zend_Tool. One could create whole projects, models, controllers, views with it. This makes sense for starters imho. My full featured Zend Studio for Eclipse with customized code templates does this job way better for me. One thing i miss (Agavi has it! ^^) is a phpunit interface and some configuration which tests should be run. In my opinion, just the existance of such an option would encourage more users to think about/actually use unit tests.

Routing now supports translation aware routes, and route chaining capabilites. Those are fetures i know and love from Agavi.

There are loads of other new features (see [1]), which I haven’t checked yet – sometimes simply because they didn’t interest me.

I’m curious if switching our main project on monday to ZF 1.8.0 will break any test ^^.

Sources:
[1] Zend Developer Zone: Zend Framework 1.8.0 Released

Agavi vs Zend Framework Part 1 – Forms

Agavi and Zend Framework are two major MVC PHP5 Frameworks today. I am actively using both in two different projects.

I will discuss some differences, starting with Part 1 now: Forms.

Forms are used in nearly any web application where you expect user-input. Following the “never trust your users” rule, proper validation is one major (security-) subtopic of forms.

1. Building simple Forms:

Zend Framework:

a) define your Zend_Form object, once, including validation

    /**
     * @return Zend_Form
     */
    protected function getDemoForm()
    {
        $form = new Zend_Form();

        $form->addElement('textarea', 'comment', array(
            'label' => 'comment:',
            'required' => true,
            'validators' => array(
                array('StringLength', array(160), array(1))
            )
        ));
        $form->addElement('submit', 'submit', array(
            'label' => 'submit',
        ));

        return $form;
    }

b) trigger validation in your action, use the result if validation succeeds

$demoForm = $this->getDemoForm();
$request = $this->getRequest();

if ($request->isPost())
{
    if ($demoForm>isValid($request->getPost()))
    {
        doSomeStuff();
        redirectToSuccessAction();
    }
}

c) pass the form object to your view

$this->view->demoForm = $demoForm;

Agavi:

a) write html code for your form in your view

You know how that works. (Or see the Agavi documentation link below)

b) add validation to your write-action

The Agavi documentation prefers defining validators in a .xml file, per action, app/modules/Posts/validate/Add.xml:  (module Post, Action Add)

<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations
  xmlns="http://agavi.org/agavi/config/parts/validators/1.0"
  xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0"
  parent="%core.module_dir%/Posts/config/validators.xml"
>
  <ae:configuration>

    <validators>
      <validator class="string">
        <arguments>
          <argument>title</argument>
        </arguments>
        <errors>
          <error>The title field has an invalid value.</error>
          <error for="required">Please provide a title.</error>
          <error for="max_error">The title must be shorter than 255 characters.</error>
        </errors>
        <ae:parameters>
          <ae:parameter name="max">255</ae:parameter>
        </ae:parameters>
      </validator>
    </validators>
  </ae:configuration>
</ae:configurations>

c) formpopulationfilter magic

“All we need to do is re-display our form on the error page and the AgaviFormPopulationFilter will perform all of those duties. To re-display the form we could either include it in the ErrorViews template or we could set the input template in the view.”

2. The Zend Framework way

+ Encapsulation

+ Abstraction

+ DRY

3. The Agavi way

- I have to keep an eye to input names, as they are needed at more than one place. Beware of templating guys changing the input names, breaking stuff.

- validating an action, not a single form/form object

- breaks the DRY principle, code duplication occurs

4. Conclusion

I prefer Zend Framework over Agavi for forms. The main reason is the encapsulation in ZF with the Zend_Form object.

I can have more separated forms with separate validation on one page. I can reuse forms withouth having (that much) duplicate code anywhere. I don’t have to make changes to multiple locations if changing input names or validation, just one object holds every needed information/configuration. Zend_Form also does the html output for me, application-persistent interface guaranteed (styling is done via css or decorators per form/element).

Sources:

entropy project: Hello World!

Die Tage war es endlich so weit: nach zweimaliger und von vorne beginnender Programmierung habe ich den Prototypen meines PHP5 MVC Micro-Frameworks bei Github online gestellt – entropy project. Der Projekt-Name selbst lag mir schon seit Jahren auf der Zunge, es fehlte nur ein passendes Projekt.

[Read more]

PHP Micro Frameworks

Seit einigen Tagen bin ich jetzt auf der Suche nach sogenannten Micro Frameworks, insbesondere für PHP.

symfony, Agavi, Zend Framework und wie die anderen Größen in der Welt der PHP MVC-Frameworks alle heißen mögen, sind zwar schön und gut, mir persönlich aber viel zu aufgedunsen – die guten alten eierlegenden Wollmilchsäue eben.

[Read more]

,