Soap server authentication using nusoap

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”

  1. 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()

    • nferreira says:

      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!’);
      }

  2. 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;
      }

  3. Jefferson says:

    Dear Abdullah,

    Please, give me an example of the return of the authenticate function.

    Thanks in advance and best regards,

    Jefferson.

  4. 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.

  5. 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

  6. 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!

  7. 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.

  8. 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?

  9. Fernando says:

    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!

  10. Anderson Barbosa says:

    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

    " . $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

    ";
        print_r($result);
        echo "

    “;
    } else {
    $error = $client->getError();
    if ($error) {
    echo “Error

    " . $error . "

    “;
    } else {
    echo “zip code

    ";
            echo $result;
            echo "

    “;
    }
    }

    echo “Request”;
    echo “

    " . htmlspecialchars($client->request, ENT_QUOTES) . "

    “;
    echo “Response”;
    echo “

    " . htmlspecialchars($client->response, ENT_QUOTES) . "

    “;

Leave a Reply

Your email address will not be published.