SOAP Authenticatation using Soap Headers – API Class, Client, Server & WSDL Generation Examples

So about a week ago I needed to put together a SOAP service and wanted to make sure that not just anyone would be able to access the services. So I set about and scanned many pages in my google searches and have finally come to a working example. Hopefully you will find this page relatively quickly and save yourself the same nearly endless searches.

First let’s go ahead and create the server side of the service. I have posted the example of this code earlier on in another SOAP tutorial, but I will go ahead and throw it in here as well.

Server.php

if (isset($_GET['wsdl'])) {
    // This is to autogenerate the WSDL based off of our main API class
    $autodiscover = new Zend_Soap_AutoDiscover();
    $autodiscover->setClass('YourClassNameHere','', null,$_SERVER['PHP_SELF']);
    $autodiscover->handle();
    
} else {
    
    $options = array('uri' => 'urn:YourClassNameHere',
    		           'location' => 'http://location/tothisfile/Server.php?wsdl');
    
    $server = new SoapServer(null, $options);
    $server->setClass('YourClassNameHere');
    $server->handle();
    
}

The above code will generate a WSDL when sent requested via the GET variable, otherwise it will act as our Server. I used the Zend Framework Soap class to auto-generate my WSDL, worked great!

Now for the client:

Client.php

class API_Client {

    private static $instance = NULL;
    
    private function __construct() {
    
    }
    
    /**
    * Return client instance or create intitial 
    *
    * @todo save session id or set var or something so each soap call doesn't need to auth
    * @return object
    * @access public
    */
    
    public static function getInstance() {
    
        if (!self::$instance) {
       
            $ns   = "auth";
            $wsdl = "http://location/tothisfile/Server.php?wsdl";
            
            //Create our Auth Object to pass to the SOAP service with our values
            $auth->username = 'fake_user';
            $auth->password = 'fake_pass';

            $auth_vals    = new SoapVar($auth, SOAP_ENC_OBJECT);

            //The 2nd variable, 'authenticate' is a method that exists inside of the SOAP service (you must create it, see next example)
            $authenticate = new SoapHeader($ns,'authenticate',$auth_vals, false);
            
            $client = new SoapClient($wsdl,array('cache_wsdl' => 0));
                                             
            $client->__setSoapHeaders(array($authenticate));
            
            self::$instance = $client;
        }
        
        return self::$instance;
    }
    
    
    private function __clone(){
        
    }

}

//These are a few sample calls to functions inside of the WSDL

$data_1 = API_Client::getInstance()->getCategories('Tips');
$data_2 = API_Client::getInstance()->getContent('Zend Framework');

print_r($data_1);
print_r($data_2);

Ok there is our client example. This will connect to our SOAP server and passes it the username and password values (auth object) that we will then authenticate inside of our ‘YourClassNameHere’ class that we passed into the WSDL to autogenerate. Here is an example class that we can pass into the object from the start.

class YourClassNameHere {
    
  /**
     * Authenticates the SOAP request. (This one is the key to the authentication, it will be called upon the server request)
     *
     * @param array
     * @return array
     */
    public function authenticate($login)
    {
        if(!empty($login->username) && !empty($login->password)) {
            
            $query = "SELECT authentication_id FROM authentication WHERE username = ? AND password = ?";
            
            //add your own auth code here. I have it check against a database table and return a value if found.

            if($found) {
                
                return true;
                
            } else {
                
                throw new SOAPFault("Incorrect username and or password.", 401);
                
            }
            
        } else {
            
             throw new SOAPFault("Invalid username and password format. Values may not be empty and are case-sensitive.", 401);
             
        }
        
    }

    /**
     * 
     * SAMPLE METHOD NOT COMPLETE AND NOT SUGGESTED FOR USE
     * Get category information for the passed id
     * 
     * @param integer id 
     * @return mixed
     * 
     */
    public function getCategory($id)
    {
        
        $query = "SELECT * FROM category WHERE category = ?";

        if($found) {
            
            return $found;
        
        } else {
            
            return false;
        }
        
    }
   // INSERT MORE METHODS HERE!! Make sure to use the PHP doc comments above your methods and include the 
   // @param VAR_TYPE (array,mixed,integer,string, etc.)
   // @return RESPONSE_TYPE (array,mixed,integer,string, etc.)
}

This should get you a GREAT start on your project. It should be all you will need in order to create an auth based soap server and client. Post any questions below and I will do my best to help you out.

Tuesday, January 5th, 2010 API Services, Zend Framework

5 Comments to SOAP Authenticatation using Soap Headers – API Class, Client, Server & WSDL Generation Examples

  • Dan says:

    Nice page, though it could be improved by making the client Zend based too

  • [...] integer Routy Design SOAP Authenticatation using Soap Headers API …return RESPONSE_TYPE (array,mixed,integer,string, etc.) This should get you a GREAT start on your [...]

  • Elthamare says:

    I know this is an old post and if I don’t have an answer, well, I tried.

    I’m trying to setup a SoapServer (using Zend) with authentication. If I manage to beat all the problems regarding headers with Zend_Soap_server, I’d like to use some kind of authentication, and your example is the only one I could find (despite it’s not based on Zend).

    My question is: in this example “authentication” isn’t forced, is it? is there any way to do it? (or, if it is, how is it working?)

    Thanks.

    • nick@routydesign.com says:

      Only a couple month delay, not bad right? ;) This authentication IS forced. You will not be able to access any of the other methods in the service without first successfully passing through the authentication. Let me know if you need any more details on it, took me awhile to figure out how to do this.

  • Ruben says:

    Hello,

    I’m working on a SOAP Server and I need authentication. So I followed your instructions but I get this error:

    Message: Error cannot find parameter
    Stack trace:

    #0 application/controllers/SoapController.php(58): SoapClient->__call(‘getAllCategorie…’, Array)
    #1 application/controllers/SoapController.php(58): SoapClient->getAllCategories()
    #2 /library/Zend/Controller/Action.php(513): SoapController->clientAction()
    #3 /library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch(‘clientAction’)
    #4 /library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
    #5 /library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
    #6 /library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
    #7 /public_html/index.php(29): Zend_Application->run()
    #8 {main}

    Do you know where this error come from?
    Thanks

  • Leave a Reply

    You must be logged in to post a comment.

    [ad code=1 align=center]