<?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; } } ?>