diff options
-rw-r--r-- | Auth/OpenID/Discover.php | 28 | ||||
-rw-r--r-- | Auth/OpenID/HTTPFetcher.php | 11 | ||||
-rw-r--r-- | Auth/OpenID/ParanoidHTTPFetcher.php | 6 | ||||
-rw-r--r-- | Auth/OpenID/PlainHTTPFetcher.php | 5 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Discover.php | 472 | ||||
-rw-r--r-- | Tests/TestDriver.php | 1 |
6 files changed, 507 insertions, 16 deletions
diff --git a/Auth/OpenID/Discover.php b/Auth/OpenID/Discover.php index 5fd2aa0..1b5aaaa 100644 --- a/Auth/OpenID/Discover.php +++ b/Auth/OpenID/Discover.php @@ -120,7 +120,7 @@ function filter_MatchesAnyOpenIDType(&$service) return false; } -function Auth_OpenID_discoverWithYadis($uri) +function Auth_OpenID_discoverWithYadis($uri, &$fetcher) { // Discover OpenID services for a URI. Tries Yadis and falls back // on old-style <link rel='...'> discovery if Yadis fails. @@ -131,15 +131,19 @@ function Auth_OpenID_discoverWithYadis($uri) // to catch it. $openid_services = array(); - $response = @Services_Yadis_Yadis::discover($uri); + $http_response = null; + $response = @Services_Yadis_Yadis::discover($uri, $http_response, + $fetcher); if ($response) { $identity_url = $response->uri; $openid_services = $response->xrds->services(array('filter_MatchesAnyOpenIDType')); - } else { + } + + if (!$openid_services) { return @Auth_OpenID_discoverWithoutYadis($uri, - Auth_OpenID::getHTTPFetcher()); + $fetcher); } if (!$openid_services) { @@ -179,38 +183,38 @@ function Auth_OpenID_discoverWithYadis($uri) $openid_services = $s; } - return array($identity_url, $openid_services); + return array($identity_url, $openid_services, $http_response); } function Auth_OpenID_discoverWithoutYadis($uri, &$fetcher) { $http_resp = @$fetcher->get($uri); - list($code, $url, $body) = $http_resp; - if ($code != 200) { - return null; + if ($http_resp->status != 200) { + return array(null, array(), $http_resp); } - $identity_url = $url; + $identity_url = $http_resp->final_url; // Try to parse the response as HTML to get OpenID 1.0/1.1 <link // rel="..."> $endpoint =& new Auth_OpenID_ServiceEndpoint(); - $service = $endpoint->fromHTML($identity_url, $body); + $service = $endpoint->fromHTML($identity_url, $http_resp->body); if ($service === null) { $openid_services = array(); } else { $openid_services = array($service); } - return array($identity_url, $openid_services); + return array($identity_url, $openid_services, $http_resp); } function Auth_OpenID_discover($uri, &$fetcher) { global $_yadis_available; + if ($_yadis_available) { - return @Auth_OpenID_discoverWithYadis($uri); + return @Auth_OpenID_discoverWithYadis($uri, $fetcher); } else { return @Auth_OpenID_discoverWithoutYadis($uri, $fetcher); } diff --git a/Auth/OpenID/HTTPFetcher.php b/Auth/OpenID/HTTPFetcher.php index fb6d1ab..f84e9ab 100644 --- a/Auth/OpenID/HTTPFetcher.php +++ b/Auth/OpenID/HTTPFetcher.php @@ -18,6 +18,17 @@ require_once "Auth/OpenID/Parse.php"; require_once "Auth/OpenID.php"; +class Auth_OpenID_HTTPResponse { + function Auth_OpenID_HTTPResponse($final_url = null, $status = null, + $headers = null, $body = null) + { + $this->final_url = $final_url; + $this->status = $status; + $this->headers = $headers; + $this->body = $body; + } +} + /** * This is the status code beginAuth returns when it is unable to * fetch the OpenID URL the user entered. diff --git a/Auth/OpenID/ParanoidHTTPFetcher.php b/Auth/OpenID/ParanoidHTTPFetcher.php index c84457b..c4e11cb 100644 --- a/Auth/OpenID/ParanoidHTTPFetcher.php +++ b/Auth/OpenID/ParanoidHTTPFetcher.php @@ -111,7 +111,8 @@ class Auth_OpenID_ParanoidHTTPFetcher extends Auth_OpenID_HTTPFetcher { } else { $redir = false; curl_close($c); - return array($code, $url, $body); + return new Services_Yadis_HTTPResponse($url, $code, + $headers, $body); } $off = $stop - time(); @@ -155,7 +156,8 @@ class Auth_OpenID_ParanoidHTTPFetcher extends Auth_OpenID_HTTPFetcher { $body = $this->data; curl_close($c); - return array($code, $url, $body); + return new Auth_OpenID_HTTPResponse($url, $code, + $this->headers, $body); } } diff --git a/Auth/OpenID/PlainHTTPFetcher.php b/Auth/OpenID/PlainHTTPFetcher.php index afb5ace..9dd3600 100644 --- a/Auth/OpenID/PlainHTTPFetcher.php +++ b/Auth/OpenID/PlainHTTPFetcher.php @@ -118,7 +118,7 @@ class Auth_OpenID_PlainHTTPFetcher extends Auth_OpenID_HTTPFetcher { $off = $stop - time(); } - return array($code, $url, $body); + return new Auth_OpenID_HTTPResponse($url, $code, $headers, $body); } function post($url, $body) @@ -203,7 +203,8 @@ class Auth_OpenID_PlainHTTPFetcher extends Auth_OpenID_HTTPFetcher { $http_code = explode(" ", $headers[0]); $code = $http_code[1]; - return array($code, $url, $response_body); + return new Auth_OpenID_HTTPResponse($url, $code, + $headers, $response_body); } } diff --git a/Tests/Auth/OpenID/Discover.php b/Tests/Auth/OpenID/Discover.php new file mode 100644 index 0000000..4574477 --- /dev/null +++ b/Tests/Auth/OpenID/Discover.php @@ -0,0 +1,472 @@ +<?php + +require_once 'PHPUnit.php'; + +require_once 'Auth/OpenID.php'; +require_once 'Auth/OpenID/Discover.php'; + +/** + * Tests for the core of the PHP Yadis library discovery logic. + */ + +class _SimpleMockFetcher { + function _SimpleMockFetcher($responses) + { + $this->responses = $responses; + } + + function get($url) + { + $response = array_pop($this->responses); + assert($response[1] == $url); + return $response; + } +} + +class Tests_Services_Yadis_DiscoveryFailure extends PHPUnit_TestCase { + + function Tests_Services_Yadis_DiscoveryFailure($responses) + { + // Response is ($code, $url, $body). + $this->cases = array( + array(null, 'http://network.error/', ''), + array(404, 'http://not.found/', ''), + array(400, 'http://bad.request/', ''), + array(500, 'http://server.error/', ''), + array(200, 'http://header.found/', 200, + array('x-xrds-location' => 'http://xrds.missing/')), + array(404, 'http://xrds.missing/', '')); + + $this->url = $responses[0]->final_url; + $this->responses = $responses; + $this->fetcher = new _SimpleMockFetcher($this->responses); + } + + function runTest() + { + foreach ($this->cases as $case) { + list($status, $url, $body) = $case; + $expected_status = $status; + + $result = Auth_OpenID_discover($this->url, $this->fetcher); + list($id_url, $svclist, $http_response) = $result; + + $this->assertEquals($http_response->status, $expected_status); + } + } +} + +### Tests for raising/catching exceptions from the fetcher through the +### discover function + +class _ErrorRaisingFetcher { + // Just raise an exception when fetch is called + + function _ErrorRaisingFetcher($thing_to_raise) + { + $this->thing_to_raise = $thing_to_raise; + } + + function post($body = null) + { + __raiseError($this->thing_to_raise); + } + + function get($url) + { + __raiseError($this->thing_to_raise); + } +} + +define('E_AUTH_OPENID_EXCEPTION', 'e_exception'); +define('E_AUTH_OPENID_DIDFETCH', 'e_didfetch'); +define('E_AUTH_OPENID_VALUE_ERROR', 'e_valueerror'); +define('E_AUTH_OPENID_RUNTIME_ERROR', 'e_runtimeerror'); +define('E_AUTH_OPENID_OI', 'e_oi'); + +class Tests_Auth_OpenID_Discover_FetchException extends PHPUnit_TestCase { + // Make sure exceptions get passed through discover function from + // fetcher. + + function Tests_Auth_OpenID_Discover_FetchException($exc) + { + $this->cases = array(E_AUTH_OPENID_EXCEPTION, + E_AUTH_OPENID_DIDFETCH, + E_AUTH_OPENID_VALUE_ERROR, + E_AUTH_OPENID_RUNTIME_ERROR, + E_AUTH_OPENID_OI); + } + + function runTest() + { + foreach ($this->cases as $thing_to_raise) { + $fetcher = ErrorRaisingFetcher($thing_to_raise); + Auth_OpenID_discover('http://doesnt.matter/', $fetcher); + $exc = __getError(); + + if ($exc !== $thing_to_raise) { + $this->fail('FetchException expected %s to be raised', + $thing_to_raise); + } + } + } +} + + +// Tests for openid.consumer.discover.discover + +class _DiscoveryMockFetcher { + function _DiscoveryMockFetcher(&$documents) + { + $this->redirect = null; + $this->documents = &$documents; + $this->fetchlog = array(); + } + + function post($url, $body = null, $headers = null) + { + return $this->get($url, $headers, $body); + } + + function get($url, $headers = null, $body = null) + { + $this->fetchlog[] = array($url, $body, $headers); + + if ($this->redirect) { + $final_url = $this->redirect; + } else { + $final_url = $url; + } + + if (array_key_exists($url, $this->documents)) { + list($ctype, $body) = $this->documents[$url]; + $status = 200; + } else { + $status = 404; + $ctype = 'text/plain'; + $body = ''; + } + + return new Auth_OpenID_HTTPResponse($final_url, $status, + array('content-type' => $ctype), $body); + } +} + +define('DISCOVERYBASE_ID_URL', "http://someuser.unittest/"); + +class _DiscoveryBase extends PHPUnit_TestCase { + var $id_url = DISCOVERYBASE_ID_URL; + var $documents = array(); + + function setUp() + { + $this->fetcher = new _DiscoveryMockFetcher($this->documents); + } +} + +$__yadis_2entries = '<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS xmlns:xrds="xri://$xrds" + xmlns="xri://$xrd*($v*2.0)" + xmlns:openid="http://openid.net/xmlns/1.0" + > + <XRD> + + <Service priority="10"> + <Type>http://openid.net/signon/1.0</Type> + <URI>http://www.myopenid.com/server</URI> + <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate> + </Service> + + <Service priority="20"> + <Type>http://openid.net/signon/1.0</Type> + <URI>http://www.livejournal.com/openid/server.bml</URI> + <openid:Delegate>http://frank.livejournal.com/</openid:Delegate> + </Service> + + </XRD> +</xrds:XRDS> +'; + +$__yadis_another = '<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS xmlns:xrds="xri://$xrds" + xmlns="xri://$xrd*($v*2.0)" + xmlns:openid="http://openid.net/xmlns/1.0" + > + <XRD> + + <Service priority="10"> + <Type>http://openid.net/signon/1.0</Type> + <URI>http://vroom.unittest/server</URI> + <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate> + </Service> + </XRD> +</xrds:XRDS> +'; + +$__yadis_0entries = '<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS xmlns:xrds="xri://$xrds" + xmlns="xri://$xrd*($v*2.0)" + xmlns:openid="http://openid.net/xmlns/1.0" + > + <XRD> + <Service > + <Type>http://is-not-openid.unittest/</Type> + <URI>http://noffing.unittest./</URI> + </Service> + </XRD> +</xrds:XRDS> +'; + +$__yadis_no_delegate = '<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS xmlns:xrds="xri://$xrds" + xmlns="xri://$xrd*($v*2.0)" + > + <XRD> + <Service priority="10"> + <Type>http://openid.net/signon/1.0</Type> + <URI>http://www.myopenid.com/server</URI> + </Service> + </XRD> +</xrds:XRDS> +'; + +$__openid_html = ' +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <head> + <title>Identity Page for Smoker</title> +<link rel="openid.server" href="http://www.myopenid.com/server" /> +<link rel="openid.delegate" href="http://smoker.myopenid.com/" /> + </head><body><p>foo</p></body></html> +'; + +$__openid_html_no_delegate = ' +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <head> + <title>Identity Page for Smoker</title> +<link rel="openid.server" href="http://www.myopenid.com/server" /> + </head><body><p>foo</p></body></html> +'; + +$__openid_and_yadis_html = ' +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <head> + <title>Identity Page for Smoker</title> +<meta http-equiv="X-XRDS-Location" content="http://someuser.unittest/xrds" /> +<link rel="openid.server" href="http://www.myopenid.com/server" /> +<link rel="openid.delegate" href="http://smoker.myopenid.com/" /> + </head><body><p>foo</p></body></html> +'; + +class Tests_Auth_OpenID_Discover extends _DiscoveryBase { + function _usedYadis($service) + { + $this->assertTrue($service->used_yadis, + "Expected to use Yadis"); + } + + function _notUsedYadis($service) + { + $this->assertFalse($service->used_yadis, + "Expected to use old-style discovery"); + } + + function test_404() + { + $result = Auth_OpenID_discover($this->id_url . '/404', + $this->fetcher); + + list($id_url, $svclist, $http_response) = $result; + + $this->assertTrue($http_response->status == 404, + "Expected 404 status from /404 discovery"); + } + + function test_noYadis() + { + global $__openid_html; + + $this->documents[$this->id_url] = array('text/html', $__openid_html); + + list($id_url, $services, $http_response) = + Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertEquals(count($services), 1, + "More than one service"); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->assertEquals($services[0]->delegate, + "http://smoker.myopenid.com/"); + + $this->assertEquals($services[0]->identity_url, $this->id_url); + $this->_notUsedYadis($services[0]); + } + + function test_noOpenID() + { + $this->fetcher->documents = array( + $this->id_url => array('text/plain', "junk")); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertFalse(count($services) > 0); + } + + function test_yadis() + { + global $__yadis_2entries; + + $this->fetcher->documents = array( + DISCOVERYBASE_ID_URL => array('application/xrds+xml', + $__yadis_2entries)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertEquals(count($services), 2, + "Not 2 services"); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->_usedYadis($services[0]); + + $this->assertEquals($services[1]->server_url, + "http://www.livejournal.com/openid/server.bml"); + + $this->_usedYadis($services[1]); + } + + function test_redirect() + { + global $__openid_html; + + $expected_final_url = "http://elsewhere.unittest/"; + + $this->fetcher->redirect = $expected_final_url; + $this->fetcher->documents = array( + $this->id_url => array('text/html', $__openid_html)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($expected_final_url, $id_url); + + $this->assertEquals(count($services), 1, + "More than one service"); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->assertEquals($services[0]->delegate, + "http://smoker.myopenid.com/"); + + $this->assertEquals($services[0]->identity_url, + $expected_final_url); + + $this->_notUsedYadis($services[0]); + } + + function test_emptyList() + { + global $__yadis_0entries; + + $this->fetcher->documents = array( + $this->id_url => + array('application/xrds+xml', $__yadis_0entries)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertTrue(count($services) == 0); + } + + function test_emptyListWithLegacy() + { + global $__openid_and_yadis_html, + $__yadis_0entries; + + $this->fetcher->documents = array( + $this->id_url => array('text/html', $__openid_and_yadis_html), + $this->id_url . 'xrds' => array('application/xrds+xml', $__yadis_0entries)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertEquals(count($services), 1, + "Not one service"); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->assertEquals($services[0]->identity_url, $this->id_url); + + $this->_notUsedYadis($services[0]); + } + + function test_yadisNoDelegate() + { + global $__yadis_no_delegate; + + $this->fetcher->documents = array( + $this->id_url => array('application/xrds+xml', $__yadis_no_delegate)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertEquals(count($services), 1, + "Not 1 service"); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->assertEquals($services[0]->delegate, null, + 'Delegate should be null'); + + $this->_usedYadis($services[0]); + } + + function test_openidNoDelegate() + { + global $__openid_html_no_delegate; + + $this->fetcher->documents = array( + $this->id_url => array('text/html', + $__openid_html_no_delegate)); + + list($id_url, $services, $http) = Auth_OpenID_discover($this->id_url, + $this->fetcher); + + $this->assertEquals($this->id_url, $id_url); + + $this->assertEquals($services[0]->server_url, + "http://www.myopenid.com/server"); + + $this->assertEquals($services[0]->identity_url, $this->id_url); + + $this->assertEquals($services[0]->delegate, null, + 'Delegate should be null'); + + $this->_notUsedYadis($services[0]); + } +} + +?>
\ No newline at end of file diff --git a/Tests/TestDriver.php b/Tests/TestDriver.php index 7677691..1162516 100644 --- a/Tests/TestDriver.php +++ b/Tests/TestDriver.php @@ -116,6 +116,7 @@ $_test_names = array( 'StoreTest', 'Server', 'TrustRoot', + 'Discover' ); function selectTests($names) |