522 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			522 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
|  | <?php | ||
|  | 
 | ||
|  | /** | ||
|  |  * Simple registration request and response parsing and object | ||
|  |  * representation. | ||
|  |  * | ||
|  |  * This module contains objects representing simple registration | ||
|  |  * requests and responses that can be used with both OpenID relying | ||
|  |  * parties and OpenID providers. | ||
|  |  * | ||
|  |  * 1. The relying party creates a request object and adds it to the | ||
|  |  * {@link Auth_OpenID_AuthRequest} object before making the | ||
|  |  * checkid request to the OpenID provider: | ||
|  |  * | ||
|  |  *   $sreg_req = Auth_OpenID_SRegRequest::build(array('email')); | ||
|  |  *   $auth_request->addExtension($sreg_req); | ||
|  |  * | ||
|  |  * 2. The OpenID provider extracts the simple registration request | ||
|  |  * from the OpenID request using {@link | ||
|  |  * Auth_OpenID_SRegRequest::fromOpenIDRequest}, gets the user's | ||
|  |  * approval and data, creates an {@link Auth_OpenID_SRegResponse} | ||
|  |  * object and adds it to the id_res response: | ||
|  |  * | ||
|  |  *   $sreg_req = Auth_OpenID_SRegRequest::fromOpenIDRequest( | ||
|  |  *                                  $checkid_request); | ||
|  |  *   // [ get the user's approval and data, informing the user that
 | ||
|  |  *   //   the fields in sreg_response were requested ]
 | ||
|  |  *   $sreg_resp = Auth_OpenID_SRegResponse::extractResponse( | ||
|  |  *                                  $sreg_req, $user_data); | ||
|  |  *   $sreg_resp->toMessage($openid_response->fields); | ||
|  |  * | ||
|  |  * 3. The relying party uses {@link | ||
|  |  * Auth_OpenID_SRegResponse::fromSuccessResponse} to extract the data | ||
|  |  * from the OpenID response: | ||
|  |  * | ||
|  |  *   $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse( | ||
|  |  *                                  $success_response); | ||
|  |  * | ||
|  |  * @package OpenID | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * Import message and extension internals. | ||
|  |  */ | ||
|  | require_once 'Auth/OpenID/Message.php'; | ||
|  | require_once 'Auth/OpenID/Extension.php'; | ||
|  | 
 | ||
|  | // The data fields that are listed in the sreg spec
 | ||
|  | global $Auth_OpenID_sreg_data_fields; | ||
|  | $Auth_OpenID_sreg_data_fields = array( | ||
|  |                                       'fullname' => 'Full Name', | ||
|  |                                       'nickname' => 'Nickname', | ||
|  |                                       'dob' => 'Date of Birth', | ||
|  |                                       'email' => 'E-mail Address', | ||
|  |                                       'gender' => 'Gender', | ||
|  |                                       'postcode' => 'Postal Code', | ||
|  |                                       'country' => 'Country', | ||
|  |                                       'language' => 'Language', | ||
|  |                                       'timezone' => 'Time Zone'); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Check to see that the given value is a valid simple registration | ||
|  |  * data field name.  Return true if so, false if not. | ||
|  |  */ | ||
|  | function Auth_OpenID_checkFieldName($field_name) | ||
|  | { | ||
|  |     global $Auth_OpenID_sreg_data_fields; | ||
|  | 
 | ||
|  |     if (!in_array($field_name, array_keys($Auth_OpenID_sreg_data_fields))) { | ||
|  |         return false; | ||
|  |     } | ||
|  |     return true; | ||
|  | } | ||
|  | 
 | ||
|  | // URI used in the wild for Yadis documents advertising simple
 | ||
|  | // registration support
 | ||
|  | define('Auth_OpenID_SREG_NS_URI_1_0', 'http://openid.net/sreg/1.0'); | ||
|  | 
 | ||
|  | // URI in the draft specification for simple registration 1.1
 | ||
|  | // <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html>
 | ||
|  | define('Auth_OpenID_SREG_NS_URI_1_1', 'http://openid.net/extensions/sreg/1.1'); | ||
|  | 
 | ||
|  | // This attribute will always hold the preferred URI to use when
 | ||
|  | // adding sreg support to an XRDS file or in an OpenID namespace
 | ||
|  | // declaration.
 | ||
|  | define('Auth_OpenID_SREG_NS_URI', Auth_OpenID_SREG_NS_URI_1_1); | ||
|  | 
 | ||
|  | Auth_OpenID_registerNamespaceAlias(Auth_OpenID_SREG_NS_URI_1_1, 'sreg'); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Does the given endpoint advertise support for simple | ||
|  |  * registration? | ||
|  |  * | ||
|  |  * $endpoint: The endpoint object as returned by OpenID discovery. | ||
|  |  * returns whether an sreg type was advertised by the endpoint | ||
|  |  */ | ||
|  | function Auth_OpenID_supportsSReg(&$endpoint) | ||
|  | { | ||
|  |     return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) || | ||
|  |             $endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0)); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * A base class for classes dealing with Simple Registration protocol | ||
|  |  * messages. | ||
|  |  * | ||
|  |  * @package OpenID | ||
|  |  */ | ||
|  | class Auth_OpenID_SRegBase extends Auth_OpenID_Extension { | ||
|  |     /** | ||
|  |      * Extract the simple registration namespace URI from the given | ||
|  |      * OpenID message. Handles OpenID 1 and 2, as well as both sreg | ||
|  |      * namespace URIs found in the wild, as well as missing namespace | ||
|  |      * definitions (for OpenID 1) | ||
|  |      * | ||
|  |      * $message: The OpenID message from which to parse simple | ||
|  |      * registration fields. This may be a request or response message. | ||
|  |      * | ||
|  |      * Returns the sreg namespace URI for the supplied message. The | ||
|  |      * message may be modified to define a simple registration | ||
|  |      * namespace. | ||
|  |      * | ||
|  |      * @access private | ||
|  |      */ | ||
|  |     function _getSRegNS(&$message) | ||
|  |     { | ||
|  |         $alias = null; | ||
|  |         $found_ns_uri = null; | ||
|  | 
 | ||
|  |         // See if there exists an alias for one of the two defined
 | ||
|  |         // simple registration types.
 | ||
|  |         foreach (array(Auth_OpenID_SREG_NS_URI_1_1, | ||
|  |                        Auth_OpenID_SREG_NS_URI_1_0) as $sreg_ns_uri) { | ||
|  |             $alias = $message->namespaces->getAlias($sreg_ns_uri); | ||
|  |             if ($alias !== null) { | ||
|  |                 $found_ns_uri = $sreg_ns_uri; | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($alias === null) { | ||
|  |             // There is no alias for either of the types, so try to
 | ||
|  |             // add one. We default to using the modern value (1.1)
 | ||
|  |             $found_ns_uri = Auth_OpenID_SREG_NS_URI_1_1; | ||
|  |             if ($message->namespaces->addAlias(Auth_OpenID_SREG_NS_URI_1_1, | ||
|  |                                                'sreg') === null) { | ||
|  |                 // An alias for the string 'sreg' already exists, but
 | ||
|  |                 // it's defined for something other than simple
 | ||
|  |                 // registration
 | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return $found_ns_uri; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * An object to hold the state of a simple registration request. | ||
|  |  * | ||
|  |  * required: A list of the required fields in this simple registration | ||
|  |  * request | ||
|  |  * | ||
|  |  * optional: A list of the optional fields in this simple registration | ||
|  |  * request | ||
|  |  * | ||
|  |  * @package OpenID | ||
|  |  */ | ||
|  | class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase { | ||
|  | 
 | ||
|  |     var $ns_alias = 'sreg'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Initialize an empty simple registration request. | ||
|  |      */ | ||
|  |     function build($required=null, $optional=null, | ||
|  |                    $policy_url=null, | ||
|  |                    $sreg_ns_uri=Auth_OpenID_SREG_NS_URI, | ||
|  |                    $cls='Auth_OpenID_SRegRequest') | ||
|  |     { | ||
|  |         $obj = new $cls(); | ||
|  | 
 | ||
|  |         $obj->required = array(); | ||
|  |         $obj->optional = array(); | ||
|  |         $obj->policy_url = $policy_url; | ||
|  |         $obj->ns_uri = $sreg_ns_uri; | ||
|  | 
 | ||
|  |         if ($required) { | ||
|  |             if (!$obj->requestFields($required, true, true)) { | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($optional) { | ||
|  |             if (!$obj->requestFields($optional, false, true)) { | ||
|  |                 return null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return $obj; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Create a simple registration request that contains the fields | ||
|  |      * that were requested in the OpenID request with the given | ||
|  |      * arguments | ||
|  |      * | ||
|  |      * $request: The OpenID authentication request from which to | ||
|  |      * extract an sreg request. | ||
|  |      * | ||
|  |      * $cls: name of class to use when creating sreg request object. | ||
|  |      * Used for testing. | ||
|  |      * | ||
|  |      * Returns the newly created simple registration request | ||
|  |      */ | ||
|  |     function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest') | ||
|  |     { | ||
|  | 
 | ||
|  |         $obj = call_user_func_array(array($cls, 'build'), | ||
|  |                  array(null, null, null, Auth_OpenID_SREG_NS_URI, $cls)); | ||
|  | 
 | ||
|  |         // Since we're going to mess with namespace URI mapping, don't
 | ||
|  |         // mutate the object that was passed in.
 | ||
|  |         $m = $request->message; | ||
|  | 
 | ||
|  |         $obj->ns_uri = $obj->_getSRegNS($m); | ||
|  |         $args = $m->getArgs($obj->ns_uri); | ||
|  | 
 | ||
|  |         if ($args === null || Auth_OpenID::isFailure($args)) { | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         $obj->parseExtensionArgs($args); | ||
|  | 
 | ||
|  |         return $obj; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Parse the unqualified simple registration request parameters | ||
|  |      * and add them to this object. | ||
|  |      * | ||
|  |      * This method is essentially the inverse of | ||
|  |      * getExtensionArgs. This method restores the serialized simple | ||
|  |      * registration request fields. | ||
|  |      * | ||
|  |      * If you are extracting arguments from a standard OpenID | ||
|  |      * checkid_* request, you probably want to use fromOpenIDRequest, | ||
|  |      * which will extract the sreg namespace and arguments from the | ||
|  |      * OpenID request. This method is intended for cases where the | ||
|  |      * OpenID server needs more control over how the arguments are | ||
|  |      * parsed than that method provides. | ||
|  |      * | ||
|  |      * $args == $message->getArgs($ns_uri); | ||
|  |      * $request->parseExtensionArgs($args); | ||
|  |      * | ||
|  |      * $args: The unqualified simple registration arguments | ||
|  |      * | ||
|  |      * strict: Whether requests with fields that are not defined in | ||
|  |      * the simple registration specification should be tolerated (and | ||
|  |      * ignored) | ||
|  |      */ | ||
|  |     function parseExtensionArgs($args, $strict=false) | ||
|  |     { | ||
|  |         foreach (array('required', 'optional') as $list_name) { | ||
|  |             $required = ($list_name == 'required'); | ||
|  |             $items = Auth_OpenID::arrayGet($args, $list_name); | ||
|  |             if ($items) { | ||
|  |                 foreach (explode(',', $items) as $field_name) { | ||
|  |                     if (!$this->requestField($field_name, $required, $strict)) { | ||
|  |                         if ($strict) { | ||
|  |                             return false; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         $this->policy_url = Auth_OpenID::arrayGet($args, 'policy_url'); | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * A list of all of the simple registration fields that were | ||
|  |      * requested, whether they were required or optional. | ||
|  |      */ | ||
|  |     function allRequestedFields() | ||
|  |     { | ||
|  |         return array_merge($this->required, $this->optional); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Have any simple registration fields been requested? | ||
|  |      */ | ||
|  |     function wereFieldsRequested() | ||
|  |     { | ||
|  |         return count($this->allRequestedFields()); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Was this field in the request? | ||
|  |      */ | ||
|  |     function contains($field_name) | ||
|  |     { | ||
|  |         return (in_array($field_name, $this->required) || | ||
|  |                 in_array($field_name, $this->optional)); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Request the specified field from the OpenID user | ||
|  |      * | ||
|  |      * $field_name: the unqualified simple registration field name | ||
|  |      * | ||
|  |      * required: whether the given field should be presented to the | ||
|  |      * user as being a required to successfully complete the request | ||
|  |      * | ||
|  |      * strict: whether to raise an exception when a field is added to | ||
|  |      * a request more than once | ||
|  |      */ | ||
|  |     function requestField($field_name, | ||
|  |                           $required=false, $strict=false) | ||
|  |     { | ||
|  |         if (!Auth_OpenID_checkFieldName($field_name)) { | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($strict) { | ||
|  |             if ($this->contains($field_name)) { | ||
|  |                 return false; | ||
|  |             } | ||
|  |         } else { | ||
|  |             if (in_array($field_name, $this->required)) { | ||
|  |                 return true; | ||
|  |             } | ||
|  | 
 | ||
|  |             if (in_array($field_name, $this->optional)) { | ||
|  |                 if ($required) { | ||
|  |                     unset($this->optional[array_search($field_name, | ||
|  |                                                        $this->optional)]); | ||
|  |                 } else { | ||
|  |                     return true; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($required) { | ||
|  |             $this->required[] = $field_name; | ||
|  |         } else { | ||
|  |             $this->optional[] = $field_name; | ||
|  |         } | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Add the given list of fields to the request | ||
|  |      * | ||
|  |      * field_names: The simple registration data fields to request | ||
|  |      * | ||
|  |      * required: Whether these values should be presented to the user | ||
|  |      * as required | ||
|  |      * | ||
|  |      * strict: whether to raise an exception when a field is added to | ||
|  |      * a request more than once | ||
|  |      */ | ||
|  |     function requestFields($field_names, $required=false, $strict=false) | ||
|  |     { | ||
|  |         if (!is_array($field_names)) { | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         foreach ($field_names as $field_name) { | ||
|  |             if (!$this->requestField($field_name, $required, $strict=$strict)) { | ||
|  |                 return false; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Get a dictionary of unqualified simple registration arguments | ||
|  |      * representing this request. | ||
|  |      * | ||
|  |      * This method is essentially the inverse of | ||
|  |      * C{L{parseExtensionArgs}}. This method serializes the simple | ||
|  |      * registration request fields. | ||
|  |      */ | ||
|  |     function getExtensionArgs() | ||
|  |     { | ||
|  |         $args = array(); | ||
|  | 
 | ||
|  |         if ($this->required) { | ||
|  |             $args['required'] = implode(',', $this->required); | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($this->optional) { | ||
|  |             $args['optional'] = implode(',', $this->optional); | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($this->policy_url) { | ||
|  |             $args['policy_url'] = $this->policy_url; | ||
|  |         } | ||
|  | 
 | ||
|  |         return $args; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Represents the data returned in a simple registration response | ||
|  |  * inside of an OpenID C{id_res} response. This object will be created | ||
|  |  * by the OpenID server, added to the C{id_res} response object, and | ||
|  |  * then extracted from the C{id_res} message by the Consumer. | ||
|  |  * | ||
|  |  * @package OpenID | ||
|  |  */ | ||
|  | class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase { | ||
|  | 
 | ||
|  |     var $ns_alias = 'sreg'; | ||
|  | 
 | ||
|  |     function Auth_OpenID_SRegResponse($data=null, | ||
|  |                                       $sreg_ns_uri=Auth_OpenID_SREG_NS_URI) | ||
|  |     { | ||
|  |         if ($data === null) { | ||
|  |             $this->data = array(); | ||
|  |         } else { | ||
|  |             $this->data = $data; | ||
|  |         } | ||
|  | 
 | ||
|  |         $this->ns_uri = $sreg_ns_uri; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Take a C{L{SRegRequest}} and a dictionary of simple | ||
|  |      * registration values and create a C{L{SRegResponse}} object | ||
|  |      * containing that data. | ||
|  |      * | ||
|  |      * request: The simple registration request object | ||
|  |      * | ||
|  |      * data: The simple registration data for this response, as a | ||
|  |      * dictionary from unqualified simple registration field name to | ||
|  |      * string (unicode) value. For instance, the nickname should be | ||
|  |      * stored under the key 'nickname'. | ||
|  |      */ | ||
|  |     function extractResponse($request, $data) | ||
|  |     { | ||
|  |         $obj = new Auth_OpenID_SRegResponse(); | ||
|  |         $obj->ns_uri = $request->ns_uri; | ||
|  | 
 | ||
|  |         foreach ($request->allRequestedFields() as $field) { | ||
|  |             $value = Auth_OpenID::arrayGet($data, $field); | ||
|  |             if ($value !== null) { | ||
|  |                 $obj->data[$field] = $value; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return $obj; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Create a C{L{SRegResponse}} object from a successful OpenID | ||
|  |      * library response | ||
|  |      * (C{L{openid.consumer.consumer.SuccessResponse}}) response | ||
|  |      * message | ||
|  |      * | ||
|  |      * success_response: A SuccessResponse from consumer.complete() | ||
|  |      * | ||
|  |      * signed_only: Whether to process only data that was | ||
|  |      * signed in the id_res message from the server. | ||
|  |      * | ||
|  |      * Returns a simple registration response containing the data that | ||
|  |      * was supplied with the C{id_res} response. | ||
|  |      */ | ||
|  |     function fromSuccessResponse(&$success_response, $signed_only=true) | ||
|  |     { | ||
|  |         global $Auth_OpenID_sreg_data_fields; | ||
|  | 
 | ||
|  |         $obj = new Auth_OpenID_SRegResponse(); | ||
|  |         $obj->ns_uri = $obj->_getSRegNS($success_response->message); | ||
|  | 
 | ||
|  |         if ($signed_only) { | ||
|  |             $args = $success_response->getSignedNS($obj->ns_uri); | ||
|  |         } else { | ||
|  |             $args = $success_response->message->getArgs($obj->ns_uri); | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($args === null || Auth_OpenID::isFailure($args)) { | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) { | ||
|  |             if (in_array($field_name, array_keys($args))) { | ||
|  |                 $obj->data[$field_name] = $args[$field_name]; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return $obj; | ||
|  |     } | ||
|  | 
 | ||
|  |     function getExtensionArgs() | ||
|  |     { | ||
|  |         return $this->data; | ||
|  |     } | ||
|  | 
 | ||
|  |     // Read-only dictionary interface
 | ||
|  |     function get($field_name, $default=null) | ||
|  |     { | ||
|  |         if (!Auth_OpenID_checkFieldName($field_name)) { | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         return Auth_OpenID::arrayGet($this->data, $field_name, $default); | ||
|  |     } | ||
|  | 
 | ||
|  |     function contents() | ||
|  |     { | ||
|  |         return $this->data; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | ?>
 |