TYPO3 API  SVNRelease
SReg.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /**
00004  * Simple registration request and response parsing and object
00005  * representation.
00006  *
00007  * This module contains objects representing simple registration
00008  * requests and responses that can be used with both OpenID relying
00009  * parties and OpenID providers.
00010  *
00011  * 1. The relying party creates a request object and adds it to the
00012  * {@link Auth_OpenID_AuthRequest} object before making the
00013  * checkid request to the OpenID provider:
00014  *
00015  *   $sreg_req = Auth_OpenID_SRegRequest::build(array('email'));
00016  *   $auth_request->addExtension($sreg_req);
00017  *
00018  * 2. The OpenID provider extracts the simple registration request
00019  * from the OpenID request using {@link
00020  * Auth_OpenID_SRegRequest::fromOpenIDRequest}, gets the user's
00021  * approval and data, creates an {@link Auth_OpenID_SRegResponse}
00022  * object and adds it to the id_res response:
00023  *
00024  *   $sreg_req = Auth_OpenID_SRegRequest::fromOpenIDRequest(
00025  *                                  $checkid_request);
00026  *   // [ get the user's approval and data, informing the user that
00027  *   //   the fields in sreg_response were requested ]
00028  *   $sreg_resp = Auth_OpenID_SRegResponse::extractResponse(
00029  *                                  $sreg_req, $user_data);
00030  *   $sreg_resp->toMessage($openid_response->fields);
00031  *
00032  * 3. The relying party uses {@link
00033  * Auth_OpenID_SRegResponse::fromSuccessResponse} to extract the data
00034  * from the OpenID response:
00035  *
00036  *   $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse(
00037  *                                  $success_response);
00038  *
00039  * @package OpenID
00040  */
00041 
00042 /**
00043  * Import message and extension internals.
00044  */
00045 require_once 'Auth/OpenID/Message.php';
00046 require_once 'Auth/OpenID/Extension.php';
00047 
00048 // The data fields that are listed in the sreg spec
00049 global $Auth_OpenID_sreg_data_fields;
00050 $Auth_OpenID_sreg_data_fields = array(
00051                                       'fullname' => 'Full Name',
00052                                       'nickname' => 'Nickname',
00053                                       'dob' => 'Date of Birth',
00054                                       'email' => 'E-mail Address',
00055                                       'gender' => 'Gender',
00056                                       'postcode' => 'Postal Code',
00057                                       'country' => 'Country',
00058                                       'language' => 'Language',
00059                                       'timezone' => 'Time Zone');
00060 
00061 /**
00062  * Check to see that the given value is a valid simple registration
00063  * data field name.  Return true if so, false if not.
00064  */
00065 function Auth_OpenID_checkFieldName($field_name)
00066 {
00067     global $Auth_OpenID_sreg_data_fields;
00068 
00069     if (!in_array($field_name, array_keys($Auth_OpenID_sreg_data_fields))) {
00070         return false;
00071     }
00072     return true;
00073 }
00074 
00075 // URI used in the wild for Yadis documents advertising simple
00076 // registration support
00077 define('Auth_OpenID_SREG_NS_URI_1_0', 'http://openid.net/sreg/1.0');
00078 
00079 // URI in the draft specification for simple registration 1.1
00080 // <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html>
00081 define('Auth_OpenID_SREG_NS_URI_1_1', 'http://openid.net/extensions/sreg/1.1');
00082 
00083 // This attribute will always hold the preferred URI to use when
00084 // adding sreg support to an XRDS file or in an OpenID namespace
00085 // declaration.
00086 define('Auth_OpenID_SREG_NS_URI', Auth_OpenID_SREG_NS_URI_1_1);
00087 
00088 Auth_OpenID_registerNamespaceAlias(Auth_OpenID_SREG_NS_URI_1_1, 'sreg');
00089 
00090 /**
00091  * Does the given endpoint advertise support for simple
00092  * registration?
00093  *
00094  * $endpoint: The endpoint object as returned by OpenID discovery.
00095  * returns whether an sreg type was advertised by the endpoint
00096  */
00097 function Auth_OpenID_supportsSReg(&$endpoint)
00098 {
00099     return ($endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_1) ||
00100             $endpoint->usesExtension(Auth_OpenID_SREG_NS_URI_1_0));
00101 }
00102 
00103 /**
00104  * A base class for classes dealing with Simple Registration protocol
00105  * messages.
00106  *
00107  * @package OpenID
00108  */
00109 class Auth_OpenID_SRegBase extends Auth_OpenID_Extension {
00110     /**
00111      * Extract the simple registration namespace URI from the given
00112      * OpenID message. Handles OpenID 1 and 2, as well as both sreg
00113      * namespace URIs found in the wild, as well as missing namespace
00114      * definitions (for OpenID 1)
00115      *
00116      * $message: The OpenID message from which to parse simple
00117      * registration fields. This may be a request or response message.
00118      *
00119      * Returns the sreg namespace URI for the supplied message. The
00120      * message may be modified to define a simple registration
00121      * namespace.
00122      *
00123      * @access private
00124      */
00125     function _getSRegNS(&$message)
00126     {
00127         $alias = null;
00128         $found_ns_uri = null;
00129 
00130         // See if there exists an alias for one of the two defined
00131         // simple registration types.
00132         foreach (array(Auth_OpenID_SREG_NS_URI_1_1,
00133                        Auth_OpenID_SREG_NS_URI_1_0) as $sreg_ns_uri) {
00134             $alias = $message->namespaces->getAlias($sreg_ns_uri);
00135             if ($alias !== null) {
00136                 $found_ns_uri = $sreg_ns_uri;
00137                 break;
00138             }
00139         }
00140 
00141         if ($alias === null) {
00142             // There is no alias for either of the types, so try to
00143             // add one. We default to using the modern value (1.1)
00144             $found_ns_uri = Auth_OpenID_SREG_NS_URI_1_1;
00145             if ($message->namespaces->addAlias(Auth_OpenID_SREG_NS_URI_1_1,
00146                                                'sreg') === null) {
00147                 // An alias for the string 'sreg' already exists, but
00148                 // it's defined for something other than simple
00149                 // registration
00150                 return null;
00151             }
00152         }
00153 
00154         return $found_ns_uri;
00155     }
00156 }
00157 
00158 /**
00159  * An object to hold the state of a simple registration request.
00160  *
00161  * required: A list of the required fields in this simple registration
00162  * request
00163  *
00164  * optional: A list of the optional fields in this simple registration
00165  * request
00166  *
00167  * @package OpenID
00168  */
00169 class Auth_OpenID_SRegRequest extends Auth_OpenID_SRegBase {
00170 
00171     var $ns_alias = 'sreg';
00172 
00173     /**
00174      * Initialize an empty simple registration request.
00175      */
00176     function build($required=null, $optional=null,
00177                    $policy_url=null,
00178                    $sreg_ns_uri=Auth_OpenID_SREG_NS_URI,
00179                    $cls='Auth_OpenID_SRegRequest')
00180     {
00181         $obj = new $cls();
00182 
00183         $obj->required = array();
00184         $obj->optional = array();
00185         $obj->policy_url = $policy_url;
00186         $obj->ns_uri = $sreg_ns_uri;
00187 
00188         if ($required) {
00189             if (!$obj->requestFields($required, true, true)) {
00190                 return null;
00191             }
00192         }
00193 
00194         if ($optional) {
00195             if (!$obj->requestFields($optional, false, true)) {
00196                 return null;
00197             }
00198         }
00199 
00200         return $obj;
00201     }
00202 
00203     /**
00204      * Create a simple registration request that contains the fields
00205      * that were requested in the OpenID request with the given
00206      * arguments
00207      *
00208      * $request: The OpenID authentication request from which to
00209      * extract an sreg request.
00210      *
00211      * $cls: name of class to use when creating sreg request object.
00212      * Used for testing.
00213      *
00214      * Returns the newly created simple registration request
00215      */
00216     function fromOpenIDRequest($request, $cls='Auth_OpenID_SRegRequest')
00217     {
00218 
00219         $obj = call_user_func_array(array($cls, 'build'),
00220                  array(null, null, null, Auth_OpenID_SREG_NS_URI, $cls));
00221 
00222         // Since we're going to mess with namespace URI mapping, don't
00223         // mutate the object that was passed in.
00224         $m = $request->message;
00225 
00226         $obj->ns_uri = $obj->_getSRegNS($m);
00227         $args = $m->getArgs($obj->ns_uri);
00228 
00229         if ($args === null || Auth_OpenID::isFailure($args)) {
00230             return null;
00231         }
00232 
00233         $obj->parseExtensionArgs($args);
00234 
00235         return $obj;
00236     }
00237 
00238     /**
00239      * Parse the unqualified simple registration request parameters
00240      * and add them to this object.
00241      *
00242      * This method is essentially the inverse of
00243      * getExtensionArgs. This method restores the serialized simple
00244      * registration request fields.
00245      *
00246      * If you are extracting arguments from a standard OpenID
00247      * checkid_* request, you probably want to use fromOpenIDRequest,
00248      * which will extract the sreg namespace and arguments from the
00249      * OpenID request. This method is intended for cases where the
00250      * OpenID server needs more control over how the arguments are
00251      * parsed than that method provides.
00252      *
00253      * $args == $message->getArgs($ns_uri);
00254      * $request->parseExtensionArgs($args);
00255      *
00256      * $args: The unqualified simple registration arguments
00257      *
00258      * strict: Whether requests with fields that are not defined in
00259      * the simple registration specification should be tolerated (and
00260      * ignored)
00261      */
00262     function parseExtensionArgs($args, $strict=false)
00263     {
00264         foreach (array('required', 'optional') as $list_name) {
00265             $required = ($list_name == 'required');
00266             $items = Auth_OpenID::arrayGet($args, $list_name);
00267             if ($items) {
00268                 foreach (explode(',', $items) as $field_name) {
00269                     if (!$this->requestField($field_name, $required, $strict)) {
00270                         if ($strict) {
00271                             return false;
00272                         }
00273                     }
00274                 }
00275             }
00276         }
00277 
00278         $this->policy_url = Auth_OpenID::arrayGet($args, 'policy_url');
00279 
00280         return true;
00281     }
00282 
00283     /**
00284      * A list of all of the simple registration fields that were
00285      * requested, whether they were required or optional.
00286      */
00287     function allRequestedFields()
00288     {
00289         return array_merge($this->required, $this->optional);
00290     }
00291 
00292     /**
00293      * Have any simple registration fields been requested?
00294      */
00295     function wereFieldsRequested()
00296     {
00297         return count($this->allRequestedFields());
00298     }
00299 
00300     /**
00301      * Was this field in the request?
00302      */
00303     function contains($field_name)
00304     {
00305         return (in_array($field_name, $this->required) ||
00306                 in_array($field_name, $this->optional));
00307     }
00308 
00309     /**
00310      * Request the specified field from the OpenID user
00311      *
00312      * $field_name: the unqualified simple registration field name
00313      *
00314      * required: whether the given field should be presented to the
00315      * user as being a required to successfully complete the request
00316      *
00317      * strict: whether to raise an exception when a field is added to
00318      * a request more than once
00319      */
00320     function requestField($field_name,
00321                           $required=false, $strict=false)
00322     {
00323         if (!Auth_OpenID_checkFieldName($field_name)) {
00324             return false;
00325         }
00326 
00327         if ($strict) {
00328             if ($this->contains($field_name)) {
00329                 return false;
00330             }
00331         } else {
00332             if (in_array($field_name, $this->required)) {
00333                 return true;
00334             }
00335 
00336             if (in_array($field_name, $this->optional)) {
00337                 if ($required) {
00338                     unset($this->optional[array_search($field_name,
00339                                                        $this->optional)]);
00340                 } else {
00341                     return true;
00342                 }
00343             }
00344         }
00345 
00346         if ($required) {
00347             $this->required[] = $field_name;
00348         } else {
00349             $this->optional[] = $field_name;
00350         }
00351 
00352         return true;
00353     }
00354 
00355     /**
00356      * Add the given list of fields to the request
00357      *
00358      * field_names: The simple registration data fields to request
00359      *
00360      * required: Whether these values should be presented to the user
00361      * as required
00362      *
00363      * strict: whether to raise an exception when a field is added to
00364      * a request more than once
00365      */
00366     function requestFields($field_names, $required=false, $strict=false)
00367     {
00368         if (!is_array($field_names)) {
00369             return false;
00370         }
00371 
00372         foreach ($field_names as $field_name) {
00373             if (!$this->requestField($field_name, $required, $strict=$strict)) {
00374                 return false;
00375             }
00376         }
00377 
00378         return true;
00379     }
00380 
00381     /**
00382      * Get a dictionary of unqualified simple registration arguments
00383      * representing this request.
00384      *
00385      * This method is essentially the inverse of
00386      * C{L{parseExtensionArgs}}. This method serializes the simple
00387      * registration request fields.
00388      */
00389     function getExtensionArgs()
00390     {
00391         $args = array();
00392 
00393         if ($this->required) {
00394             $args['required'] = implode(',', $this->required);
00395         }
00396 
00397         if ($this->optional) {
00398             $args['optional'] = implode(',', $this->optional);
00399         }
00400 
00401         if ($this->policy_url) {
00402             $args['policy_url'] = $this->policy_url;
00403         }
00404 
00405         return $args;
00406     }
00407 }
00408 
00409 /**
00410  * Represents the data returned in a simple registration response
00411  * inside of an OpenID C{id_res} response. This object will be created
00412  * by the OpenID server, added to the C{id_res} response object, and
00413  * then extracted from the C{id_res} message by the Consumer.
00414  *
00415  * @package OpenID
00416  */
00417 class Auth_OpenID_SRegResponse extends Auth_OpenID_SRegBase {
00418 
00419     var $ns_alias = 'sreg';
00420 
00421     function Auth_OpenID_SRegResponse($data=null,
00422                                       $sreg_ns_uri=Auth_OpenID_SREG_NS_URI)
00423     {
00424         if ($data === null) {
00425             $this->data = array();
00426         } else {
00427             $this->data = $data;
00428         }
00429 
00430         $this->ns_uri = $sreg_ns_uri;
00431     }
00432 
00433     /**
00434      * Take a C{L{SRegRequest}} and a dictionary of simple
00435      * registration values and create a C{L{SRegResponse}} object
00436      * containing that data.
00437      *
00438      * request: The simple registration request object
00439      *
00440      * data: The simple registration data for this response, as a
00441      * dictionary from unqualified simple registration field name to
00442      * string (unicode) value. For instance, the nickname should be
00443      * stored under the key 'nickname'.
00444      */
00445     function extractResponse($request, $data)
00446     {
00447         $obj = new Auth_OpenID_SRegResponse();
00448         $obj->ns_uri = $request->ns_uri;
00449 
00450         foreach ($request->allRequestedFields() as $field) {
00451             $value = Auth_OpenID::arrayGet($data, $field);
00452             if ($value !== null) {
00453                 $obj->data[$field] = $value;
00454             }
00455         }
00456 
00457         return $obj;
00458     }
00459 
00460     /**
00461      * Create a C{L{SRegResponse}} object from a successful OpenID
00462      * library response
00463      * (C{L{openid.consumer.consumer.SuccessResponse}}) response
00464      * message
00465      *
00466      * success_response: A SuccessResponse from consumer.complete()
00467      *
00468      * signed_only: Whether to process only data that was
00469      * signed in the id_res message from the server.
00470      *
00471      * Returns a simple registration response containing the data that
00472      * was supplied with the C{id_res} response.
00473      */
00474     function fromSuccessResponse(&$success_response, $signed_only=true)
00475     {
00476         global $Auth_OpenID_sreg_data_fields;
00477 
00478         $obj = new Auth_OpenID_SRegResponse();
00479         $obj->ns_uri = $obj->_getSRegNS($success_response->message);
00480 
00481         if ($signed_only) {
00482             $args = $success_response->getSignedNS($obj->ns_uri);
00483         } else {
00484             $args = $success_response->message->getArgs($obj->ns_uri);
00485         }
00486 
00487         if ($args === null || Auth_OpenID::isFailure($args)) {
00488             return null;
00489         }
00490 
00491         foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) {
00492             if (in_array($field_name, array_keys($args))) {
00493                 $obj->data[$field_name] = $args[$field_name];
00494             }
00495         }
00496 
00497         return $obj;
00498     }
00499 
00500     function getExtensionArgs()
00501     {
00502         return $this->data;
00503     }
00504 
00505     // Read-only dictionary interface
00506     function get($field_name, $default=null)
00507     {
00508         if (!Auth_OpenID_checkFieldName($field_name)) {
00509             return null;
00510         }
00511 
00512         return Auth_OpenID::arrayGet($this->data, $field_name, $default);
00513     }
00514 
00515     function contents()
00516     {
00517         return $this->data;
00518     }
00519 }
00520 
00521 ?>