PHP and SOAP Authentication

One of my recent projects for a customer of mine, ResortScope, LLC, involved setting up some web services to allow access to data in our database to external consumers.  To provide this functionality, I used the NuSOAP library and PHP.  However, one of the limitations of the NuSOAP library is that it is unable to parse SOAP headers, which typically contain authentication information.  Consider:



<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:si="http://soapinterop.org/xsd">

<soap:Header>
<AuthenticationInfo xmlns="urn:MyService">
<username>test</username>
<password>1a232d4dg35</password>
</AuthenticationInfo>
</soap:Header>
<SOAP:Body>
<ns1:SomeMethod xmlns:ns1="urn:MyService">
<param1>foo</param1>
<param2>bar</param2>
</ns1:SomeMethod>
</SOAP:Body>
</SOAP-ENV:Envelope>

As you can see, the username and password are embedded in the SOAP:header.  So, to get at this data, you will need to parse the header yourself.  The way I chose to do this was to subclass the NuSOAP soap_server class and override the service method.



<?php
class MySoapServer extends soap_server
{
var $_objParser;

// Class constructor
function MySoapServer($wsdl=false)
{
// Create a new instance of the XML parser
$this->_objParser = new MyXMLParser();

// Call the parent constructor method and pass the WSDL flag to it
parent::soap_server($wsdl);

} // End Function

function service($data)
{
// Parse the xml message
$this->_objParser->setXMLData($data);

// Retrieve the authentication information from the xml message
$arrCredentials = $this->_objParser->getCredentials();

// Sanity check - did we get the credentials?
if(is_array($arrCredentials) &#038;&#038;
($arrCredentials[&#8217;username&#8217;] != &#8220;&#8221;) &#038;&#038;
($arrCredentials[&#8217;password&#8217;] != &#8220;&#8221;))
{
// Authenticate the user
$this->_intWSUserID = $this->_authenticate($arrCredentials);

// If authentication was successful, handle the rest of the message
if($this->_intWSUserID > 0)
{
parent::service($data);
}
else
{
// return a SOAP fault
}
}

} // End Function

function _authenticate($arrCredentials)
{
// Sanity check: did we get a valid array?
if(! is_array($arrCredentials))
{
// return a SOAP fault
}

// Handle your authentication code here.  I use a MySQL database for holding user data

} // End Function

} // End of Class
?>

In this above example, I deal with a class called “MyXMLParser”, which is an object that has methods for parsing XML data.  You could just as easily parse the data using native PHP methods.  As you can see, the AuthenticationInfo is parsed out of the SOAP message header, and the username and password are extracted and passed to the _authenticate() method.  How you choose to do your authentication is up to you.  In my case, I return the userID from the database for the authenticated user.  If and only if I get a userID back from the _authenticate() method do I call the service() method in the parent class.

Thanks to Scott Nichol for a great PHP library!

Technorati Tags: php nusoap SOAP

Leave a Comment

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.