Now you can view the article I wrote titling “Introduction to PHP Data Services“. There I explain how you can design and implement Data Services in PHP using WSF/PHP Data Services Library.

This article covers,

  1. Designing your Data Service API.
  2. Writing the Data Service.
  3. Deploying and Testing Data Service.
  4. Make the Data Service available in both SOAP and RESTful form.
  5. Use of WS-* features in your Data Service.

If you are thinking of adapting SOA in to your database backed PHP applications, this article will be a good starting point.

Same as web pages, web services also sometime require  client authentication. The most frequent way of authentication is the use of WS-Security Username token which authenticate clients based on the username and passwords. There can be situations where clients need to be authenticated based on its IP or its domain.

If you are writing web services from PHP (Using some PHP web service framework like WSF/PHP), You can use the PHP variables, $_SERVER["REMOTE_ADDR"] and $_SERVER["REMOTE_HOST"] to find the clients ip within the service logic code. If the client’s IP is static you can directly use the $_SERVER["REMOTE_ADDR"] and if it is dynamic you can use the $_SERVER["REMOTE_HOST"] which will be derived by reverse DNS look of the clients IP.

Here is one example of the use of these $_SERVER[] variables inside service logic.

 
function members_only_func($in_message) {

    // getting the clients IP.
    $remote_addr = $_SERVER["REMOTE_ADDR"];

    if($remote_addr == "67.205.26.154" ||
       $remote_addr == "124.43.59.95") {
       // generates the message for authenticated clients.

       return $valid_out_message;
    }

    // otherwise throw an exception
    throw new WSFault("Sender", "Failed to Authenticate");
}

$operations = array("membersOnlyOp" => "members_only_func");

$service = new WSService(array("operations" => $operations));

$service->reply();

Replay attack is a common kind of attack, the hackers are using to break the security of a web service.

If you can intercept one soap message while it is transferring through the wire, you can replay that message to the server again and again. Since the original message may have already encrypted, signed and contain valid authentication credentials the replaying messages will also be able to pass all the security tests and fool the server and do enormous damages to the business. For an example think of replying a soap message that a client is conducting a payment with a e-commerce service. The service may tend to charge the client multiple times for each request which break the integrity of the business.

So it is no doubt when ever you thinking of designing an enterprise web service application, you should give attention to ‘Replay Detection’ more seriously.

One solution is you can handle the replay detection inside the business logic itself. If you do this for the above mentioned e-commerce like services, you will keep all the session ids and make sure only one payment is possible for one session. But this may need some really careful design of the application logic.

The other solution is to let your web service framework to handle the ‘Replay Detection’. That will clearly separate the security aspects from the business aspects of your service. And it will give you more flexibility in configuring your security requirements. And the other advantage is it will detect ‘Replay Attacks’ well before hitting the business logic, making the web service perform well.

WSF/PHP allows you to detect replay attacks using WS-Addressing and WS-Username token headers. WS-Addressing headers contains a message id which can be considered as unique to a soap message and ws-security headers contains created time of the message which can be used to calculate the age of the message and derive its validity.

WSF/PHP provide web service developer a callback with the ‘message id’ and the ‘message created time’  per each message. In the callback you can store this message id and created time in a database, and check them against all the incoming soap messages. If it found duplicate entries, you can consider it as a replay attack.

Here is an example draft of the above scenario written using WSF/PHP.

/* replay detection callback */
function replay_detect_callback($msg_id, $time_created) {
    /* Here is the pseudo code of the logic

    query for the $msg_id and $time_created for the database.
    if already exist
      return FALSE;
    else
      Insert message id and time created to the database
    return TRUE */
}

$security_token = new WSSecurityToken(array( 
                      "replayDetectionCallback" => "replay_detect_callback",
                      "enableReplayDetect" => TRUE,
                      /* Other tokens */ ));

$svr = new WSService(array("securityToken" => $security_token,
                      /* Other options*/ ));

$svr->reply()

So if you use this code in the service you can happily detect any replays of an old message and avoid possible damages. But remember this security check will work only if the replaying message contain the same message id and the created time as the original one. It is possible that an intruder not only intercept the message, but also change these fields and replay it in to your server. Such replays will not be detected from this code.

The solution is to sign each SOAP requests. If a client sign a message with his private key, the server can confirm that the message is not altered while it is on the wire. So if intruder replay a signed message, either it will fail the replay detection test (if it is replaying without changing the message id and created time) or it will fail validating the signature (if the message id and the created time is altered).

So if you implement a replay detection test with a signature test, you can eliminate all the replay attacks to your service (at least theoretically :) .

Few months ago, I blogged about How you represent custom headers in a WSDL. In there I mentioned, WSF/PHP is going to support sending and handling custom SOAP headers with the 2.0 release which was released early September. Today I will write how how to use this new feature in your Web Service Client.

In order to do the comparison I will show you how you could send Custom SOAP headers before WSF/PHP 2.0.

Preparing Custom SOAP Headers Manually

Before 2.0 you have to prepare the custom SOAP headers manually. For that you could use the WSHeader object.

Say you want to create the following message for your WSDL. (I excluded the headers and payload namespaces for the clarity)

<soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
   <soapenv:Header>
      <Header1>
         <string>test1</string>
         <int>5</int>
      </Header1>
      <Header2>
         <int>6</int>
         <string>test2</string>
      </Header2>
   </soapenv:Header>
   <soapenv:Body>
      <echo>Hello</echo>
   </soapenv:Body>
</soapenv:Envelope>

Here is how you prepare it using WSMessage and WSHeader objects.

// request payload
$requestPayloadString = <<<XML
<echo>Hello</echo>
XML;

// creation of two headers
$header1 = new WSHeader(array(
			"name" => "Header1",
			"data" => array(
				new WSHeader(array("name" => "string",
						"data" => "test1")),
				new WSHeader(array("name" => "int",
						"data" => "5")))));

$header2 = new WSHeader(array(
			"name" => "Header2",
			"data" => array(
				new WSHeader(array("name" => "int",
						"data" => "6")),
				new WSHeader(array("name" => "string",
						"data" => "test2")))));

// you prepare the soap message = request payload + two input headers
$request_msg = new WSMessage($requestPayloadString,
			array("inputHeaders" => array($header1, $header2)));

// create the WSClient with the endpoint
$client = new WSClient(array( "to" => "http://localhost/header_echo_service.php" ));

// do the request with the WSMessage instance as the request argument
$responseMessage = $client->request($request_msg);

// print the response
printf("Response = %s <br>", htmlspecialchars($responseMessage->str));

As you can see you are preparing hierarchical tree of WSHeaders to prepare the SOAP message. Anyway after 2.0 you don’t need to write this much of code to get the work done.

Preparing Custom SOAP Headers in WSDL Mode

If you have a WSDL it is so easy to start by generating the initial code from the WSDL2PHP tool. If I take the WSDL from my old post about custom headers in WSDL WSDL2PHP tool will generate the following set of classes.

class Header1 {

    /**
     * @var string
     */
    public $string;

    /**
     * @var int
     */
    public $int;

}

class Header2 {

    /**
     * @var int
     */
    public $int;

    /**
     * @var string
     */
    public $string;

}

And you will get the following piece of code with the Note “TODO” where you need to fill the input fields and retrive the output values from the operation.

    // create input object and set values
    //TODO: fill $input with (data type: string) data to match your business logic

    $header_in0 = new Header1();
    // TODO: fill in the class fields of $header_in0 object which is of type Header1 to match your business logic

    $header_in1 = new Header2();
    // TODO: fill in the class fields of $header_in1 object which is of type Header2 to match your business logic

    // call the operation
    $response = $proxy->echoString($input, $header_in0, $header_in1, &$header_out0, &$header_out1);
    //TODO: Implement business logic to consume $response, which is of type string

    // TODO: Implement business logic to consume $header_out0 object, which is of type class Header1

    // TODO: Implement business logic to consume $header_out1 object, which is of type class Header2

After I follow the guidelines in the comment, My code looks so simple and little like this,

    // create input object and set values
    $input = "Hello"; // I filled $input with a string

    $header_in0 = new Header1(); // I m filling the header1
    $header_in0->string = "test1";
    $header_in0->int = 5;

    $header_in1 = new Header2(); // now the header2;
    $header_in1->string = "test2";
    $header_in1->int = 6;

    // call the operation
    $response = $proxy->echoString($input, $header_in0, $header_in1, &$header_out0, &$header_out1);

    // echoing the response payload which of type string
    echo $response;

    // echoing the $header_out0 object, which is of type class Header1
    echo "output header0 contains {$header_out0->string} and {$header_out0->int}";

    // echoing the $header_out1 object, which is of type class Header2
    echo "output header1 contains {$header_out1->string} and {$header_out1->int}";

There the headers are PHP class objects. You fill the public variables of the classes and pass them to the ‘echoString’ operation. Although it looks like it call just a php function named ‘echoString’, it actually invoke the web service operation named ‘echoString’, with the request payload and custom SOAP headers. It returns the response payload value + the output headers to the references we passed as the last 2 arguments.

So with WSF/PHP 2.0 you can use WSDL mode and WSDL2PHP tool to send payload with custom headers with a little and quick code.

Samisa Abeysinghe who is the director of engineering at WSO2 and one of the key leaders of the WSF/PHP project has published a book titled RESTful PHP Web Services.

RESTful PHP Web Services - Samisa Abeysinghe

RESTful PHP Web Services - Samisa Abeysinghe

In Samisa’s Blog He describes the structure and the content of the book in his own words.

If you are developing RESTful web services in PHP, you will find this book will be a great reference.

WSF/PHP Demo Site contains number of sample web service applications which demonstrate the different features of WSF/PHP. From these demos, Mashup Search Demo demonstrate  the use of  publicly available web services to create a search mashup in your web site.

This demo consists of 3 public web services namely Flickr, Yahoo and Amazon.

Flickr Yahoo Amazon
Service Documentation Page Flickr API Docs
Yahoo API Docs
Amazon API Docs
REST/SOAP REST REST SOAP and REST
Registration for Key Flickr API registration
Yahoo API registration
Amazon API Registration
Source code for sample consumer Flickr Demo Source
Yahoo Demo Source
Amazon Demo Source
PHP class used FlickrClient YahooClient AmazonClient
Available Operations
  • photosTextSearch
  • photosTagSearch
  • webSearch
  • newsSearch
  • imageSearch
  • localSearch
  • itemSearch
  • itemLookup

September 25th, 2008WSF/PHP Webinar

WSO2 WSF/PHP Webinar slides are now online. It basically contains an introduction to the WSF/PHP project, the features in its last week hot release and its enterprise applications.

You can watch the video of the Webinar from here. Visit the WSF/PHP Webinar Page for more details.

In PHP you have several ways of sending binary data. It can be primarily categorized in to non-optimized method (send as base64 binary) and optimized method (send as MTOM or SWA). Here I m talking about how to send binaries in above mentioned methods starting from a WSDL.

WSDL

Think you have a WSDL with the following XML Schema.

            <!-- Here is my submitPerson method->

            <xs:element name="submitPerson">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="name" type="xs:string"/>
                        <xs:element name="age" type="xs:int"/>
                        <xs:element name="photo" type="xs:base64Binary"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>

The submit Person method submit the name,age and a photo which is a type of base64Binary.

Generated Class

After generating php class for this piece of code using wsdl2php you will have  the following class.

class submitPerson {

    /**
     * @var string
     */
    public $name;

    /**
     * @var int
     */
    public $age;

    // You need to set only one from the following two vars

    /**
     * @var Plain Binary
     */
    public $photo;

    /**
     * @var base64Binary
     */
    public $photo_encoded;

}

So it is very easy to fill the class with your own data. Note that you only need to fill one of the ‘photo’ or ‘photo_encoded’ fields. If you have binary already converted to base64 then you can use the ‘photo_encoded’ field where as if you only have the row binary just use the ‘photo’ field. Here are my values for this particular example.

$person = new submitPerson();
$person->name = "xxxx yyy";
$person->age = 35;
$person->photo = file_get_contents("/photo/xxxyyy");

Sending Binary as MTOM

Here is the code you need to send the above structure as a MTOM message.

$client = new WSClient(array("useMTOM" => TRUE)); // anyway useMTOM is default to TRUE for WSClient
$proxy = $client->getProxy();

$response = $proxy->submitPerson($person);

Sending Binary as Base64 Encoded string

You only need to change one option. That is setting “useMTOM” to FALSE will send the binary as Base64.

$client = new WSClient(array("useMTOM" => FALSE));
$proxy = $client->getProxy();

$response = $proxy->submitPerson($person);

SWA (SOAP With Attachments)
You can send the binary data as SWA by setting the “useMTOM” option to “SWA”. SWA is also a binary optimized method of sending attachments, but unlike with MTOM you can’t integrate security or reliability with this approach.

September 20th, 2008SOA Way of Writing PHP

Traditional way of Writing PHP
Let me draw a component diagram of a typical traditional(conventional) PHP web application.MVC Architecture Model

With this design you get the advantages of the client-server architecture and the MVC design pattern.

Advantages of the Traditional Approach

  • You can connect to the server from anywhere that has the connectivity to the centralized server. Say you process purchase orders in your application. Sails agents, customers around the world can connect to the application from their computers and do purchase orders. (Because of the Client-Server Architecture)client-server architecture
  • Doing Changes to the inside of the components (Model, View and Controller) are relatively easy , because of the separation of the logics. But if changes affect to inter-communication of each component then it become harder because of the low granularity. (check disadvantages)

Are their any disadvantages of this approach?
Yes. There are plenty of them. Actually it is lot more than the advantages list.

Disadvantages of the Traditional Approach

  • More Server load: The only server is responsible for maintenance of all the components. And there is no straight forward way to distribute these components in a network.
  • No Interoperability: Can I replace the PHP Presentation layer with a .NET, C, Java Desktop Application with this design? No. PHP components (Model, View, Controller) are communicated in PHP code level through php function calls or may be through PHP object interactions, If you want to integrate .NET/Java to replace one component, you have to change all these function calls, object passings with each components.
    non-interoperability
  • Fine Grained Interfaces: Even when I want to replace some component with another PHP implementation, it is still very difficult to integrate to the running system because of the fine-grained interfaces (Lot of small operations) used in the inter-component communication.
    Mostly this issue comes when integrating new business component to existing business logic within the controller logic. The below is just a figure to demonstrate what is meant by fine-grained interface.
    fine-grained-services
    This causes the application to be slow (more message exchange => more time on the wire =&t; lesser speed), more traffic to the server and most importantly very hard to make interfaces consistent. (There can be many additions and removals of small operations over the time). Check this for learn more about the granularity.
  • Business Process Automation (BPA) is impossible: Your partner companies can not purchase your products through their systems. Because they are only given a browser interface, which need human interaction. You should provide some remote interface to allow their computers to talk to your systems.
    bpa-impossibility
    For BPA, interoperability is really important. Because your partner company may run on completely different platform and use completely different languages. I already proved traditional design will not suit to situation where interoperability is need.
  • Lack of security: With the above approach you have to depend on the transport level security, which is handled by your OS. There can be applications (malicious codes) run top of your OS which have back doors to these information. So for business critical messages you need to have message level security (application to application security) which secure the messages by application itself .
  • Lack of reliability: In any case if the connection is lost, will my messages completely lost?. Here too you depend on the transport level reliability which you don’t have much control of.

So now lets turn to our main topic.

SOA Way of Writing PHP

SOA Model

With SOA, you application is no longer presenting the ‘View’ component directly. Instead it provides your business operations as a Web Service. You may implement a View with PHP using this web service. This approach allows you to implement View not only in PHP but also in other languages like .NET, Java or C as web application or desktop applications.

The business logic access the Data Layer through a Data Service. Simmilarly It can use third party Data services, Web Services to extract out the Data needed in the business process.

Let’s see how it helps you to solve the problems arouse in the traditional approach.

  • Less Server load: The SOA components are natively distributed. You don’t need to process the View and the Data in the same server you process the Buisness Logic.
  • High Interoperability: SOA communication happens through Web Services which is a standard protocol. There are implementations for web services in many languages and for many platforms. You can replace any components with any implementation you prefer. For an example you may first write your business logic in PHP, And as the server load goes high, you can write the buisness module in native language (‘C’) and easily intergreate to the system, without being bother of changing other components.
  • Coarse grained Interfaces: The latest web services standards (e.g. WSDL 2.0) enforce the use of documents for messaging rather than invoking remote procedures. This causes the system to be consistent, maintainable and more responsive.
  • Business Process Automation: Web service provide a platform to machine to machine communication. With the availability of interoperability two companies who use different implementations can communicate easily
  • Security: With a WS-Security implementation you can get message level security in your application. For PHP developers there were no implementation or library that can provide  WS-Security sometime ago. But as WSF/PHP is launched with many implementations for WS-* stack, that gap was closed.
  • Reliability: With the WS-Reliable Messaging you can make sure a reliable communication at the application layer. You can use WSF/PHP to do reliable messaging in PHP

As your business get more complicated you can divide the logic too in to several service components as you do with data and view components. This allows you to extend your application very easily. Here is a rough design of an enterprise SOA application that you may have seen in Java and .NET paradigms. And it is time to see more of these in PHP space as well.

SOA design

I have been working for Axis2/C codegen tool for sometime now and I found lot of users who want to edit the codegen templates for a more optimized code specific to their use cases. This is mainly because codegen tool generates a very general code (For an example lot of unused variables generated for some WSDLs, but they are used in some other WSDLs) where as mostly ‘C’ people prefer to be as optimized as possible. Axis2 Java templates are more stable and not needed to customized as much as C templates, but Java developers too may find it is really useful to edit them in a case they need some customizations.

Both Axis2 C and Java tools comes with Axis2/Java project. So you may already have downloaded the latest Axis2/Java release or the Axis2/Java nightly build. As per title you can do this customization not only in the source but also in the binary pack. So I assume you have the binary pack.

Codegen tool mainly comes within two jars inside the lib directory of your Axis2/Java pack. (Here xxxx should be replaced with the particular jar version, it can be 1.4, 1.4.1 or SNAPSHOT)

  • axis2-codegen-xxxx.jar – The core classes of the codegen (This is where WSDL2C and WSDL2Java classes reside)
  • axis2-adb-codegen-xxxx.jar – This is the library containing the adb component of the codegen tool. ADB (Axis2 Data Binding) is the native databinding format of Axis2 which convert your xml schema to a more programmer friendly set of java classes or ‘C’ structures. The XSD2Java class comes in this jar.

Editing the Stub and Skeleton templates

When you unpack the axis2-codegen-xxxx.jar

jar xf axis2-codegen-xxxx.jar

you can find the template for Stub and Skel in org/apache/axis2/wsdl/template/c or org/apache/axis2/wsdl/template/java directories.

  • Stub For C – org/apache/axis2/wsdl/template/c/StubSourceTemplate.xsl (source) and org/apache/axis2/wsdl/template/c/StubHeaderTemplate.xsl (header)
  • Skeleton for C – org/apache/axis2/wsdl/template/c/SkelSourceTemplate.xsl (source) and org/apache/axis2/wsdl/template/c/SkelHeaderTemplate.xsl (header)
  • Stub For Java – org/apache/axis2/wsdl/template/java/InterfaceImplementationTemplate.xsl
  • Skel For Java – org/apache/axis2/wsdl/template/java/MessageReceiverTemplate.xsl (Message Reciever) and org/apache/axis2/wsdl/template/java/SkeletonTemplate.xsl (skeleton)

These templates are written is XSL. Even if you are an XSL expert, you may find little difficult to understand whole lot of codes in there. But if you really know what you need to change, you can track back the lines (may be using comment or some specific static set of code). So you don’t actually need to know any XSL to do these little customizations.

After you do the change simply pack the classes (which are in the ‘org’ directory) as the jar with the same name.

jar cf axis2-codegen-xxxx.jar org

Editing the ADB templates

You can similarly observe the axis2-adb-codegen-xxxx.jar. All the templates are in the org/apache/axis2/schema/template/ directory.

  • C ADB templates – org/apache/axis2/schema/template/CADBBeanTemplateHeader.xsl (Source) and org/apache/axis2/schema/template/CADBBeanTemplateHeader.xsl (Header)
  • Java ADB template – org/apache/axis2/schema/template/ADBBeanTemplate.xsl

You will find the template for the Java classes and C structures there. In C code generation if you find some variables are not used throughout your WSDLs, you can remove directly if from the templates. And some constants which are defined to allocate memory can be changed to suit to your application.

Anyway after all these notes, I have to say it is not really recommended to hack a code specific to your application. If you found a change general to all the applications you better submit the patch to the Axis2 community, so others too can use it. Otherwise whenever you do a upgrade you have to do this again on your own. But I hope these tips may be useful specially when you are working with ADB to do your own experiments.


© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress