summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortailor <cygnus@janrain.com>2007-03-29 22:21:08 +0000
committertailor <cygnus@janrain.com>2007-03-29 22:21:08 +0000
commit4764ca71327ea47d2b7ff3154141d4449853ad16 (patch)
tree005a376ab6bb748b4d0b39c30fe4ee2a16895d33
parent571843ed0fd063b5c1cd39e4f99a6caa5a5ee74e (diff)
downloadphp-openid-4764ca71327ea47d2b7ff3154141d4449853ad16.zip
php-openid-4764ca71327ea47d2b7ff3154141d4449853ad16.tar.gz
php-openid-4764ca71327ea47d2b7ff3154141d4449853ad16.tar.bz2
[project @ Added new Sreg module, extension code, and tests]
-rw-r--r--Auth/OpenID/Extension.php47
-rw-r--r--Auth/OpenID/Message.php20
-rw-r--r--Auth/OpenID/SReg.php530
-rw-r--r--Tests/Auth/OpenID/Consumer.php6
-rw-r--r--Tests/Auth/OpenID/SReg.php642
-rw-r--r--Tests/TestDriver.php1
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',