diff options
-rw-r--r-- | Auth/OpenID/Extension.php | 47 | ||||
-rw-r--r-- | Auth/OpenID/Message.php | 20 | ||||
-rw-r--r-- | Auth/OpenID/SReg.php | 530 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Consumer.php | 6 | ||||
-rw-r--r-- | Tests/Auth/OpenID/SReg.php | 642 | ||||
-rw-r--r-- | Tests/TestDriver.php | 1 |
6 files changed, 1241 insertions, 5 deletions
diff --git a/Auth/OpenID/Extension.php b/Auth/OpenID/Extension.php new file mode 100644 index 0000000..6f943c2 --- /dev/null +++ b/Auth/OpenID/Extension.php @@ -0,0 +1,47 @@ +<?php + +/** + * An interface for OpenID extensions. + */ + +require_once 'Auth/OpenID/Message.php'; + +class Auth_OpenID_Extension { + /** + * ns_uri: The namespace to which to add the arguments for this + * extension + */ + var $ns_uri = null; + var $ns_alias = null; + + /** + * Get the string arguments that should be added to an OpenID + * message for this extension. + */ + function getExtensionArgs() + { + return null; + } + + /** + * Add the arguments from this extension to the provided message. + * + * Returns the message with the extension arguments added. + */ + function toMessage(&$message) + { + if ($message->namespaces->addAlias($this->ns_uri, + $this->ns_alias) === null) { + if ($message->namespaces->getAlias($this->ns_uri) != + $this->ns_alias) { + return null; + } + } + + $message->updateArgs($this->ns_uri, + $this->getExtensionArgs()); + return $message; + } +} + +?>
\ No newline at end of file diff --git a/Auth/OpenID/Message.php b/Auth/OpenID/Message.php index a9a7d21..cdc4d65 100644 --- a/Auth/OpenID/Message.php +++ b/Auth/OpenID/Message.php @@ -74,7 +74,7 @@ function Auth_OpenID_registerNamespaceAlias($namespace_uri, $alias) return false; } - if (in_array($alias, $Auth_OpenID_registered_aliases)) { + if (in_array($alias, array_keys($Auth_OpenID_registered_aliases))) { return false; } @@ -83,6 +83,24 @@ function Auth_OpenID_registerNamespaceAlias($namespace_uri, $alias) } /** + * Removes a (namespace_uri, alias) registration from the global + * namespace alias map. Returns true if the removal succeeded; false + * if not (if the mapping did not exist). + */ +function Auth_OpenID_removeNamespaceAlias($namespace_uri, $alias) +{ + global $Auth_OpenID_registered_aliases; + + if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases, + $alias) === $namespace_uri) { + unset($Auth_OpenID_registered_aliases[$alias]); + return true; + } + + return false; +} + +/** * An Auth_OpenID_Mapping maintains a mapping from arbitrary keys to * arbitrary values. (This is unlike an ordinary PHP array, whose * keys may be only simple scalars.) diff --git a/Auth/OpenID/SReg.php b/Auth/OpenID/SReg.php new file mode 100644 index 0000000..e7051e1 --- /dev/null +++ b/Auth/OpenID/SReg.php @@ -0,0 +1,530 @@ +<?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 + * C{L{AuthRequest<openid.consumer.consumer.AuthRequest>}} object + * before making the C{checkid_} request to the OpenID provider:: + * + * auth_request.addExtension(SRegRequest(required=['email'])) + * + * 2. The OpenID provider extracts the simple registration request from + * the OpenID request using C{L{SRegRequest.fromOpenIDRequest}}, + * gets the user's approval and data, creates a C{L{SRegResponse}} + * object and adds it to the C{id_res} response:: + * + * sreg_req = SRegRequest.fromOpenIDRequest(checkid_request.message) + * // [ get the user's approval and data, informing the user that + * // the fields in sreg_response were requested ] + * sreg_resp = SRegResponse.extractResponse(sreg_req, user_data) + * sreg_resp.addToOpenIDResponse(openid_response) + * + * 3. The relying party uses C{L{SRegResponse.fromSuccessResponse}} to + * extract the data from the OpenID response:: + * + * sreg_resp = SRegResponse.fromSuccessResponse(success_response) + */ + +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)); +} + +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. + */ + 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 + * + * @ivar policy_url: The policy URL that was provided with the request + */ +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) + { + $obj = new Auth_OpenID_SRegRequest(); + + $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 + * + * $message: The arguments that were given for this OpenID + * authentication request + * + * Returns the newly created simple registration request + */ + function fromOpenIDRequest($message) + { + $obj = Auth_OpenID_SRegRequest::build(); + + // Since we're going to mess with namespace URI mapping, don't + // mutate the object that was passed in. + $m = $message; + + $obj->ns_uri = $obj->_getSRegNS($m); + $args = $m->getArgs($obj->ns_uri); + + if ($args === null) { + 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 + * C{L{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 + * C{L{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. + */ +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) { + 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; + } + + /** + * Add the data fields contained in this simple registration + * response to the supplied message, in the appropriate namespace. + * + * response_message: The OpenID id_res response message that will + * be returned to the relying party + * + * Returns nothing; updates the response_message + */ + function addToOpenIDResponse(&$response_message) + { + $response_message->updateArgs($this->ns_uri, $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; + } +} + +/** + * Convenience function for copying all the sreg data that was + * requested from a supplied set of sreg data into the response + * message. If no data were requested, no data will be sent. + * + * openid_request: The OpenID (checkid_*) request that may be + * requesting sreg data. + * + * data: The simple registration data to send. All requested fields + * that are present in this dictionary will be added to the response + * message. + * + * openid_response: The OpenID C{id_res} response to which the simple + * registration data should be added + * + * Does not return a value; updates the openid_response instead. + */ +function Auth_OpenID_sendSRegFields(&$openid_request, $data, &$openid_response) +{ + $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest( + $openid_request->message); + $sreg_response = Auth_OpenID_SRegResponse::extractResponse( + $sreg_request, $data); + $sreg_response->addToOpenIDResponse($openid_response->fields); +} + +?>
\ No newline at end of file diff --git a/Tests/Auth/OpenID/Consumer.php b/Tests/Auth/OpenID/Consumer.php index 249886a..fae98aa 100644 --- a/Tests/Auth/OpenID/Consumer.php +++ b/Tests/Auth/OpenID/Consumer.php @@ -23,6 +23,7 @@ require_once 'Auth/OpenID/KVForm.php'; require_once 'Auth/OpenID/Consumer.php'; require_once 'Auth/OpenID/Server.php'; require_once 'Auth/OpenID/Nonce.php'; +require_once 'Auth/OpenID/SReg.php'; require_once 'Auth/OpenID/Message.php'; require_once 'Auth/OpenID/HMACSHA1.php'; require_once 'Tests/Auth/OpenID/MemStore.php'; @@ -1450,15 +1451,12 @@ class Tests_Auth_OpenID_SuccessResponse extends PHPUnit_TestCase { 'openid.sreg.nickname' => 'j3h', 'openid.return_to' => 'return_to'); - $temp_sreg_uri = 'bogus'; - $this->assertTrue(Auth_OpenID_registerNamespaceAlias($temp_sreg_uri, 'sreg')); - $message = Auth_OpenID_Message::fromPostArgs($query); $resp = new Auth_OpenID_SuccessResponse($this->endpoint, $message); $utargs = $resp->extensionResponse($uri, false); $this->assertEquals($utargs, array('one' => '1', 'two' => '2')); - $sregargs = $resp->extensionResponse($temp_sreg_uri, false); + $sregargs = $resp->extensionResponse(Auth_OpenID_SREG_NS_URI, false); $this->assertEquals($sregargs, array('nickname' => 'j3h')); } diff --git a/Tests/Auth/OpenID/SReg.php b/Tests/Auth/OpenID/SReg.php new file mode 100644 index 0000000..f807aa6 --- /dev/null +++ b/Tests/Auth/OpenID/SReg.php @@ -0,0 +1,642 @@ +<?php + +/** + * SReg.php testing code. + */ + +require_once 'Auth/OpenID/SReg.php'; +require_once 'Auth/OpenID/Message.php'; +require_once 'Auth/OpenID/Server.php'; + +require_once 'PHPUnit.php'; + +class SRegURITest extends PHPUnit_TestCase { + function test_is11() + { + $this->assertEquals(Auth_OpenID_SREG_NS_URI_1_1, + Auth_OpenID_SREG_NS_URI); + } +} + +class CheckFieldNameTest extends PHPUnit_TestCase { + function test_goodNamePasses() + { + global $Auth_OpenID_sreg_data_fields; + + foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) { + $this->assertTrue(Auth_OpenID_checkFieldName($field_name)); + } + } + + function test_badNameFails() + { + $this->assertfalse(Auth_OpenID_checkFieldName('INVALID')); + } + + function test_badTypeFails() + { + $this->assertfalse(Auth_OpenID_checkFieldName(null)); + } +} + +// For supportsSReg test +class FakeEndpoint { + function FakeEndpoint($supported) + { + $this->supported = $supported; + $this->checked_uris = array(); + } + + function usesExtension($namespace_uri) + { + $this->checked_uris[] = $namespace_uri; + return in_array($namespace_uri, $this->supported); + } +} + +class SupportsSRegTest extends PHPUnit_TestCase { + function test_unsupported() + { + $endpoint = new FakeEndpoint(array()); + $this->assertfalse(Auth_OpenID_supportsSReg($endpoint)); + $this->assertEquals(array(Auth_OpenID_SREG_NS_URI_1_1, + Auth_OpenID_SREG_NS_URI_1_0), + $endpoint->checked_uris); + } + + function test_supported_1_1() + { + $endpoint = new FakeEndpoint(array(Auth_OpenID_SREG_NS_URI_1_1)); + $this->assertTrue(Auth_OpenID_supportsSReg($endpoint)); + $this->assertEquals(array(Auth_OpenID_SREG_NS_URI_1_1), + $endpoint->checked_uris); + } + + function test_supported_1_0() + { + $endpoint = new FakeEndpoint(array(Auth_OpenID_SREG_NS_URI_1_0)); + $this->assertTrue(Auth_OpenID_supportsSReg($endpoint)); + $this->assertEquals(array(Auth_OpenID_SREG_NS_URI_1_1, + Auth_OpenID_SREG_NS_URI_1_0), + $endpoint->checked_uris); + } +} + +class FakeMessage { + function FakeMessage() + { + $this->openid1 = false; + $this->namespaces = new Auth_OpenID_NamespaceMap(); + } + + function isOpenID1() + { + return $this->openid1; + } +} + +class GetNSTest extends PHPUnit_TestCase { + function setUp() + { + $this->msg = new FakeMessage(); + } + + function test_openID2Empty() + { + $ns_uri = Auth_OpenID_SRegBase::_getSRegNS($this->msg); + $this->assertEquals($this->msg->namespaces->getAlias($ns_uri), 'sreg'); + $this->assertEquals(Auth_OpenID_SREG_NS_URI, $ns_uri); + } + + function test_openID1Empty() + { + $this->msg->openid1 = true; + $ns_uri = Auth_OpenID_SRegBase::_getSRegNS($this->msg); + $this->assertEquals($this->msg->namespaces->getAlias($ns_uri), 'sreg'); + $this->assertEquals(Auth_OpenID_SREG_NS_URI, $ns_uri); + } + + function test_openID1Defined_1_0() + { + $this->msg->openid1 = true; + $this->msg->namespaces->add(Auth_OpenID_SREG_NS_URI_1_0); + $ns_uri = Auth_OpenID_SRegBase::_getSRegNS($this->msg); + $this->assertEquals(Auth_OpenID_SREG_NS_URI_1_0, $ns_uri); + } + + function test_openID1Defined_1_0_overrideAlias() + { + foreach (array(true, false) as $openid_version) { + foreach (array(Auth_OpenID_SREG_NS_URI_1_0, + Auth_OpenID_SREG_NS_URI_1_1) as $sreg_version) { + foreach (array('sreg', 'bogus') as $alias) { + $this->setUp(); + + $this->msg->openid1 = $openid_version; + $this->assertTrue($this->msg->namespaces->addAlias($sreg_version, $alias) !== null); + $ns_uri = Auth_OpenID_SRegBase::_getSRegNS($this->msg); + $this->assertEquals($this->msg->namespaces->getAlias($ns_uri), $alias); + $this->assertEquals($sreg_version, $ns_uri); + } + } + } + } + + function test_openID1DefinedBadly() + { + $this->msg->openid1 = true; + $this->msg->namespaces->addAlias('http://invalid/', 'sreg'); + $this->assertTrue(Auth_OpenID_SRegBase::_getSRegNS($this->msg) === null); + } + + function test_openID2DefinedBadly() + { + $this->msg->openid1 = false; + $this->msg->namespaces->addAlias('http://invalid/', 'sreg'); + $this->assertTrue(Auth_OpenID_SRegBase::_getSRegNS($this->msg) === null); + } + + function test_openID2Defined_1_0() + { + $this->msg->namespaces->add(Auth_OpenID_SREG_NS_URI_1_0); + $ns_uri = Auth_OpenID_SRegBase::_getSRegNS($this->msg); + $this->assertEquals(Auth_OpenID_SREG_NS_URI_1_0, $ns_uri); + } + + function test_openID1_sregNSfromArgs() + { + $args = array( + 'sreg.optional' => 'nickname', + 'sreg.required' => 'dob'); + + $m = Auth_OpenID_Message::fromOpenIDArgs($args); + + $this->assertTrue($m->getArg(Auth_OpenID_SREG_NS_URI_1_1, 'optional') == 'nickname'); + $this->assertTrue($m->getArg(Auth_OpenID_SREG_NS_URI_1_1, 'required') == 'dob'); + } +} + +class SentinelFakeMessage { + var $args_sentinel = 'args_sentinel'; + + function SentinelFakeMessage(&$test_case) + { + $this->test_case =& $test_case; + } + + function getArgs($ns_uri) + { + $this->test_case->assertEquals($ns_sentinel, $ns_uri); + return $this->args_sentinel; + } +} + +class TestingReq extends Auth_OpenID_SRegRequest { + var $ns_sentinel = 'ns_sentinel'; + + function fromOpenIDRequest($message, &$test_case) + { + parent::fromOpenIDRequest($message); + $this->test_case =& $test_case; + } + + function _getSRegNS($unused) + { + return $this->ns_sentinel; + } + + function parseExtensionArgs($args) + { + $this->test_case->assertEquals($args_sentinel, $args); + } +} + +class SRegRequestTest extends PHPUnit_TestCase { + function test_constructEmpty() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertEquals(array(), $req->optional); + $this->assertEquals(array(), $req->required); + $this->assertEquals(null, $req->policy_url); + $this->assertEquals(Auth_OpenID_SREG_NS_URI, $req->ns_uri); + } + + function test_constructFields() + { + $req = Auth_OpenID_SRegRequest::build( + array('nickname'), + array('gender'), + 'http://policy', + 'http://sreg.ns_uri'); + $this->assertEquals(array('gender'), $req->optional); + $this->assertEquals(array('nickname'), $req->required); + $this->assertEquals('http://policy', $req->policy_url); + $this->assertEquals('http://sreg.ns_uri', $req->ns_uri); + } + + function test_constructBadFields() + { + $this->assertTrue(Auth_OpenID_SRegRequest::build(array('elvis')) === null); + } + + /* + function test_fromOpenIDResponse() + { + $msg = new SentinelFakeMessage($this); + $req = TestingReq::fromOpenIDRequest($msg, $this); + } + */ + + function test_parseExtensionArgs_empty() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array())); + } + + function test_parseExtensionArgs_extraIgnored() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('janrain' => 'inc'))); + } + + function test_parseExtensionArgs_nonStrict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('required' => 'beans'))); + $this->assertEquals(array(), $req->required); + } + + function test_parseExtensionArgs_strict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->parseExtensionArgs(array('required' => 'beans'), + true)); + } + + function test_parseExtensionArgs_policy() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs( + array('policy_url' => 'http://policy'), true)); + $this->assertEquals('http://policy', $req->policy_url); + } + + function test_parseExtensionArgs_requiredEmpty() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('required' => ''), true)); + $this->assertEquals(array(), $req->required); + } + + function test_parseExtensionArgs_optionalEmpty() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => ''), true)); + $this->assertEquals(array(), $req->optional); + } + + function test_parseExtensionArgs_optionalSingle() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => 'nickname'), true)); + $this->assertEquals(array('nickname'), $req->optional); + } + + function test_parseExtensionArgs_optionalList() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => 'nickname,email'), true)); + $this->assertEquals(array('nickname','email'), $req->optional); + } + + function test_parseExtensionArgs_optionalListBadNonStrict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => 'nickname,email,beer'))); + $this->assertEquals(array('nickname','email'), $req->optional); + } + + function test_parseExtensionArgs_optionalListBadStrict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->parseExtensionArgs(array('optional' => 'nickname,email,beer'), + true)); + } + + function test_parseExtensionArgs_bothNonStrict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => 'nickname', + 'required' => 'nickname'))); + $this->assertEquals(array(), $req->optional); + $this->assertEquals(array('nickname'), $req->required); + } + + function test_parseExtensionArgs_bothStrict() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->parseExtensionArgs( + array('optional' => 'nickname', + 'required' => 'nickname'), + true)); + } + + function test_parseExtensionArgs_bothList() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertTrue($req->parseExtensionArgs(array('optional' => 'nickname,email', + 'required' => 'country,postcode'), + true)); + $this->assertEquals(array('nickname','email'), $req->optional); + $this->assertEquals(array('country','postcode'), $req->required); + } + + function test_allRequestedFields() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertEquals(array(), $req->allRequestedFields()); + $req->requestField('nickname'); + $this->assertEquals(array('nickname'), $req->allRequestedFields()); + $req->requestField('gender', true); + $requested = $req->allRequestedFields(); + sort($requested); + $this->assertEquals(array('gender', 'nickname'), $requested); + } + + function test_wereFieldsRequested() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->wereFieldsRequested()); + $req->requestField('gender'); + $this->assertTrue($req->wereFieldsRequested()); + } + + function test_contains() + { + global $Auth_OpenID_sreg_data_fields; + + $req = Auth_OpenID_SRegRequest::build(); + foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) { + $this->assertFalse($req->contains($field_name)); + } + + $this->assertFalse($req->contains('something else')); + + $req->requestField('nickname'); + foreach ($Auth_OpenID_sreg_data_fields as $field_name => $desc) { + if ($field_name == 'nickname') { + $this->assertTrue($req->contains($field_name)); + } else { + $this->assertFalse($req->contains($field_name)); + } + } + } + + function test_requestField_bogus() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->requestField('something else')); + $this->assertFalse($req->requestField('something else', true)); + } + + function test_requestField() + { + global $Auth_OpenID_sreg_data_fields; + + // Add all of the fields, one at a time + $req = Auth_OpenID_SRegRequest::build(); + $fields = array_keys($Auth_OpenID_sreg_data_fields); + foreach ($fields as $field_name) { + $req->requestField($field_name); + } + + $this->assertEquals($fields, $req->optional); + $this->assertEquals(array(), $req->required); + + // By default, adding the same fields over again has no effect + foreach ($fields as $field_name) { + $req->requestField($field_name); + } + + $this->assertEquals($fields, $req->optional); + $this->assertEquals(array(), $req->required); + + // Requesting a field as required overrides requesting it as + // optional + $expected = $fields; + $overridden = array_pop($expected); + + $this->assertTrue($req->requestField($overridden, true)); + + $this->assertEquals($expected, $req->optional); + $this->assertEquals(array($overridden), $req->required); + + // Requesting a field as required overrides requesting it as + // optional + foreach ($fields as $field_name) { + $this->assertTrue($req->requestField($field_name, true)); + } + + $this->assertEquals(array(), $req->optional); + foreach ($fields as $f) { + $this->assertTrue(in_array($f, $req->required)); + } + + // Requesting it as optional does not downgrade it to optional + foreach ($fields as $field_name) { + $req->requestField($field_name); + } + + $this->assertEquals(array(), $req->optional); + + foreach ($fields as $f) { + $this->assertTrue(in_array($f, $req->required)); + } + } + + function test_requestFields_type() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertFalse($req->requestFields('nickname')); + } + + function test_requestFields() + { + global $Auth_OpenID_sreg_data_fields; + + // Add all of the fields + $req = Auth_OpenID_SRegRequest::build(); + + $fields = array_keys($Auth_OpenID_sreg_data_fields); + $req->requestFields($fields); + + $this->assertEquals($fields, $req->optional); + $this->assertEquals(array(), $req->required); + + // By default, adding the same fields over again has no effect + $req->requestFields($fields); + + $this->assertEquals($fields, $req->optional); + $this->assertEquals(array(), $req->required); + + // Requesting a field as required overrides requesting it as + // optional + $expected = $fields; + $overridden = array_shift($expected); + $req->requestFields(array($overridden), true); + + foreach ($expected as $f) { + $this->assertTrue(in_array($f, $req->optional)); + } + + $this->assertEquals(array($overridden), $req->required); + + // Requesting a field as required overrides requesting it as + // optional + $req->requestFields($fields, true); + + $this->assertEquals(array(), $req->optional); + $this->assertEquals($fields, $req->required); + + // Requesting it as optional does not downgrade it to optional + $req->requestFields($fields); + + $this->assertEquals(array(), $req->optional); + $this->assertEquals($fields, $req->required); + } + + function test_getExtensionArgs() + { + $req = Auth_OpenID_SRegRequest::build(); + $this->assertEquals(array(), $req->getExtensionArgs()); + + $this->assertTrue($req->requestField('nickname')); + $this->assertEquals(array('optional' => 'nickname'), + $req->getExtensionArgs()); + + $this->assertTrue($req->requestField('email')); + $this->assertEquals(array('optional' => 'nickname,email'), + $req->getExtensionArgs()); + + $this->assertTrue($req->requestField('gender', true)); + $this->assertEquals(array('optional' => 'nickname,email', + 'required' => 'gender'), + $req->getExtensionArgs()); + + $this->assertTrue($req->requestField('postcode', true)); + $this->assertEquals(array('optional' => 'nickname,email', + 'required' => 'gender,postcode'), + $req->getExtensionArgs()); + + $req->policy_url = 'http://policy.invalid/'; + $this->assertEquals(array('optional' => 'nickname,email', + 'required' => 'gender,postcode', + 'policy_url' => 'http://policy.invalid/'), + $req->getExtensionArgs()); + } +} + +class DummySuccessResponse { + function DummySuccessResponse($message, $signed_stuff) + { + $this->message = $message; + $this->signed_stuff = $signed_stuff; + } + + function getSignedNS($ns_uri) + { + return $this->signed_stuff; + } +} + +class SRegResponseTest extends PHPUnit_TestCase { + function test_fromSuccessResponse_signed() + { + $message = Auth_OpenID_Message::fromOpenIDArgs(array( + 'sreg.nickname' => 'The Mad Stork', + )); + $success_resp = new DummySuccessResponse($message, array()); + $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($success_resp); + $this->assertTrue(count($sreg_resp->contents()) === 0); + } + + function test_fromSuccessResponse_unsigned() + { + $message = Auth_OpenID_Message::fromOpenIDArgs(array( + 'sreg.nickname' => 'The Mad Stork', + )); + + $success_resp = new DummySuccessResponse($message, array()); + $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($success_resp, + false); + + $this->assertEquals(array('nickname' => 'The Mad Stork'), + $sreg_resp->contents()); + } +} + +class SendFieldsTest extends PHPUnit_TestCase { + function test() + { + // Create a request message with simple registration fields + $sreg_req = Auth_OpenID_SRegRequest::build(array('nickname', 'email'), + array('fullname')); + $req_msg = new Auth_OpenID_Message(); + $req_msg->updateArgs(Auth_OpenID_SREG_NS_URI, + $sreg_req->getExtensionArgs()); + + $req = new Auth_OpenID_Request(); + $req->message = $req_msg; + $req->namespace = $req_msg->getOpenIDNamespace(); + + // -> send checkid_* request + + // Create an empty response message + $resp_msg = new Auth_OpenID_Message(); + $resp = new Auth_OpenID_ServerResponse($req); + $resp->fields = $resp_msg; + + $data = array( + 'nickname' => 'linusaur', + 'postcode' => '12345', + 'country' => 'US', + 'gender' => 'M', + 'fullname' => 'Leonhard Euler', + 'email' => 'president@whitehouse.gov', + 'dob' => '0000-00-00', + 'language' => 'en-us'); + + // Put the requested data fields in the response message + Auth_OpenID_sendSRegFields($req, $data, $resp); + + // <- send id_res response + + // Extract the fields that were sent + $sreg_data_resp = $resp->fields->getArgs(Auth_OpenID_SREG_NS_URI); + $this->assertEquals( + array('nickname' => 'linusaur', + 'email' => 'president@whitehouse.gov', + 'fullname' => 'Leonhard Euler'), + $sreg_data_resp); + } +} + +class Tests_Auth_OpenID_SReg extends PHPUnit_TestSuite { + function getName() + { + return "Tests_Auth_OpenID_SReg"; + } + + function Tests_Auth_OpenID_SReg() + { + $this->addTestSuite('SRegURITest'); + $this->addTestSuite('CheckFieldNameTest'); + $this->addTestSuite('SupportsSRegTest'); + $this->addTestSuite('GetNSTest'); + $this->addTestSuite('SRegRequestTest'); + $this->addTestSuite('SRegResponseTest'); + $this->addTestSuite('SendFieldsTest'); + } +} + +?>
\ No newline at end of file diff --git a/Tests/TestDriver.php b/Tests/TestDriver.php index c88d525..69b69ce 100644 --- a/Tests/TestDriver.php +++ b/Tests/TestDriver.php @@ -130,6 +130,7 @@ $_tests = array( 'OpenID_Yadis', 'Parse', 'Server', + 'SReg', 'StoreTest', 'TrustRoot', 'URINorm', |