|
<?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 |
|
*/ |
|
static 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. |
|
*/ |
|
static 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 |
|
*/ |
|
static 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; |
|
} |
|
} |
|