Problem scenario:
You want to create a secure soap server with nusoap library. In the nusoap library there is no better way to make authentication
Efficient solved scenario:
There is 2 way to make authentication
1. You may create a custom function which works for authentication and you need to pass username and password in every call
2. You may send authentication data in soap header. All time you process the username and password data from soap header
Prerequisites
- NuSoap library.
Following steps
1. Create a wrapper class for server
require_once('lib/nusoap.php');
class Soap_wrapper extends soap_server{
var $script_uri;
public function __construct()
{
$page = $_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
//$page = substr($page,0,strrpos($page,'/'));
$this->script_uri='http://'.$page;
parent::nusoap_server();
$this->configureWSDL('testserver','urn:'.$this->script_uri);
$this->wsdl->addComplexType("ArrayOfString",
"complexType",
"array",
"",
"SOAP-ENC:Array",
array(),
array(array("ref"=>"SOAP-ENC:arrayType","wsdl:arrayType"=>"xsd:string[]")),
"xsd:string");
$this->wsdl->schemaTargetNamespace=$this->script_uri;
$this->register('authenticate',
array('client'=>'xsd:string','key'=>'xsd:string'),
array('return'=>'xsd:string'),
'urn:'.$this->script_uri,
'urn:'.$this->script_uri.'#authenticate'
);
public function service_start($data)
{
if(!empty($data)){
/***********parsing header for authentication********/
parse header for username and password
/*********************************************************/
$this->validateUser($authHeaders); // function to validate the user
$this->service($data);
}
else
$this->service($data);
}
public function validateUser($auth)
{
if(!empty($auth[username])&& !empty($auth[password]))
authenticate($auth[username],$auth[password]); //this function check the authentication from db
else $server->fault(401,'Authentication failed!');
}
}
2. Create soap server
require_once('soap_wrapper.cls.php');
$debug=1;
$server=new Soap_wrapper();
/*********************************************************/
$HTTP_RAW_POST_DATA=isset($HTTP_RAW_POST_DATA)?$HTTP_RAW_POST_DATA:'';
$server->service_start($HTTP_RAW_POST_DATA);
3. Create a client
$client=new SoapClient('http://localhost/soap_server/server.php?wsdl',array('trace'=>true));
$param= new SoapVar(array('username' => 'abdullah','password'=>'test'), SOAP_ENC_OBJECT);
$header = new SoapHeader('http://localhost/soap_server/server.php', 'AuthenticationInfo', $param,false);
$client->__setSoapHeaders($header);
try{
$data=$client->__soapCall('getData',array('id'=>'1'));
print_r($data);
}
catch (SoapFault $exception)
{
echo $exception->faultstring;
}
20 Responses to “Soap server authentication using nusoap”
Dear Abdullah,
where does the variable “$authHeaders” get its values ?
Regards,
Jerre
You need to parse $data to get the header value. $authHeaders is a simple array where you stored the username,password from the $data variable. You can parse this $data using any xml library
is the function ‘authenticate which registered must call by the client,if so; when to call main function;
and what is return result of authenticate()
Hi.
I am using nusoap (X-SOAP-Server: NuSOAP/0.7.3 (1.114)) for the first time and i am having trouble to access the headers in the server side.
My request is this:
user
pass
123456789
In the client i use this to fill the headers:
——————————————
$param = new SoapVar(array(‘username’ => ‘user’,’password’=> ‘pass’),SOAP_ENC_OBJECT);
$header = new SoapHeader($this->wsdl,’UserCredentials’,$param,false);
$this->client->__setSoapHeaders($header);
——————————————-
In the server i will use a function to authenticate the user after parsing the username and password from headers.
However i can’t access the variables from headers.
I tried this methods whitout success:
——————————————-
$this->nusoap_server->parse_request()
$this->nusoap_server->parse_http_headers()
$this->nusoap_server->requestHeader[‘UserCredentials’][‘username’]
$this->nusoap_server->requestHeader[‘UserCredentials’][‘password’]
——————————————————————-
Can you explain me how to fetch those variables Abdullah?
Thanks in advance and best regards,
nferreira
You can use any xml library for parsing the headers.
Try this
In client:
$client->setCredentials(base64_encode($login),base64_encode($password));
In Server:
$arrCred[‘user’] = base64_decode($_SERVER[‘PHP_AUTH_USER’]);
$arrCred[‘password’] = base64_decode($_SERVER[‘PHP_AUTH_PW’]);
this way it works for me:
public function service_start($data)
{
if(!empty($data)){
/***********parsing header for authentication********/
// parse header for username and password
$AuthenticationInfo = array();
$doc = new DOMDocument(“1.0″,”utf8”);
$doc->loadXML($data);
$xpath = new DOMXpath($doc);
$usernameList = $xpath->query(“//username”);
if($usernameList->length>0){
$AuthenticationInfo[“username”] = $usernameList->item(0)->nodeValue;
}
$passwordList = $xpath->query(“//password”);
if($passwordList->length>0){
$AuthenticationInfo[“password”] = $passwordList->item(0)->nodeValue;
}
/*********************************************************/
$this->validateUser($AuthenticationInfo); // function to validate the user
$this->service($data);
}
else
$this->service($data);
}
public function validateUser($auth)
{
if(!empty($auth[“username”])&& !empty($auth[“password”])){
$this->authenticate($auth[“username”],$auth[“password”]); //this function check the authentication from db
}
else //$server->fault(401,’Authentication failed!’);
$this->fault(401,’Authentication failed!’);
}
Hello Abdullah,
I am looking at your comments in service_start function “parse header for username and password”, could you please help with the function to parse this. A simple example will do, or point me to one, I am new to PHP and kind off lost.
Thank you for you help,
joat
Hello,
I have been playing with this script today and only got it working after I realized I had to parse the soap header. Here is the code I used:
$AuthenticationInfo = array();
$doc = new DOMDocument(“1.0″,”utf8”);
$doc->loadXML($data);
$xpath = new DOMXpath($doc);
$usernameList = $xpath->query(“//username”);
if($usernameList->length>0){
$AuthenticationInfo[“username”] = $usernameList->item(0)->nodeValue;
}
$passwordList = $xpath->query(“//password”);
if($passwordList->length>0){
$AuthenticationInfo[“password”] = $passwordList->item(0)->nodeValue;
}
Excellent replay thank you very much , it works fine
Dear Abdullah,
Please, give me an example of the return of the authenticate function.
Thanks in advance and best regards,
Jefferson.
Hi, I’ve tried servial times on php 5.1.6, but without success. Could you send me sample codes?
My mailbox is xj107359@163.com.
Thanks in advance.
What error you get?
Hey,
I am trying to learn as to how to consume a web service in .NET using PHP. This is my first time with NuSoap and i can’t seem to get anywhere here. Below are the request and response to the webservice. Now how do i go about accessing the same. Anyhelp would be appreciated.
________________________________________________________________
Request:
POST /Service.asmx HTTP/1.1
Host: 172.160.0.49
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: “http://tempuri.org/GetData”
string
string
string
________________________________________________________________
Response:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
string
You’ll find way easier to use Zend_Soap_Client from Zend Framework. It’s actually a wrapper for native SOAP functions from PHP. If you want any help with this send an email to marc (at) nwd (dot) mx.
Regards,
Marc
I do not even understand how I finished up here, however I thought this submit was good. I don’t understand who you might be but certainly you are going to a well-known blogger when you are not already. Cheers!
Hi,
can you please tell me how to add authentication header / soap header in during wsdl creation i.e. during adding complextype and registring function in nusoap_server.
I really need that as soon as possilbe.
your help will be appriciated.
Thanks in advance try to place sample code for this as well.
Seems to work for me except that I can’t access the WSDL now.
Do you have any idea why this is happening?
Or do I have to pass credentials in order to view the WSDL?
Thank for the script it helped a lot!!
For the “incomplete” parts you can use same nusoap to parse headers:
/***********parsing header for authentication********/
$parser = new nusoap_parser($data);
$authHeaders = $parser->get_soapheader(); // get headers in php array
/****************************************************/
for validation I modified the script like this:
if( $this->validateUser($authHeaders) ){
$this->service($data)
}
and the validateUser method return true if user and password are valid or false otherwise, how do you achieve this, is up to you (text file, database, array, hard coded…)
cheers!
Add basic authentication in the header (Works with SoapUi)
Thank you very much for sharing, I have managed to complete with other forums authentication in the header, I share result.
You need to use “PHP_AUTH_USER” and “PHP_AUTH_PW”, this guarantees credentials per header and you can do example by “SoapUI – Auth (Basic)” select “Pre-emptive auth -> Authenticate pre-emptively”.
///////// server.php
script_uri = ‘http://’ . $page;
$this->configureWSDL(‘testserver’, ‘urn:’ . $this->script_uri);
$this->wsdl->schemaTargetNamespace = $this->script_uri;
}
public function service_start($data)
{
if (!empty($data)) {
/***********parsing header for authentication********/
if (!isset($_SERVER[‘PHP_AUTH_USER’]) || !isset($_SERVER[‘PHP_AUTH_PW’])) {
$this->fault(401, “Authentication required!”);
return;
}
$AuthenticationInfo = [‘username’ => $_SERVER[‘PHP_AUTH_USER’], ‘password’ => $_SERVER[‘PHP_AUTH_PW’]];
/*********************************************************/
$this->validateUser($AuthenticationInfo); // function to validate the user
$this->service($data);
} else{
$this->service($data);
}
}
public function validateUser($auth)
{
if (!empty($auth[“username”]) && !empty($auth[“password”])) {
$this->authenticate($auth[“username”], $auth[“password”]); //this function check the authentication from db
} else {
$this->fault(401, “Authentication failed!”);
}
}
public function authenticate($username, $password){
if($username === ‘anderson’ && $password === ‘1234567890’){
return true;
}else{
$this->fault(401, “Authentication failed!”);
}
}
}
try{
$server = new Soap_wrapper();
$page = $_SERVER[‘HTTP_HOST’] . $_SERVER[‘PHP_SELF’];
$ns = ‘http://’ . $page;
$input_array = array(‘id’ => “xsd:string”);
$return_array = array(“return” => “xsd:string”); // cambio de array a string
$server->register(‘getData’, $input_array, $return_array, “urn:SOAPServerWSDL”, “urn:” . $ns . “/getData”, “rpc”, “encoded”, “Prueba de conexion al WS”);
function getData($id){
return “Hola $id”;
}
$server->service_start(file_get_contents(“php://input”));
}catch(\Exception $e){
die(“Error”);
}
///////// client.php
getError();
if ($error) {
echo “Constructor error
“;
}
//Use basic authentication method
$client->setCredentials(“anderson”, “1234567890”, “basic”);
$result = “”;
if ($client) {
$result = $client->call(“getData”, array(“id” => “123”));
}
if ($client->fault) {
echo “Fault
“;
} else {
$error = $client->getError();
if ($error) {
echo “Error
“;
} else {
echo “zip code
“;
}
}
echo “Request”;
echo “
“;
echo “Response”;
echo “
“;