Recipe 15.8. Using Authentication with SOAP


15.8.1. Problem

You want to authenticate SOAP requests. This allows you to restrict services to only trusted clients.

15.8.2. Solution

Authenticate using HTTP Basic authentication:

<?php // Your authentication logic // Which is probably decoupled from your SOAP Server function pc_authenticate_user($username, password) {     // authenticate user     $is_valid = true; // Implement your lookup here     if ($is_valid) {         return true;     } else {         return false;     } } class pc_SOAP_return_time {     public function __construct() {         // Throw SOAP fault for invalid username and password combo         if (! pc_authenticate_user($_SERVER['PHP_AUTH_USER'],                                    $_SERVER['PHP_AUTH_PW'])) {             throw new SOAPFault("Incorrect username and password combination.", 401);         }     }     // Rest of SOAP Server methods here... } $server = new SOAPServer(null,array('uri'=>"urn:pc_SOAP_return_time")); $server->setClass("pc_SOAP_return_time"); $server->handle(); ?>

Or use a SOAP header:

<?php // Your authentication logic // Which is probably decoupled from your SOAP Server function pc_authenticate_user($username, password) {     // authenticate user     $is_valid = true; // Implement your lookup here     if ($is_valid) {         return true;     } else {         return false;     } } class pc_SOAP_return_time {     public function authenticate_user($args) {         // Throw SOAP fault for invalid username and password combo         if (! pc_authenticate_user($args->username,                                    $args->password)) {             throw new SOAPFault("Incorrect username and password combination.", 401);         }     }     // Rest of SOAP Server methods here... } $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time')); $server->setClass('pc_SOAP_return_time'); $server->handle(); ?>

15.8.3. Discussion

Compared to the standard authentication in the rest of your applications, SOAP authentication isn't too complicated. There are two easy ways of integrating it into your SOAP server: using HTTP Basic authentication or processing a custom SOAP header.

If you're unfamiliar with these concepts, you should first read Recipe 8.9 for a review of HTTP Basic and Digest authentication and Recipe 15.6 for information on SOAP headers and how to handle them.

Example 15-10 shows how it's done using HTTP Basic authentication.

Authenticating using HTTP Basic authentication and a SOAP server

<?php // Your authentication logic // Which is probably decoupled from your SOAP Server function pc_authenticate_user($username, password) {     // authenticate user     $is_valid = true; // Implement your lookup here     if ($is_valid) {         return true;     } else {         return false;     } } class pc_SOAP_return_time {     public function __construct() {         // Throw SOAP fault for invalid username and password combo         if (! pc_authenticate_user($_SERVER['PHP_AUTH_USER'],                                    $_SERVER['PHP_AUTH_PW'])) {             throw new SOAPFault("Incorrect username and password combination.", 401);         }     }     // Rest of SOAP Server methods here... } $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time')); $server->setClass('pc_SOAP_return_time'); $server->handle(); ?>

Example 15-10 defines pc_authenticate_user( ). This function isn't SOAP specific, it's your standard code to handle user authentication. In this example, it's a separate function to emphasize its decoupled nature. However, you could also define this as a private method inside of pc_SOAP_return_time if you wanted to have it save state or access other object properties.

By defining a constructor for pc_SOAP_return_time, you force the SOAP server to execute that code before it handles any SOAP headers or the SOAP body. Inside of __construct( ), call out to pc_authenticate_user, passing the variables where PHP stores HTTP Basic Authentication credentials, $_SERVER['PHP_AUTH_USER'] and $_SERVER['PHP_AUTH_PW'].

If the authentication fails, throw a SOAP fault. Remember, you must send an HTTP Status Code of 500 on SOAP faults, so PHP will not return 401.

You can pass HTTP Basic authentication credentials like this:

<?php $opts = array('location' => 'http://api.example.org/getTime',               'uri' => 'urn:pc_SOAP_return_time',               'login' => 'elvis',               'password' => 'the-king', $client = new SOAPClient(null, $opts); $result = $client->__soapCall('return_time'); ?> 

The SOAPClient accepts the login and password options. These should be set to the proper username and password and ext/soap will do the rest to send them using HTTP Basic authentication.

The other option is to use not HTTP Basic authentication, but pass the username and password in a custom SOAP header. This allows you additional control over what information you gather and lets you extend into using a protocol other than HTTP.

The downside is that HTTP Basic authentication is a familiar concept, so people will need to learn how to construct your custom header.

Example 15-13 outlines the basic setup.

Authenticating using a SOAP header and a SOAP server

<?php // Your authentication logic // Which is probably decoupled from your SOAP Server function pc_authenticate_user($username, password) {     // authenticate user     $is_valid = true; // Implement your lookup here     if ($is_valid) {         return true;     } else {         return false;     } } class pc_SOAP_return_time {     private $authenticated;     public function __construct() {         $this->authenticated = false;     }     public function authenticate_user($args) {         // Throw SOAP fault for invalid username and password combo         if (! pc_authenticate_user($args->username,                                    $args->password)) {             throw new SOAPFault("Incorrect username and password combination.", 401);         }         $this->authenticated = true;     }     // Rest of SOAP Server methods here...     public function soap_method() {         if ($this->authenticated) {             // Method body here...         } else {             throw new SOAPFault("Must pass authenticate_user Header.", 401);         }     } } $server = new SOAPServer(null, array('uri'=>'urn:pc_SOAP_return_time')); $server->setClass('pc_SOAP_return_time'); $server->handle(); ?>

The pc_authenticate_user( ) function is identical, as there's no need for that low-level system to change merely because you altered the interface for passing the username and password.

However, instead of implementing the authentication check inside of the constructor, you place it inside a method named after your authentication header. Since there's no way to force ext/soap to require a SOAP header, use this method to set the authenticated property to TRue.

Then, make sure each of your SOAP body methods wraps the "real" code inside an if ($this->authenticated) check. If the SOAP client failed to pass the credentials, throw a SOAP fault.

Here's how you pass the credentials using SOAPClient:

<?php $opts = array('location' => 'http://api.example.org/getTime',               'uri' => 'urn:pc_SOAP_return_time'); $client = new SOAPClient(null, $opts); class SOAPAuth {     public $username;     public $password;     public function __construct($username, $password) {         $this->username = $username;         $this->password = $password;     } } $auth = new SOAPAuth('elvis', 'the-king'); $header = new SOAPHeader('urn:example.org/auth', 'authenticate_user', $auth); $result = $client->__soapCall('return_time', array(), array(), array($header)); ?>

The easiest way to create a SOAP header with both username and password variables is to create a simple class with properties with those names and then pass an instance of that class to SOAPHeader.

The entire SOAP header is then sent as the fourth argument in your __soapCall( ).

15.8.4. See Also

Recipe 14.8 for using authentication in a SOAP client; Recipe 8.9 for information on HTTP Basic and Digest authentication in general.




PHP Cookbook, 2nd Edition
PHP Cookbook: Solutions and Examples for PHP Programmers
ISBN: 0596101015
EAN: 2147483647
Year: 2006
Pages: 445

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net