├── .gitignore ├── Auth ├── OpenID.php ├── OpenID │ ├── AX.php │ ├── Association.php │ ├── BigMath.php │ ├── Consumer.php │ ├── CryptUtil.php │ ├── DatabaseConnection.php │ ├── DiffieHellman.php │ ├── Discover.php │ ├── DumbStore.php │ ├── Extension.php │ ├── FileStore.php │ ├── HMAC.php │ ├── Interface.php │ ├── KVForm.php │ ├── MDB2Store.php │ ├── MemcachedStore.php │ ├── Message.php │ ├── MySQLStore.php │ ├── Nonce.php │ ├── PAPE.php │ ├── Parse.php │ ├── PostgreSQLStore.php │ ├── PredisStore.php │ ├── SQLStore.php │ ├── SQLiteStore.php │ ├── SReg.php │ ├── Server.php │ ├── ServerRequest.php │ ├── TrustRoot.php │ └── URINorm.php └── Yadis │ ├── HTTPFetcher.php │ ├── Manager.php │ ├── Misc.php │ ├── ParanoidHTTPFetcher.php │ ├── ParseHTML.php │ ├── PlainHTTPFetcher.php │ ├── XML.php │ ├── XRDS.php │ ├── XRI.php │ ├── XRIRes.php │ └── Yadis.php ├── CHANGES-2.1.0 ├── COPYING ├── NEWS.md ├── README.Debian ├── README.git ├── README.md ├── Tests ├── Auth │ ├── OpenID │ │ ├── AX.php │ │ ├── Association.php │ │ ├── AssociationResponse.php │ │ ├── AuthRequest.php │ │ ├── BigMath.php │ │ ├── Consumer.php │ │ ├── CryptUtil.php │ │ ├── DiffieHellman.php │ │ ├── Discover_OpenID.php │ │ ├── Extension.php │ │ ├── HMAC.php │ │ ├── KVForm.php │ │ ├── MemStore.php │ │ ├── Message.php │ │ ├── Negotiation.php │ │ ├── Nonce.php │ │ ├── OpenID_Yadis.php │ │ ├── PAPE.php │ │ ├── Parse.php │ │ ├── RPVerify.php │ │ ├── SReg.php │ │ ├── Server.php │ │ ├── StoreTest.php │ │ ├── TestUtil.php │ │ ├── TrustRoot.php │ │ ├── URINorm.php │ │ ├── Util.php │ │ ├── VerifyDisco.php │ │ └── data │ │ │ ├── dhexch │ │ │ ├── dhpriv │ │ │ ├── hmac-sha1.txt │ │ │ ├── hmac-sha256.txt │ │ │ ├── linkparse.txt │ │ │ ├── n2b64 │ │ │ ├── openid.html │ │ │ ├── test_discover_openid.html │ │ │ ├── test_discover_openid2.html │ │ │ ├── test_discover_openid2_xrds.xml │ │ │ ├── test_discover_openid2_xrds_no_local_id.xml │ │ │ ├── test_discover_openid_1_and_2.html │ │ │ ├── test_discover_openid_1_and_2_xrds.xml │ │ │ ├── test_discover_openid_1_and_2_xrds_bad_delegate.xml │ │ │ ├── test_discover_openid_and_yadis.html │ │ │ ├── test_discover_openid_no_delegate.html │ │ │ ├── test_discover_openid_ssl.xml │ │ │ ├── test_discover_yadis_0entries.xml │ │ │ ├── test_discover_yadis_2_bad_local_id.xml │ │ │ ├── test_discover_yadis_2entries_delegate.xml │ │ │ ├── test_discover_yadis_2entries_idp.xml │ │ │ ├── test_discover_yadis_another_delegate.xml │ │ │ ├── test_discover_yadis_idp.xml │ │ │ ├── test_discover_yadis_idp_delegate.xml │ │ │ ├── test_discover_yadis_no_delegate.xml │ │ │ ├── trustroot.txt │ │ │ └── urinorm.txt │ └── Yadis │ │ ├── DiscoverData.php │ │ ├── Discover_Yadis.php │ │ ├── ParseHTML.php │ │ ├── TestUtil.php │ │ ├── XRDS.php │ │ ├── XRI.php │ │ ├── Yadis.php │ │ └── data │ │ ├── README │ │ ├── accept.txt │ │ ├── brian.multi.xrds │ │ ├── brian.multi_uri.xrds │ │ ├── brian.xrds │ │ ├── brian_priority.xrds │ │ ├── delegated-20060809-r1.xrds │ │ ├── delegated-20060809-r2.xrds │ │ ├── delegated-20060809.xrds │ │ ├── example-xrds.xml │ │ ├── no-xrd.xml │ │ ├── not-xrds.xml │ │ ├── pip.xrds │ │ ├── prefixsometimes.xrds │ │ ├── ref.xrds │ │ ├── sometimesprefix.xrds │ │ ├── spoof1.xrds │ │ ├── spoof2.xrds │ │ ├── spoof3.xrds │ │ ├── subsegments.xrds │ │ ├── test1-discover.txt │ │ ├── test1-parsehtml.txt │ │ ├── test1-xrd.xml │ │ └── uri_priority.xrds └── TestDriver.php ├── admin ├── adminutil.php ├── brace_style.pl ├── checkimport ├── checkimports ├── darcs-ignore ├── docblocks ├── docblocks.pl ├── findallphp ├── findglobals ├── findphp ├── fixperms ├── gettlds.py ├── library-name ├── longlines.pl ├── makedoc.sh ├── mathlib ├── nobadbraces ├── nobadcase ├── nolonglines ├── notabs ├── open_tag ├── otb_test.php ├── package.xml ├── package2.xml ├── packagexml.py ├── phpaliases.py ├── prepare-release ├── runtests ├── syntaxcheck ├── texttest.php ├── tutorials │ └── OpenID │ │ └── OpenID.pkg ├── webtest.php └── xmlconfig.py ├── composer.json ├── contrib ├── google │ └── php-openid-apps-discover-1.0.1.tar.gz ├── signed_assertions │ ├── AP.php │ └── SAML.php └── upgrade-store-1.1-to-2.0 └── examples ├── README.md ├── consumer ├── common.php ├── finish_auth.php ├── index.php └── try_auth.php ├── detect.php ├── discover.php └── server ├── index.php ├── lib ├── actions.php ├── common.php ├── render.php ├── render │ ├── about.php │ ├── idpXrds.php │ ├── idpage.php │ ├── login.php │ ├── trust.php │ └── userXrds.php └── session.php ├── openid-server.css ├── server.php └── setup.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /Auth/OpenID/CryptUtil.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2005-2008 Janrain, Inc. 15 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 16 | */ 17 | 18 | if (!defined('Auth_OpenID_RAND_SOURCE')) { 19 | /** 20 | * The filename for a source of random bytes. Define this yourself 21 | * if you have a different source of randomness. 22 | */ 23 | define('Auth_OpenID_RAND_SOURCE', '/dev/urandom'); 24 | } 25 | 26 | class Auth_OpenID_CryptUtil { 27 | /** 28 | * Get the specified number of random bytes. 29 | * 30 | * Attempts to use a cryptographically secure (not predictable) 31 | * source of randomness if available. If there is no high-entropy 32 | * randomness source available, it will fail. As a last resort, 33 | * for non-critical systems, define 34 | * Auth_OpenID_RAND_SOURCE as null, and 35 | * the code will fall back on a pseudo-random number generator. 36 | * 37 | * @param int $num_bytes The length of the return value 38 | * @return string $bytes random bytes 39 | */ 40 | static function getBytes($num_bytes) 41 | { 42 | static $f = null; 43 | if ($f === null) { 44 | if (Auth_OpenID_RAND_SOURCE === null) { 45 | $f = false; 46 | } else { 47 | $f = @fopen(Auth_OpenID_RAND_SOURCE, "r"); 48 | if ($f === false) { 49 | $msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' . 50 | ' continue with an insecure random number generator.'; 51 | trigger_error($msg, E_USER_ERROR); 52 | } 53 | } 54 | } 55 | if ($f === false) { 56 | // pseudorandom used 57 | $bytes = ''; 58 | for ($i = 0; $i < $num_bytes; $i += 4) { 59 | $bytes .= pack('L', mt_rand()); 60 | } 61 | $bytes = substr($bytes, 0, $num_bytes); 62 | } else { 63 | $bytes = fread($f, $num_bytes); 64 | } 65 | return $bytes; 66 | } 67 | 68 | /** 69 | * Produce a string of length random bytes, chosen from chrs. If 70 | * $chrs is null, the resulting string may contain any characters. 71 | * 72 | * @param integer $length The length of the resulting 73 | * randomly-generated string 74 | * @param string|null $population A string of characters from which to choose 75 | * to build the new string 76 | * @return string $result A string of randomly-chosen characters 77 | * from $chrs 78 | */ 79 | static function randomString($length, $population = null) 80 | { 81 | if ($population === null) { 82 | return Auth_OpenID_CryptUtil::getBytes($length); 83 | } 84 | 85 | $popsize = strlen($population); 86 | 87 | if ($popsize > 256) { 88 | $msg = 'More than 256 characters supplied to ' . __FUNCTION__; 89 | trigger_error($msg, E_USER_ERROR); 90 | } 91 | 92 | $duplicate = 256 % $popsize; 93 | 94 | $str = ""; 95 | for ($i = 0; $i < $length; $i++) { 96 | do { 97 | $n = ord(Auth_OpenID_CryptUtil::getBytes(1)); 98 | } while ($n < $duplicate); 99 | 100 | $n %= $popsize; 101 | $str .= $population[$n]; 102 | } 103 | 104 | return $str; 105 | } 106 | 107 | static function constEq($s1, $s2) 108 | { 109 | if (strlen($s1) != strlen($s2)) { 110 | return false; 111 | } 112 | 113 | $result = true; 114 | $length = strlen($s1); 115 | for ($i = 0; $i < $length; $i++) { 116 | $result &= ($s1[$i] == $s2[$i]); 117 | } 118 | return $result; 119 | } 120 | } 121 | 122 | -------------------------------------------------------------------------------- /Auth/OpenID/DatabaseConnection.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright 2005-2008 Janrain, Inc. 10 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 11 | */ 12 | 13 | /** 14 | * An empty base class intended to emulate PEAR connection 15 | * functionality in applications that supply their own database 16 | * abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more 17 | * information. You should subclass this class if you need to create 18 | * an SQL store that needs to access its database using an 19 | * application's database abstraction layer instead of a PEAR database 20 | * connection. Any subclass of Auth_OpenID_DatabaseConnection MUST 21 | * adhere to the interface specified here. 22 | * 23 | * @package OpenID 24 | */ 25 | class Auth_OpenID_DatabaseConnection { 26 | /** 27 | * Sets auto-commit mode on this database connection. 28 | * 29 | * @param bool $mode True if auto-commit is to be used; false if 30 | * not. 31 | */ 32 | function autoCommit($mode) 33 | { 34 | } 35 | 36 | /** 37 | * Run an SQL query with the specified parameters, if any. 38 | * 39 | * @param string $sql An SQL string with placeholders. The 40 | * placeholders are assumed to be specific to the database engine 41 | * for this connection. 42 | * 43 | * @param array $params An array of parameters to insert into the 44 | * SQL string using this connection's escaping mechanism. 45 | * 46 | * @return mixed $result The result of calling this connection's 47 | * internal query function. The type of result depends on the 48 | * underlying database engine. This method is usually used when 49 | * the result of a query is not important, like a DDL query. 50 | */ 51 | function query($sql, $params = []) 52 | { 53 | return null; 54 | } 55 | 56 | /** 57 | * Starts a transaction on this connection, if supported. 58 | */ 59 | function begin() 60 | { 61 | } 62 | 63 | /** 64 | * Commits a transaction on this connection, if supported. 65 | */ 66 | function commit() 67 | { 68 | } 69 | 70 | /** 71 | * Performs a rollback on this connection, if supported. 72 | */ 73 | function rollback() 74 | { 75 | } 76 | 77 | /** 78 | * Run an SQL query and return the first column of the first row 79 | * of the result set, if any. 80 | * 81 | * @param string $sql An SQL string with placeholders. The 82 | * placeholders are assumed to be specific to the database engine 83 | * for this connection. 84 | * 85 | * @param array $params An array of parameters to insert into the 86 | * SQL string using this connection's escaping mechanism. 87 | * 88 | * @return mixed $result The value of the first column of the 89 | * first row of the result set. False if no such result was 90 | * found. 91 | */ 92 | function getOne($sql, $params = []) 93 | { 94 | return false; 95 | } 96 | 97 | /** 98 | * Run an SQL query and return the first row of the result set, if 99 | * any. 100 | * 101 | * @param string $sql An SQL string with placeholders. The 102 | * placeholders are assumed to be specific to the database engine 103 | * for this connection. 104 | * 105 | * @param array $params An array of parameters to insert into the 106 | * SQL string using this connection's escaping mechanism. 107 | * 108 | * @return array|bool $result The first row of the result set, if any, 109 | * keyed on column name. False if no such result was found. 110 | */ 111 | function getRow($sql, $params = []) 112 | { 113 | return false; 114 | } 115 | 116 | /** 117 | * Run an SQL query with the specified parameters, if any. 118 | * 119 | * @param string $sql An SQL string with placeholders. The 120 | * placeholders are assumed to be specific to the database engine 121 | * for this connection. 122 | * 123 | * @param array $params An array of parameters to insert into the 124 | * SQL string using this connection's escaping mechanism. 125 | * 126 | * @return array $result An array of arrays representing the 127 | * result of the query; each array is keyed on column name. 128 | */ 129 | function getAll($sql, $params = []) 130 | { 131 | return []; 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /Auth/OpenID/DiffieHellman.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2005-2008 Janrain, Inc. 14 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 | */ 16 | 17 | require_once 'Auth/OpenID.php'; 18 | require_once 'Auth/OpenID/BigMath.php'; 19 | 20 | function Auth_OpenID_getDefaultMod() 21 | { 22 | return '155172898181473697471232257763715539915724801'. 23 | '966915404479707795314057629378541917580651227423'. 24 | '698188993727816152646631438561595825688188889951'. 25 | '272158842675419950341258706556549803580104870537'. 26 | '681476726513255747040765857479291291572334510643'. 27 | '245094715007229621094194349783925984760375594985'. 28 | '848253359305585439638443'; 29 | } 30 | 31 | function Auth_OpenID_getDefaultGen() 32 | { 33 | return '2'; 34 | } 35 | 36 | /** 37 | * The Diffie-Hellman key exchange class. This class relies on 38 | * {@link Auth_OpenID_MathLibrary} to perform large number operations. 39 | * 40 | * @access private 41 | * @package OpenID 42 | */ 43 | class Auth_OpenID_DiffieHellman { 44 | 45 | public $mod; 46 | public $gen; 47 | public $private; 48 | /** @var Auth_OpenID_BcMathWrapper */ 49 | public $lib = null; 50 | 51 | function __construct($mod = null, $gen = null, 52 | $private = null, $lib = null) 53 | { 54 | if ($lib === null) { 55 | $this->lib = Auth_OpenID_getMathLib(); 56 | } else { 57 | $this->lib = $lib; 58 | } 59 | 60 | if ($mod === null) { 61 | $this->mod = $this->lib->init(Auth_OpenID_getDefaultMod()); 62 | } else { 63 | $this->mod = $mod; 64 | } 65 | 66 | if ($gen === null) { 67 | $this->gen = $this->lib->init(Auth_OpenID_getDefaultGen()); 68 | } else { 69 | $this->gen = $gen; 70 | } 71 | 72 | if ($private === null) { 73 | $r = $this->lib->rand($this->mod); 74 | $this->private = $this->lib->add($r, 1); 75 | } else { 76 | $this->private = $private; 77 | } 78 | 79 | $this->public = $this->lib->powmod($this->gen, $this->private, 80 | $this->mod); 81 | } 82 | 83 | function getSharedSecret($composite) 84 | { 85 | return $this->lib->powmod($composite, $this->private, $this->mod); 86 | } 87 | 88 | function getPublicKey() 89 | { 90 | return $this->public; 91 | } 92 | 93 | function usingDefaultValues() 94 | { 95 | return ($this->mod == Auth_OpenID_getDefaultMod() && 96 | $this->gen == Auth_OpenID_getDefaultGen()); 97 | } 98 | 99 | function xorSecret($composite, $secret, $hash_func) 100 | { 101 | $dh_shared = $this->getSharedSecret($composite); 102 | $dh_shared_str = $this->lib->longToBinary($dh_shared); 103 | $hash_dh_shared = $hash_func($dh_shared_str); 104 | 105 | $xsecret = ""; 106 | for ($i = 0; $i < Auth_OpenID::bytes($secret); $i++) { 107 | $xsecret .= chr(ord($secret[$i]) ^ ord($hash_dh_shared[$i])); 108 | } 109 | 110 | return $xsecret; 111 | } 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /Auth/OpenID/DumbStore.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2005-2008 Janrain, Inc. 14 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 | */ 16 | 17 | /** 18 | * Import the interface for creating a new store class. 19 | */ 20 | require_once 'Auth/OpenID/Interface.php'; 21 | require_once 'Auth/OpenID/HMAC.php'; 22 | 23 | /** 24 | * This is a store for use in the worst case, when you have no way of 25 | * saving state on the consumer site. Using this store makes the 26 | * consumer vulnerable to replay attacks, as it's unable to use 27 | * nonces. Avoid using this store if it is at all possible. 28 | * 29 | * Most of the methods of this class are implementation details. 30 | * Users of this class need to worry only about the constructor. 31 | * 32 | * @package OpenID 33 | */ 34 | class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore { 35 | protected $auth_key; 36 | 37 | /** 38 | * Creates a new {@link Auth_OpenID_DumbStore} instance. For the security 39 | * of the tokens generated by the library, this class attempts to 40 | * at least have a secure implementation of getAuthKey. 41 | * 42 | * When you create an instance of this class, pass in a secret 43 | * phrase. The phrase is hashed with sha1 to make it the correct 44 | * length and form for an auth key. That allows you to use a long 45 | * string as the secret phrase, which means you can make it very 46 | * difficult to guess. 47 | * 48 | * Each {@link Auth_OpenID_DumbStore} instance that is created for use by 49 | * your consumer site needs to use the same $secret_phrase. 50 | * 51 | * @param string $secret_phrase The phrase used to create the auth 52 | * key returned by getAuthKey 53 | */ 54 | function __construct($secret_phrase) 55 | { 56 | $this->auth_key = Auth_OpenID_SHA1($secret_phrase); 57 | } 58 | 59 | /** 60 | * This implementation does nothing. 61 | * 62 | * @param string $server_url 63 | * @param Auth_OpenID_Association $association 64 | */ 65 | function storeAssociation($server_url, $association) 66 | { 67 | } 68 | 69 | /** 70 | * This implementation always returns null. 71 | * 72 | * @param string $server_url 73 | * @param null $handle 74 | * @return Auth_OpenID_Association|null 75 | */ 76 | function getAssociation($server_url, $handle = null) 77 | { 78 | return null; 79 | } 80 | 81 | /** 82 | * This implementation always returns false. 83 | * 84 | * @param string $server_url 85 | * @param string $handle 86 | * @return bool|mixed 87 | */ 88 | function removeAssociation($server_url, $handle) 89 | { 90 | return false; 91 | } 92 | 93 | /** 94 | * In a system truly limited to dumb mode, nonces must all be 95 | * accepted. This therefore always returns true, which makes 96 | * replay attacks feasible. 97 | * 98 | * @param string $server_url 99 | * @param int $timestamp 100 | * @param string $salt 101 | * @return bool 102 | */ 103 | function useNonce($server_url, $timestamp, $salt) 104 | { 105 | return true; 106 | } 107 | 108 | /** 109 | * This method returns the auth key generated by the constructor. 110 | */ 111 | function getAuthKey() 112 | { 113 | return $this->auth_key; 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /Auth/OpenID/Extension.php: -------------------------------------------------------------------------------- 1 | isOpenID1(); 52 | $added = $message->namespaces->addAlias($this->ns_uri, 53 | $this->ns_alias, 54 | $implicit); 55 | 56 | if ($added === null) { 57 | if ($message->namespaces->getAlias($this->ns_uri) != 58 | $this->ns_alias) { 59 | return null; 60 | } 61 | } 62 | 63 | if ($request !== null) { 64 | $message->updateArgs($this->ns_uri, 65 | $this->getExtensionArgs($request)); 66 | } else { 67 | $message->updateArgs($this->ns_uri, 68 | $this->getExtensionArgs()); 69 | } 70 | return $message; 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Auth/OpenID/HMAC.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2005-2008 Janrain, Inc. 14 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 | */ 16 | 17 | require_once 'Auth/OpenID.php'; 18 | 19 | /** 20 | * SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback 21 | * implementation. 22 | */ 23 | define('Auth_OpenID_SHA1_BLOCKSIZE', 64); 24 | 25 | function Auth_OpenID_SHA1($text) 26 | { 27 | if (function_exists('hash') && 28 | function_exists('hash_algos') && 29 | (in_array('sha1', hash_algos()))) { 30 | // PHP 5 case (sometimes): 'hash' available and 'sha1' algo 31 | // supported. 32 | return hash('sha1', $text, true); 33 | } else if (function_exists('sha1')) { 34 | // PHP 4 case: 'sha1' available. 35 | $hex = sha1($text); 36 | $raw = ''; 37 | for ($i = 0; $i < 40; $i += 2) { 38 | $hexcode = substr($hex, $i, 2); 39 | $charcode = (int)base_convert($hexcode, 16, 10); 40 | $raw .= chr($charcode); 41 | } 42 | return $raw; 43 | } else { 44 | // Explode. 45 | trigger_error('No SHA1 function found', E_USER_ERROR); 46 | return false; 47 | } 48 | } 49 | 50 | /** 51 | * Compute an HMAC/SHA1 hash. 52 | * 53 | * @access private 54 | * @param string $key The HMAC key 55 | * @param string $text The message text to hash 56 | * @return string $mac The MAC 57 | */ 58 | function Auth_OpenID_HMACSHA1($key, $text) 59 | { 60 | if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) { 61 | $key = Auth_OpenID_SHA1($key); 62 | } 63 | 64 | if (function_exists('hash_hmac') && 65 | function_exists('hash_algos') && 66 | (in_array('sha1', hash_algos()))) { 67 | return hash_hmac('sha1', $text, $key, true); 68 | } 69 | // Home-made solution 70 | 71 | $key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00)); 72 | $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); 73 | $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); 74 | $hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text); 75 | $hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1); 76 | return $hmac; 77 | } 78 | 79 | if (function_exists('hash') && 80 | function_exists('hash_algos') && 81 | (in_array('sha256', hash_algos()))) { 82 | function Auth_OpenID_SHA256($text) 83 | { 84 | // PHP 5 case: 'hash' available and 'sha256' algo supported. 85 | return hash('sha256', $text, true); 86 | } 87 | define('Auth_OpenID_SHA256_SUPPORTED', true); 88 | } else { 89 | define('Auth_OpenID_SHA256_SUPPORTED', false); 90 | } 91 | 92 | if (function_exists('hash_hmac') && 93 | function_exists('hash_algos') && 94 | (in_array('sha256', hash_algos()))) { 95 | 96 | function Auth_OpenID_HMACSHA256($key, $text) 97 | { 98 | // Return raw MAC (not hex string). 99 | return hash_hmac('sha256', $text, $key, true); 100 | } 101 | 102 | define('Auth_OpenID_HMACSHA256_SUPPORTED', true); 103 | } else { 104 | define('Auth_OpenID_HMACSHA256_SUPPORTED', false); 105 | } 106 | 107 | -------------------------------------------------------------------------------- /Auth/OpenID/KVForm.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2005-2008 Janrain, Inc. 15 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 16 | */ 17 | 18 | /** 19 | * Container for key-value/comma-newline OpenID format and parsing 20 | */ 21 | class Auth_OpenID_KVForm { 22 | /** 23 | * Convert an OpenID colon/newline separated string into an 24 | * associative array 25 | * 26 | * @static 27 | * @access private 28 | * @param string $kvs 29 | * @param bool $strict 30 | * @return array|bool 31 | */ 32 | static function toArray($kvs, $strict=false) 33 | { 34 | $lines = explode("\n", $kvs); 35 | 36 | $last = array_pop($lines); 37 | if ($last !== '') { 38 | array_push($lines, $last); 39 | if ($strict) { 40 | return false; 41 | } 42 | } 43 | 44 | $values = []; 45 | 46 | for ($lineno = 0; $lineno < count($lines); $lineno++) { 47 | $line = $lines[$lineno]; 48 | $kv = explode(':', $line, 2); 49 | if (count($kv) != 2) { 50 | if ($strict) { 51 | return false; 52 | } 53 | continue; 54 | } 55 | 56 | $key = $kv[0]; 57 | $tkey = trim($key); 58 | if ($tkey != $key) { 59 | if ($strict) { 60 | return false; 61 | } 62 | } 63 | 64 | $value = $kv[1]; 65 | $tval = trim($value); 66 | if ($tval != $value) { 67 | if ($strict) { 68 | return false; 69 | } 70 | } 71 | 72 | $values[$tkey] = $tval; 73 | } 74 | 75 | return $values; 76 | } 77 | 78 | /** 79 | * Convert an array into an OpenID colon/newline separated string 80 | * 81 | * @static 82 | * @access private 83 | * @param null|array $values 84 | * @return null|string 85 | */ 86 | static function fromArray($values) 87 | { 88 | if ($values === null) { 89 | return null; 90 | } 91 | 92 | ksort($values); 93 | 94 | $serialized = ''; 95 | foreach ($values as $key => $value) { 96 | if (is_array($value)) { 97 | list($key, $value) = [$value[0], $value[1]]; 98 | } 99 | 100 | if (strpos($key, ':') !== false) { 101 | return null; 102 | } 103 | 104 | if (strpos($key, "\n") !== false) { 105 | return null; 106 | } 107 | 108 | if (strpos($value, "\n") !== false) { 109 | return null; 110 | } 111 | $serialized .= "$key:$value\n"; 112 | } 113 | return $serialized; 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /Auth/OpenID/MySQLStore.php: -------------------------------------------------------------------------------- 1 | sql['nonce_table'] = 26 | "CREATE TABLE %s (\n". 27 | " server_url VARCHAR(2047) NOT NULL,\n". 28 | " timestamp INTEGER NOT NULL,\n". 29 | " salt CHAR(40) NOT NULL,\n". 30 | " UNIQUE (server_url(255), timestamp, salt)\n". 31 | ") ENGINE=InnoDB"; 32 | 33 | $this->sql['assoc_table'] = 34 | "CREATE TABLE %s (\n". 35 | " server_url VARCHAR(2047) NOT NULL,\n". 36 | " handle VARCHAR(255) NOT NULL,\n". 37 | " secret BLOB NOT NULL,\n". 38 | " issued INTEGER NOT NULL,\n". 39 | " lifetime INTEGER NOT NULL,\n". 40 | " assoc_type VARCHAR(64) NOT NULL,\n". 41 | " PRIMARY KEY (server_url(255), handle)\n". 42 | ") ENGINE=InnoDB"; 43 | 44 | $this->sql['set_assoc'] = 45 | "REPLACE INTO %s (server_url, handle, secret, issued,\n". 46 | " lifetime, assoc_type) VALUES (?, ?, !, ?, ?, ?)"; 47 | 48 | $this->sql['get_assocs'] = 49 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 50 | "WHERE server_url = ?"; 51 | 52 | $this->sql['get_assoc'] = 53 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 54 | "WHERE server_url = ? AND handle = ?"; 55 | 56 | $this->sql['remove_assoc'] = 57 | "DELETE FROM %s WHERE server_url = ? AND handle = ?"; 58 | 59 | $this->sql['add_nonce'] = 60 | "INSERT INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)"; 61 | 62 | $this->sql['clean_nonce'] = 63 | "DELETE FROM %s WHERE timestamp < ?"; 64 | 65 | $this->sql['clean_assoc'] = 66 | "DELETE FROM %s WHERE issued + lifetime < ?"; 67 | } 68 | 69 | /** 70 | * @access private 71 | */ 72 | function blobEncode($blob) 73 | { 74 | return "0x" . bin2hex($blob); 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /Auth/OpenID/Nonce.php: -------------------------------------------------------------------------------- 1 | sql['nonce_table'] = 26 | "CREATE TABLE %s (server_url VARCHAR(2047) NOT NULL, ". 27 | "timestamp INTEGER NOT NULL, ". 28 | "salt CHAR(40) NOT NULL, ". 29 | "UNIQUE (server_url, timestamp, salt))"; 30 | 31 | $this->sql['assoc_table'] = 32 | "CREATE TABLE %s (server_url VARCHAR(2047) NOT NULL, ". 33 | "handle VARCHAR(255) NOT NULL, ". 34 | "secret BYTEA NOT NULL, ". 35 | "issued INTEGER NOT NULL, ". 36 | "lifetime INTEGER NOT NULL, ". 37 | "assoc_type VARCHAR(64) NOT NULL, ". 38 | "PRIMARY KEY (server_url, handle), ". 39 | "CONSTRAINT secret_length_constraint CHECK ". 40 | "(LENGTH(secret) <= 128))"; 41 | 42 | $this->sql['set_assoc'] = 43 | [ 44 | 'insert_assoc' => "INSERT INTO %s (server_url, handle, ". 45 | "secret, issued, lifetime, assoc_type) VALUES ". 46 | "(?, ?, '!', ?, ?, ?)", 47 | 'update_assoc' => "UPDATE %s SET secret = '!', issued = ?, ". 48 | "lifetime = ?, assoc_type = ? WHERE server_url = ? AND ". 49 | "handle = ?" 50 | ]; 51 | 52 | $this->sql['get_assocs'] = 53 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 54 | "WHERE server_url = ?"; 55 | 56 | $this->sql['get_assoc'] = 57 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 58 | "WHERE server_url = ? AND handle = ?"; 59 | 60 | $this->sql['remove_assoc'] = 61 | "DELETE FROM %s WHERE server_url = ? AND handle = ?"; 62 | 63 | $this->sql['add_nonce'] = 64 | "INSERT INTO %s (server_url, timestamp, salt) VALUES ". 65 | "(?, ?, ?)" 66 | ; 67 | 68 | $this->sql['clean_nonce'] = 69 | "DELETE FROM %s WHERE timestamp < ?"; 70 | 71 | $this->sql['clean_assoc'] = 72 | "DELETE FROM %s WHERE issued + lifetime < ?"; 73 | } 74 | 75 | /** 76 | * @access private 77 | */ 78 | function _set_assoc($server_url, $handle, $secret, $issued, $lifetime, 79 | $assoc_type) 80 | { 81 | $result = $this->_get_assoc($server_url, $handle); 82 | if ($result) { 83 | // Update the table since this associations already exists. 84 | $this->connection->query($this->sql['set_assoc']['update_assoc'], 85 | [ 86 | $secret, 87 | $issued, 88 | $lifetime, 89 | $assoc_type, 90 | $server_url, 91 | $handle, 92 | ]); 93 | } else { 94 | // Insert a new record because this association wasn't 95 | // found. 96 | $this->connection->query($this->sql['set_assoc']['insert_assoc'], 97 | [ 98 | $server_url, 99 | $handle, 100 | $secret, 101 | $issued, 102 | $lifetime, 103 | $assoc_type, 104 | ] 105 | ); 106 | } 107 | } 108 | 109 | /** 110 | * @access private 111 | */ 112 | function blobEncode($blob) 113 | { 114 | return $this->_octify($blob); 115 | } 116 | 117 | /** 118 | * @access private 119 | */ 120 | function blobDecode($blob) 121 | { 122 | return $this->_unoctify($blob); 123 | } 124 | } 125 | 126 | -------------------------------------------------------------------------------- /Auth/OpenID/SQLiteStore.php: -------------------------------------------------------------------------------- 1 | sql['nonce_table'] = 23 | "CREATE TABLE %s (server_url VARCHAR(2047), timestamp INTEGER, ". 24 | "salt CHAR(40), UNIQUE (server_url, timestamp, salt))"; 25 | 26 | $this->sql['assoc_table'] = 27 | "CREATE TABLE %s (server_url VARCHAR(2047), handle VARCHAR(255), ". 28 | "secret BLOB(128), issued INTEGER, lifetime INTEGER, ". 29 | "assoc_type VARCHAR(64), PRIMARY KEY (server_url, handle))"; 30 | 31 | $this->sql['set_assoc'] = 32 | "INSERT OR REPLACE INTO %s VALUES (?, ?, ?, ?, ?, ?)"; 33 | 34 | $this->sql['get_assocs'] = 35 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 36 | "WHERE server_url = ?"; 37 | 38 | $this->sql['get_assoc'] = 39 | "SELECT handle, secret, issued, lifetime, assoc_type FROM %s ". 40 | "WHERE server_url = ? AND handle = ?"; 41 | 42 | $this->sql['remove_assoc'] = 43 | "DELETE FROM %s WHERE server_url = ? AND handle = ?"; 44 | 45 | $this->sql['add_nonce'] = 46 | "INSERT INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)"; 47 | 48 | $this->sql['clean_nonce'] = 49 | "DELETE FROM %s WHERE timestamp < ?"; 50 | 51 | $this->sql['clean_assoc'] = 52 | "DELETE FROM %s WHERE issued + lifetime < ?"; 53 | } 54 | 55 | /** 56 | * @access private 57 | */ 58 | function _add_nonce($server_url, $timestamp, $salt) 59 | { 60 | // PECL SQLite extensions 1.0.3 and older (1.0.3 is the 61 | // current release at the time of this writing) have a broken 62 | // sqlite_escape_string function that breaks when passed the 63 | // empty string. Prefixing all strings with one character 64 | // keeps them unique and avoids this bug. The nonce table is 65 | // write-only, so we don't have to worry about updating other 66 | // functions with this same bad hack. 67 | return parent::_add_nonce('x' . $server_url, $timestamp, $salt); 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /Auth/OpenID/ServerRequest.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2005-2008 Janrain, Inc. 14 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 | */ 16 | 17 | /** 18 | * Imports 19 | */ 20 | require_once "Auth/OpenID.php"; 21 | 22 | /** 23 | * Object that holds the state of a request to the OpenID server 24 | * 25 | * With accessor functions to get at the internal request data. 26 | * 27 | * @see Auth_OpenID_Server 28 | * @package OpenID 29 | */ 30 | class Auth_OpenID_ServerRequest { 31 | public $mode = null; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /Auth/Yadis/Misc.php: -------------------------------------------------------------------------------- 1 | 8 | * @copyright 2005-2008 Janrain, Inc. 9 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 10 | */ 11 | 12 | function Auth_Yadis_getUCSChars() 13 | { 14 | return [ 15 | [0xA0, 0xD7FF], 16 | [0xF900, 0xFDCF], 17 | [0xFDF0, 0xFFEF], 18 | [0x10000, 0x1FFFD], 19 | [0x20000, 0x2FFFD], 20 | [0x30000, 0x3FFFD], 21 | [0x40000, 0x4FFFD], 22 | [0x50000, 0x5FFFD], 23 | [0x60000, 0x6FFFD], 24 | [0x70000, 0x7FFFD], 25 | [0x80000, 0x8FFFD], 26 | [0x90000, 0x9FFFD], 27 | [0xA0000, 0xAFFFD], 28 | [0xB0000, 0xBFFFD], 29 | [0xC0000, 0xCFFFD], 30 | [0xD0000, 0xDFFFD], 31 | [0xE1000, 0xEFFFD], 32 | ]; 33 | } 34 | 35 | function Auth_Yadis_getIPrivateChars() 36 | { 37 | return [ 38 | [0xE000, 0xF8FF], 39 | [0xF0000, 0xFFFFD], 40 | [0x100000, 0x10FFFD], 41 | ]; 42 | } 43 | 44 | function Auth_Yadis_pct_escape_unicode($char_match) 45 | { 46 | $c = $char_match[0]; 47 | $result = ""; 48 | for ($i = 0; $i < strlen($c); $i++) { 49 | $result .= "%" . sprintf("%X", ord($c[$i])); 50 | } 51 | return $result; 52 | } 53 | 54 | function Auth_Yadis_startswith($s, $stuff) 55 | { 56 | return strpos($s, $stuff) === 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Auth/Yadis/XRIRes.php: -------------------------------------------------------------------------------- 1 | fetcher = $fetcher; 18 | $this->proxy_url = $proxy_url; 19 | if (!$this->proxy_url) { 20 | $this->proxy_url = Auth_Yadis_getDefaultProxy(); 21 | } 22 | } 23 | 24 | function queryURL($xri, $service_type = null) 25 | { 26 | // trim off the xri:// prefix 27 | $qxri = substr(Auth_Yadis_toURINormal($xri), 6); 28 | $hxri = $this->proxy_url . $qxri; 29 | $args = [ 30 | '_xrd_r' => 'application/xrds+xml', 31 | ]; 32 | 33 | if ($service_type) { 34 | $args['_xrd_t'] = $service_type; 35 | } else { 36 | // Don't perform service endpoint selection. 37 | $args['_xrd_r'] .= ';sep=false'; 38 | } 39 | 40 | $query = Auth_Yadis_XRIAppendArgs($hxri, $args); 41 | return $query; 42 | } 43 | 44 | function query($xri, $service_types, $filters = []) 45 | { 46 | $services = []; 47 | $canonicalID = null; 48 | foreach ($service_types as $service_type) { 49 | $url = $this->queryURL($xri, $service_type); 50 | $response = $this->fetcher->get($url); 51 | if ($response->status != 200 and $response->status != 206) { 52 | continue; 53 | } 54 | $xrds = Auth_Yadis_XRDS::parseXRDS($response->body); 55 | if (!$xrds) { 56 | continue; 57 | } 58 | $canonicalID = Auth_Yadis_getCanonicalID($xri, 59 | $xrds); 60 | 61 | if ($canonicalID === false) { 62 | return null; 63 | } 64 | 65 | $some_services = $xrds->services($filters); 66 | $services = array_merge($services, $some_services); 67 | // TODO: 68 | // * If we do get hits for multiple service_types, we're 69 | // almost certainly going to have duplicated service 70 | // entries and broken priority ordering. 71 | } 72 | return [$canonicalID, $services]; 73 | } 74 | } 75 | 76 | 77 | -------------------------------------------------------------------------------- /CHANGES-2.1.0: -------------------------------------------------------------------------------- 1 | * API Changes 2 | * AX::FetchResponse::fromSuccessResponse - return null when AX 3 | response arguments are absent 4 | * Alter AX fromOpenIDRequest() to take Auth_OpenID_AuthRequest 5 | object instead of Auth_OpenID_Message object so that it matches 6 | its counterpart methods in SREG and PAPE extensions. 7 | * PAPE (Provider Authentication Policy Extension) module 8 | * Updated extension for specification draft 2 9 | * Auth_OpenID_PAPE_Request::fromSuccessResponse returns None if 10 | PAPE response arguments were not signed 11 | * Added functions to generate request/response HTML forms with 12 | auto-submission javascript 13 | * Consumer (relying party) API: 14 | Auth_OpenID_AuthRequest::htmlMarkup 15 | * Server API: Auth_OpenID_OpenIDResponse::toHTML 16 | 17 | * New Features 18 | * Added examples/discover.php, an OpenID service discovery tool 19 | * Add optional form_tag_attrs argument to 20 | Auth_OpenID_ServerResponse::toFormMarkup for setting arbitrary 21 | FORM element attributes 22 | * Fetchers now only read/request first megabyte of response 23 | 24 | * Bug Fixes 25 | * NOT NULL constraints were added to SQLStore tables where 26 | appropriate 27 | * Yadis discovery now properly falls back to HTML-based discovery if 28 | it fails to get an XRDS document 29 | * Auth_OpenID_Decoder now behaves correctly when given a protocol 30 | message with an invalid OpenID namespace or a missing OpenID mode 31 | * Auth_OpenID_OpenIDResponse::toFormMarkup: Use return_to from the 32 | request, not the response fields (Not all responses (i.e. cancel, 33 | setup_needed) include a return_to field.) 34 | * normalize return_to URL before performing return_to verification 35 | * Auth_OpenID_Consumer::_verifyDiscoveryResults: fall back to OpenID 36 | 1.0 type if 1.1 endpoint cannot be found 37 | * Auth_Yadis_ParanoidHTTPFetcher now works correctly with both array 38 | and non-array CURL versions 39 | * Clarified licensing language in all source files 40 | * OpenID 1 association requests no longer explicitly set 41 | no-encryption session type 42 | * Auth_OpenID_ServiceEndpoint::getDisplayIdentifier no longer 43 | includes a fragment, if present, in display identifiers 44 | * check_authentication requests: copy entire response, not just 45 | signed fields. Fixes missing namespace in check_authentication 46 | requests 47 | * Yadis discovery now includes application/xhtml+xml and qualities 48 | in the Accept header 49 | * Normalize URLs correctly with URINorm.php 50 | * Auth_OpenID_MySQLStore: Use ENGINE instead of TYPE when creating 51 | tables 52 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # News 2 | 3 | ## PHP OpenID 3.0 4 | 5 | The PHP OpenID project is now going to be strictly enforcing 6 | [SEMVER](http://semver.org/). In short, this means versions 7 | will be `MAJOR`.`MINOR`.`PATCH`. `MAJOR` indicates either 8 | backwards incompatible changes or major platform shifts. `MINOR` 9 | releases will indicate backwards compatible changes that add new 10 | features. `PATCH` are bug fix releases. Going forward, it is 11 | recommeneded users subscribe to all releases in the 3.X series. 12 | 13 | 14 | 15 | ## PHP OpenID 2.0 16 | 17 | This library implements both the OpenID 1 and OpenID 2 protocols. The 18 | API changes in this version of the library are minimal and mostly 19 | backwards-compatible with current RP and Server implementations. If 20 | you're already using this library for OpenID 1, only a few small 21 | changes (see Summary below) will be needed once you upgrade. 22 | 23 | The big news here is compatibility with version 2.0 of the OpenID 24 | protocol. Highlights include: 25 | 26 | * Simple Registration support in a new module `Auth/OpenID/SReg.php`. 27 | (Those previously using 28 | `Auth_OpenID_SuccessResponse::extensionResponse()` are advised to 29 | look here and at the example consumer and server for detailed usage 30 | information.) 31 | * OpenID provider-driven identifier selection. 32 | * "Negotiators" allow you to define which association types to use. 33 | * Improved `examples/detect.php` script (bugs fixed) 34 | * Improved layout of example consumer (see examples/consumer) 35 | * An improved HTML parser implementation 36 | * Library is now immune to being included inside functions and 37 | methods 38 | * Fixes to avoid multibyte overloading problems 39 | 40 | If you've written your own custom store or code that interacts 41 | directly with it, you'll need to review the change notes for 42 | `Auth_OpenID_Interface` in `Auth/OpenID/Interface.php`. 43 | 44 | 45 | ### Upgrading from earlier versions of this library 46 | 47 | One of the additions to the OpenID protocol was a specified nonce 48 | format for one-way nonces. As a result, the nonce table in the 49 | SQL-driven stores has changed. You'll need to run the Python script 50 | `contrib/upgrade-store-1.1-to-2.0` to upgrade your store, or you'll 51 | encounter errors about the wrong number of columns in the oid_nonces 52 | table. To run the script, you'll need a python module supporting your 53 | database type: pysqlite2, psycopg, or MySQLdb. 54 | 55 | If you cannot run the Python script, you can re-create your store by 56 | dropping the tables in the store and calling `createTables()` on the 57 | store object. 58 | 59 | Consumers should now pass the consumer `return_to` URL to 60 | `Auth_OpenID_Consumer::complete()` to defend against return_to URL 61 | tampering. This has REPLACED the old parameter, `$query`. `$query` is 62 | now a second optional parameter. It is **STRONGLY RECOMMENDED** that you 63 | never override $query, since the OpenID library uses its own logic to 64 | sidestep PHP's broken request-processing code. 65 | 66 | 67 | ### Summary of API Changes 68 | 69 | - `Auth_OpenID::fixArgs` is now no longer necessary, and 70 | `Auth_OpenID_Consumer::complete` and `Auth_OpenID_Server::decodeRequest` 71 | no longer take query argument arrays. *You should no longer pass any 72 | parameters to these methods.* 73 | 74 | - `Auth_OpenID_SuccessResponse::extensionResponse()` is no longer the 75 | preferred way to extract extension response parameters from the OpenID 76 | response. Instead, see the `Auth/OpenID/SReg.php` module and the 77 | example consumer and server for detailed usage information on 78 | constructing Simple Registration requests and inspecting responses. 79 | `extensionResponse()` is still valid, but now takes a second parameter 80 | (bool) indicating whether extension args should be signed. 81 | 82 | - The `Auth_OpenID_Server`'s response `answer()` method now takes 83 | additional parameters to support provider-driven identifier selection. 84 | See the example server and the documentation for 85 | `Auth_OpenID_CheckIDRequest::answer`. 86 | 87 | - `Auth_OpenID_Consumer::complete()` now takes two args: 88 | 89 | - `$return_to`, a required string that is the return URL passed to 90 | `Auth_OpenID_AuthRequest::redirectURL()` 91 | 92 | - `$query`, an optional array (or null if absent) denoting the query 93 | parameters of the OpenID response. If null, the response data 94 | will be extracted from the PHP request environment. Library 95 | users **SHOULD NOT** ever pass anything for `$query` unless they're 96 | testing the library. 97 | -------------------------------------------------------------------------------- /README.Debian: -------------------------------------------------------------------------------- 1 | Development Environment Setup 2 | ============================= 3 | 4 | Janrain note: You'll need to run these commands to generate 5 | documentation for this project: 6 | 7 | apt-get install php4-pear 8 | pear install PhpDocumentor 9 | -------------------------------------------------------------------------------- /README.git: -------------------------------------------------------------------------------- 1 | GitHub is the new home for php-openid library development. 2 | 3 | This library was originally written by JanRain and managed using the darcs RCS. This file is home to notes regarding the migration from darcs to git, and the move from openidenabled.com to github.com. 4 | 5 | Contact: 6 | Brian Ellin 7 | brian@janrain.com 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHP OpenID 2 | ========== 3 | 4 | This is the PHP OpenID library by JanRain, Inc. You can visit our 5 | website for more information about this package and other OpenID 6 | implementations and tools: 7 | 8 | http://www.openidenabled.com/ 9 | 10 | ## Getting Started 11 | 12 | First, run the `examples/detect.php` script either from the command 13 | line or via the web. It will generate a report of any system 14 | configuration changes necessary to run the library. 15 | 16 | ## Installation 17 | 18 | You will need **PHP 5.6.0 or greater** to use this library. 19 | 20 | Follow these steps: 21 | 22 | 1. Install dependencies. 23 | 24 | - Enable either the **GMP extension or Bcmath extension**. (GMP is 25 | STRONGLY recommended because it's MUCH faster!) This is 26 | required. 27 | 28 | - Enable the **CURL extension**. 29 | 30 | - If you plan to use SQLite, PostgreSQL, or MySQL to store OpenID 31 | data, you'll need **PEAR MDB2**. You can install this by running this 32 | as root: 33 | 34 | ```bash 35 | pear install MDB2 36 | ``` 37 | 38 | You'll also need to install and enable the appropriate PHP 39 | database extension. Alternatively, you can store OpenID data on 40 | the filesystem instead of using a relational database. Nothing 41 | special is required for using the filesystem method. 42 | 43 | - Install either the **DOM or domxml PHP XML processing extension**, 44 | but not both (they are incompatible). 45 | 46 | 2. Copy the `Auth/` directory into your PHP include path. 47 | 48 | ## Testing Your Setup 49 | 50 | You can use the example code to test your setup. To run the example 51 | consumer or server, follow the instructions in the `examples/README.md` 52 | file. 53 | 54 | ## Using the API 55 | 56 | The best way to get started using the API is to take a look at the 57 | example consumer and server in the `examples/` directory. See the 58 | `examples/README.md` file for more details. 59 | 60 | ## Troubleshooting 61 | 62 | * If you're unable to use an OpenID URL with the library, you may want 63 | to try using the discover tool (`examples/discover.php`). This tool 64 | will perform OpenID discovery on the identifier and give a list of 65 | discovered OpenID services and their types. 66 | 67 | * On some systems, PHP basedir restrictions prevent web servers from 68 | opening a source of randomness, such as `/dev/urandom`. If your PHP 69 | OpenID library has trouble getting a satisfactory source of 70 | randomness, check your Apache and PHP configurations to be sure that 71 | the randomness source is in the list of allowed paths for the 72 | `open_basedir` option. 73 | 74 | * In some cases, bugs in the GMP math library will result in signature 75 | validation errors when using this library. Since GMP is preferred 76 | over bcmath (for performance), you will have to define 77 | `Auth_OpenID_BUGGY_GMP` in your application *before* importing any of 78 | the library code: 79 | 80 | ```php 81 | define('Auth_OpenID_BUGGY_GMP', true); 82 | ``` 83 | 84 | * Not all PHP installations support SSL. You can find out if yours 85 | supports SSL by reading the "HTTP Fetching" section of the output of 86 | `examples/detect.php.` If your installation does not support SSL, 87 | then `https://` identity URLs and server URLs will not be supported by 88 | the library. An attempt to use such an identity URL will be 89 | equivalent to using an invalid OpenID. To enable SSL support, 90 | recompile PHP with OpenSSL support or install the appropriate OpenSSL 91 | module for your platform. If you are using CURL, CURL will need to be 92 | built with OpenSSL support. 93 | 94 | ## Getting Help 95 | 96 | If you have any questions, recommendations, or patches, please tell 97 | us! Subscribe to our OpenID development discussion list at 98 | 99 | https://openid.net/developers/dev-mailing-lists/ 100 | 101 | ## Documentation 102 | 103 | You can view the HTML library documentation in the `doc/` directory. 104 | 105 | This package's documentation is in PhpDoc format. To generate the 106 | documentation, install phpdoc and run the admin/makedoc.sh script. 107 | Phpdoc lives at: 108 | 109 | https://www.phpdoc.org/ 110 | 111 | ## Contributing 112 | 113 | If you have a bugfix or feature you'd like to contribute, don't 114 | hesitate to send it to us. Post your patch to the development list at 115 | 116 | https://openid.net/developers/dev-mailing-lists/ 117 | 118 | For more detailed information on how to contribute, see 119 | 120 | http://openidenabled.com/contribute/ 121 | 122 | To run the test suite included with this package, install PHPUnit 1.x 123 | and run 124 | 125 | ```bash 126 | php admin/texttest.php 127 | ``` 128 | 129 | PHPUnit 1.x can be found at 130 | 131 | http://pear.phpunit.de/get/ 132 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/Association.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2005-2008 Janrain, Inc. 13 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 14 | */ 15 | 16 | require_once 'Auth/OpenID/Association.php'; 17 | 18 | class Tests_Auth_OpenID_Association extends PHPUnit_Framework_TestCase { 19 | function test_me() 20 | { 21 | $issued = time(); 22 | $lifetime = 600; 23 | $assoc = new Auth_OpenID_Association('handle', 'secret', $issued, 24 | $lifetime, 'HMAC-SHA1'); 25 | $s = $assoc->serialize(); 26 | $assoc2 = Auth_OpenID_Association::deserialize( 27 | 'Auth_OpenID_Association', $s); 28 | 29 | if ($assoc2 === null) { 30 | $this->fail('deserialize returned null'); 31 | } else { 32 | $this->assertTrue($assoc2->equal($assoc)); 33 | } 34 | } 35 | function test_me256() 36 | { 37 | if(!Auth_OpenID_HMACSHA256_SUPPORTED) return; 38 | $issued = time(); 39 | $lifetime = 600; 40 | $assoc = new Auth_OpenID_Association('handle', 'secret', $issued, 41 | $lifetime, 'HMAC-SHA256'); 42 | $s = $assoc->serialize(); 43 | $assoc2 = Auth_OpenID_Association::deserialize( 44 | 'Auth_OpenID_Association', $s); 45 | 46 | if ($assoc2 === null) { 47 | $this->fail('deserialize returned null'); 48 | } else { 49 | $this->assertTrue($assoc2->equal($assoc)); 50 | } 51 | } 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/CryptUtil.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2005-2008 Janrain, Inc. 13 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 14 | */ 15 | 16 | require_once 'Auth/OpenID.php'; 17 | require_once 'Auth/OpenID/CryptUtil.php'; 18 | 19 | class Tests_Auth_OpenID_CryptUtil extends PHPUnit_Framework_TestCase { 20 | function test_length() 21 | { 22 | $cases = [1, 10, 255]; 23 | foreach ($cases as $length) { 24 | $data = Auth_OpenID_CryptUtil::getBytes($length); 25 | $this->assertEquals(Auth_OpenID::bytes($data), $length); 26 | } 27 | } 28 | 29 | function test_different() 30 | { 31 | $num_iterations = 100; 32 | $data_length = 20; 33 | 34 | $data = Auth_OpenID_CryptUtil::getBytes($num_iterations); 35 | for ($i = 0; $i < $num_iterations; $i++) { 36 | $last = $data; 37 | $data = Auth_OpenID_CryptUtil::getBytes($data_length); 38 | $this->assertFalse($data == $last); 39 | } 40 | } 41 | 42 | function test_cryptrand() 43 | { 44 | // It's possible, but HIGHLY unlikely that a correct 45 | // implementation will fail by returning the same number twice 46 | 47 | $s = Auth_OpenID_CryptUtil::getBytes(32); 48 | $t = Auth_OpenID_CryptUtil::getBytes(32); 49 | $this->assertEquals(Auth_OpenID::bytes($s), 32); 50 | $this->assertEquals(Auth_OpenID::bytes($t), 32); 51 | $this->assertFalse($s == $t); 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/Extension.php: -------------------------------------------------------------------------------- 1 | toMessage($oid1_msg); 22 | $namespaces = $oid1_msg->namespaces; 23 | 24 | $this->assertTrue($namespaces->isImplicit($ext->ns_uri)); 25 | $this->assertEquals($ext->ns_uri, 26 | $namespaces->getNamespaceURI($ext->ns_alias)); 27 | $this->assertEquals($ext->ns_alias, 28 | $namespaces->getAlias($ext->ns_uri)); 29 | } 30 | 31 | function test_OpenID2() 32 | { 33 | $oid2_msg = new Auth_OpenID_Message(Auth_OpenID_OPENID2_NS); 34 | $ext = new _ExtensionTest_DummyExtension(); 35 | $ext->toMessage($oid2_msg); 36 | $namespaces = $oid2_msg->namespaces; 37 | $this->assertFalse($namespaces->isImplicit($ext->ns_uri)); 38 | $this->assertEquals($ext->ns_uri, 39 | $namespaces->getNamespaceURI($ext->ns_alias)); 40 | $this->assertEquals($ext->ns_alias, 41 | $namespaces->getAlias($ext->ns_uri)); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/MemStore.php: -------------------------------------------------------------------------------- 1 | assocs = []; 13 | } 14 | 15 | function set($assoc) 16 | { 17 | $this->assocs[$assoc->handle] = $assoc; 18 | } 19 | 20 | function get($handle) 21 | { 22 | return Auth_OpenID::arrayGet($this->assocs, $handle); 23 | } 24 | 25 | function remove($handle) 26 | { 27 | if (array_key_exists($handle, $this->assocs)) { 28 | unset($this->assocs[$handle]); 29 | return true; 30 | } else { 31 | return false; 32 | } 33 | } 34 | 35 | /* 36 | * Returns association with the oldest issued date. 37 | * 38 | * or null if there are no associations. 39 | */ 40 | function best() 41 | { 42 | $best = null; 43 | foreach ($this->assocs as $handle => $assoc) { 44 | if (($best === null) || ($best->issued < $assoc->issued)) { 45 | $best = $assoc; 46 | } 47 | } 48 | return $best; 49 | } 50 | 51 | /* 52 | * Remove expired associations. 53 | * 54 | * @return (removed associations, remaining associations) 55 | */ 56 | function cleanup() 57 | { 58 | $remove = []; 59 | foreach ($this->assocs as $handle => $assoc) { 60 | if ($assoc->getExpiresIn() == 0) { 61 | $remove[] = $handle; 62 | } 63 | } 64 | 65 | foreach ($remove as $handle) { 66 | unset($this->assocs[$handle]); 67 | } 68 | 69 | return [count($remove), count($this->assocs)]; 70 | } 71 | } 72 | 73 | /* 74 | * In-process memory store. 75 | * 76 | * Use for single long-running processes. No persistence supplied. 77 | */ 78 | class Tests_Auth_OpenID_MemStore extends Auth_OpenID_OpenIDStore { 79 | function __construct() 80 | { 81 | $this->server_assocs = []; 82 | $this->nonces = []; 83 | } 84 | 85 | function &_getServerAssocs($server_url) 86 | { 87 | if (!array_key_exists($server_url, $this->server_assocs)) { 88 | $this->server_assocs[$server_url] = new ServerAssocs(); 89 | } 90 | 91 | return $this->server_assocs[$server_url]; 92 | } 93 | 94 | function storeAssociation($server_url, $assoc) 95 | { 96 | $assocs =& $this->_getServerAssocs($server_url); 97 | $assocs->set($assoc); 98 | } 99 | 100 | function getAssociation($server_url, $handle=null) 101 | { 102 | $assocs =& $this->_getServerAssocs($server_url); 103 | if ($handle === null) { 104 | return $assocs->best(); 105 | } else { 106 | return $assocs->get($handle); 107 | } 108 | } 109 | 110 | function removeAssociation($server_url, $handle) 111 | { 112 | $assocs =& $this->_getServerAssocs($server_url); 113 | return $assocs->remove($handle); 114 | } 115 | 116 | function useNonce($server_url, $timestamp, $salt) 117 | { 118 | global $Auth_OpenID_SKEW; 119 | 120 | if (abs($timestamp - time()) > $Auth_OpenID_SKEW) { 121 | return false; 122 | } 123 | 124 | $anonce = [$server_url, intval($timestamp), $salt]; 125 | 126 | if (in_array($anonce, $this->nonces)) { 127 | return false; 128 | } else { 129 | array_push($this->nonces, $anonce); 130 | return true; 131 | } 132 | } 133 | 134 | function cleanupNonces() 135 | { 136 | global $Auth_OpenID_SKEW; 137 | 138 | $now = time(); 139 | $expired = []; 140 | foreach ($this->nonces as $anonce) { 141 | if (abs($anonce[1] - $now) > $Auth_OpenID_SKEW) { 142 | // removing items while iterating over the set could 143 | // be bad. 144 | $expired[] = $anonce; 145 | } 146 | } 147 | 148 | foreach ($expired as $anonce) { 149 | unset($this->nonces[array_search($anonce, $this->nonces)]); 150 | } 151 | 152 | return count($expired); 153 | } 154 | 155 | function cleanupAssociations() 156 | { 157 | $remove_urls = []; 158 | $removed_assocs = 0; 159 | foreach ($this->server_assocs as $server_url => $assocs) { 160 | list($removed, $remaining) = $assocs->cleanup(); 161 | $removed_assocs += $removed; 162 | if (!$remaining) { 163 | $remove_urls[] = $server_url; 164 | } 165 | } 166 | 167 | // Remove entries from server_assocs that had none remaining. 168 | foreach ($remove_urls as $server_url) { 169 | unset($this->server_assocs[$server_url]); 170 | } 171 | 172 | return $removed_assocs; 173 | } 174 | } 175 | 176 | 177 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/Nonce.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2006 Janrain, Inc. 13 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 14 | */ 15 | 16 | require_once 'Auth/OpenID/Nonce.php'; 17 | 18 | define('Tests_Auth_OpenID_nonce_re', 19 | '/\A\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/'); 20 | 21 | class Tests_Auth_OpenID_Nonce extends PHPUnit_Framework_TestSuite { 22 | function __construct() 23 | { 24 | $this->addTestSuite('Tests_Auth_OpenID_NonceTests'); 25 | $this->makeSplitTests(); 26 | $this->makeCheckTimestampTests(); 27 | $this->setName('Tests_Auth_OpenID_Nonce'); 28 | } 29 | 30 | function makeSplitTests() 31 | { 32 | $cases = [ 33 | '', 34 | '1970-01-01T00:00:00+1:00', 35 | '1969-01-01T00:00:00Z', 36 | '1970-00-01T00:00:00Z', 37 | '1970.01-01T00:00:00Z', 38 | 'Thu Sep 7 13:29:31 PDT 2006', 39 | 'monkeys', 40 | ]; 41 | 42 | foreach ($cases as $nonce_str) { 43 | $this->_mkSplitTest($nonce_str); 44 | } 45 | } 46 | 47 | function _mkSplitTest($nonce_str) 48 | { 49 | $test = new Tests_Auth_OpenID_Nonce_BadSplitCase($nonce_str); 50 | $test->setName('BadNonceSplit ' . var_export($nonce_str, true)); 51 | $this->addTest($test); 52 | } 53 | 54 | function makeCheckTimestampTests() 55 | { 56 | $cases = [ 57 | // exact, no allowed skew 58 | ['1970-01-01T00:00:00Z', 0, 0, true], 59 | 60 | // exact, large skew 61 | ['1970-01-01T00:00:00Z', 1000, 0, true], 62 | 63 | // no allowed skew, one second old 64 | ['1970-01-01T00:00:00Z', 0, 1, false], 65 | 66 | // many seconds old, outside of skew 67 | ['1970-01-01T00:00:00Z', 10, 50, false], 68 | 69 | // one second old, one second skew allowed 70 | ['1970-01-01T00:00:00Z', 1, 1, true], 71 | 72 | // One second in the future, one second skew allowed 73 | ['1970-01-01T00:00:02Z', 1, 1, true], 74 | 75 | // two seconds in the future, one second skew allowed 76 | ['1970-01-01T00:00:02Z', 1, 0, false], 77 | 78 | // malformed nonce string 79 | ['monkeys', 0, 0, false], 80 | ]; 81 | 82 | foreach ($cases as $case) { 83 | $this->_mkCheckTest($case); 84 | } 85 | } 86 | 87 | function _mkCheckTest($case) 88 | { 89 | list($nonce_str, $skew, $now, $expected) = $case; 90 | $test = new Tests_Auth_OpenID_Nonce_TimestampCase( 91 | $nonce_str, $skew, $now, $expected); 92 | $test->setName('CheckTimestamp ' . var_export($nonce_str, true)); 93 | $this->addTest($test); 94 | } 95 | } 96 | 97 | class Tests_Auth_OpenID_Nonce_TimestampCase extends PHPUnit_Framework_TestCase { 98 | function __construct( 99 | $nonce_str, $skew, $now, $expected) 100 | { 101 | $this->nonce_string = $nonce_str; 102 | $this->allowed_skew = $skew; 103 | $this->now = $now; 104 | $this->expected = $expected; 105 | } 106 | 107 | function runTest() 108 | { 109 | $actual = Auth_OpenID_checkTimestamp($this->nonce_string, 110 | $this->allowed_skew, 111 | $this->now); 112 | $this->assertEquals($this->expected, $actual); 113 | } 114 | } 115 | 116 | class Tests_Auth_OpenID_NonceTests extends PHPUnit_Framework_TestCase { 117 | function test_mkNonce() 118 | { 119 | $nonce_str = Auth_OpenID_mkNonce(); 120 | $this->assertTrue(preg_match(Tests_Auth_OpenID_nonce_re, $nonce_str)); 121 | } 122 | 123 | function test_mkNonce_when() 124 | { 125 | $nonce_str = Auth_OpenID_mkNonce(0); 126 | $this->assertTrue(preg_match(Tests_Auth_OpenID_nonce_re, $nonce_str)); 127 | $tpart = substr($nonce_str, 0, 20); 128 | $this->assertEquals('1970-01-01T00:00:00Z', $tpart); 129 | } 130 | 131 | function test_splitNonce() 132 | { 133 | $s = '1970-01-01T00:00:00Z'; 134 | $expected_t = 0; 135 | $expected_salt = ''; 136 | list($actual_t, $actual_salt) = Auth_OpenID_splitNonce($s); 137 | $this->assertEquals($expected_t, $actual_t); 138 | $this->assertEquals($expected_salt, $actual_salt); 139 | } 140 | 141 | 142 | function test_mkSplit() 143 | { 144 | $t = 42;; 145 | $nonce_str = Auth_OpenID_mkNonce($t); 146 | $this->assertTrue(preg_match(Tests_Auth_OpenID_nonce_re, $nonce_str)); 147 | list($et, $salt) = Auth_OpenID_splitNonce($nonce_str); 148 | $this->assertEquals(6, strlen($salt)); 149 | $this->assertEquals($et, $t); 150 | } 151 | } 152 | 153 | class Tests_Auth_OpenID_Nonce_BadSplitCase extends PHPUnit_Framework_TestCase { 154 | function __construct($nonce_str) 155 | { 156 | $this->nonce_str = $nonce_str; 157 | } 158 | 159 | function runTest() 160 | { 161 | $result = Auth_OpenID_splitNonce($this->nonce_str); 162 | $this->assertNull($result); 163 | } 164 | } 165 | 166 | 167 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/TestUtil.php: -------------------------------------------------------------------------------- 1 | getArg($ns, $key); 39 | $error_format = 'Wrong value for openid.%s: expected=%s, actual=%s'; 40 | $error_message = sprintf($error_format, 41 | $key, $expected, $actual); 42 | 43 | $this->assertEquals($expected, $actual, $error_message); 44 | } 45 | 46 | function failIfOpenIDKeyExists($msg, $key, $ns=null) 47 | { 48 | if ($ns === null) { 49 | $ns = Auth_OpenID_OPENID_NS; 50 | } 51 | 52 | $actual = $msg->getArg($ns, $key); 53 | $error_message = sprintf('openid.%s unexpectedly present: %s', 54 | $key, $actual); 55 | 56 | $this->assertFalse($msg->hasKey($ns, $key), 57 | $error_message); 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/URINorm.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2005-2008 Janrain, Inc. 14 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 | */ 16 | 17 | require_once 'Auth/OpenID/URINorm.php'; 18 | require_once 'Tests/Auth/OpenID/TestUtil.php'; 19 | 20 | class Tests_Auth_OpenID_URINorm_TestCase extends PHPUnit_Framework_TestCase { 21 | function __construct( 22 | $name, $uri, $expected) 23 | { 24 | 25 | $this->setName($name); 26 | $this->uri = $uri; 27 | $this->expected = $expected; 28 | } 29 | 30 | function runTest() 31 | { 32 | $actual = Auth_OpenID_urinorm($this->uri); 33 | $this->assertEquals($this->expected, $actual); 34 | } 35 | } 36 | 37 | class Tests_Auth_OpenID_URINorm extends PHPUnit_Framework_TestSuite { 38 | function _readTestCases() 39 | { 40 | $lines = Tests_Auth_OpenID_readlines('urinorm.txt'); 41 | $cases = []; 42 | $case = []; 43 | for ($i = 0; $i < count($lines) && ($i + 3 <= count($lines)); $i += 4) { 44 | $name = trim($lines[$i]); 45 | $uri = trim($lines[$i + 1]); 46 | $expected = trim($lines[$i + 2]); 47 | if ($expected == 'fail') { 48 | $expected = null; 49 | } 50 | $cases[] = [$name, $uri, $expected]; 51 | } 52 | 53 | return $cases; 54 | } 55 | 56 | function __construct($name) 57 | { 58 | $this->setName($name); 59 | $cases = $this->_readTestCases(); 60 | foreach ($cases as $case) { 61 | list($name, $uri, $expected) = $case; 62 | $this->addTest(new Tests_Auth_OpenID_URINorm_TestCase($name, $uri, $expected)); 63 | } 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/hmac-sha1.txt: -------------------------------------------------------------------------------- 1 | test_case = 1 2 | key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 3 | key_len = 20 4 | data = "Hi There" 5 | data_len = 8 6 | digest = 0xb617318655057264e28bc0b6fb378c8ef146be00 7 | 8 | test_case = 2 9 | key = "Jefe" 10 | key_len = 4 11 | data = "what do ya want for nothing?" 12 | data_len = 28 13 | digest = 0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79 14 | 15 | test_case = 3 16 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 17 | key_len = 20 18 | data = 0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd 19 | data_len = 50 20 | digest = 0x125d7342b9ac11cd91a39af48aa17b4f63f175d3 21 | 22 | test_case = 4 23 | key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 24 | key_len = 25 25 | data = 0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd 26 | data_len = 50 27 | digest = 0x4c9007f4026250c6bc8414f9bf50c86c2d7235da 28 | 29 | test_case = 5 30 | key = 0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c 31 | key_len = 20 32 | data = "Test With Truncation" 33 | data_len = 20 34 | digest = 0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04 35 | digest-96 = 0x4c1a03424b55e07fe7f27be1 36 | 37 | test_case = 6 38 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 39 | key_len = 80 40 | data = "Test Using Larger Than Block-Size Key - Hash Key First" 41 | data_len = 54 42 | digest = 0xaa4ae5e15272d00e95705637ce8a3b55ed402112 43 | 44 | test_case = 7 45 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 46 | key_len = 80 47 | data = "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" 48 | data_len = 73 49 | digest = 0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91 50 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/hmac-sha256.txt: -------------------------------------------------------------------------------- 1 | test_case = 1 2 | key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 3 | data = 0x4869205468657265 4 | digest = 0xb0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7 5 | 6 | test_case = 2 7 | key = 0x4a656665 8 | data = 0x7768617420646f2079612077616e7420666f72206e6f7468696e673f 9 | digest = 0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843 10 | 11 | test_case = 3 12 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 13 | data = 0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd 14 | digest = 0x773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe 15 | 16 | test_case = 4 17 | key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819 18 | data = 0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd 19 | digest = 0x82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b 20 | 21 | test_case = 6 22 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 23 | data = 0x54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374 24 | digest = 0x60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54 25 | 26 | test_case = 7 27 | key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 28 | data = 0x5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e 29 | digest = 0x9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2 30 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/openid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid2_xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://specs.openid.net/auth/2.0/signon 8 | http://www.myopenid.com/server 9 | http://smoker.myopenid.com/ 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid2_xrds_no_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://specs.openid.net/auth/2.0/signon 8 | http://www.myopenid.com/server 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_1_and_2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 |

foo

10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_1_and_2_xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://openid.net/signon/1.1 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | http://smoker.myopenid.com/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_1_and_2_xrds_bad_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://openid.net/signon/1.0 11 | http://openid.net/signon/1.1 12 | http://www.myopenid.com/server 13 | http://smoker.myopenid.com/ 14 | http://localid.mismatch.invalid/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_and_yadis.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 | 9 | 10 |

foo

11 | 12 | 13 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_no_delegate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Identity Page for Smoker 5 | 6 | 7 | 8 |

foo

9 | 10 | 11 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_openid_ssl.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://nossl.vroom.unittest/server 11 | http://smoker.myopenid.com/ 12 | 13 | 14 | http://openid.net/signon/1.0 15 | https://ssl.vroom.unittest/server 16 | http://smoker.myopenid.com/ 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_0entries.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://is-not-openid.unittest/ 9 | http://noffing.unittest./ 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_2_bad_local_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://specs.openid.net/auth/2.0/signon 10 | http://www.myopenid.com/server 11 | http://smoker.myopenid.com/ 12 | http://localid.mismatch.invalid/ 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_2entries_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | =!1000 8 | 9 | 10 | http://openid.net/signon/1.0 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | 14 | 15 | 16 | http://openid.net/signon/1.0 17 | http://www.livejournal.com/openid/server.bml 18 | http://frank.livejournal.com/ 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_2entries_idp.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | =!1000 8 | 9 | 10 | http://specs.openid.net/auth/2.0/signon 11 | http://www.myopenid.com/server 12 | http://smoker.myopenid.com/ 13 | 14 | 15 | 16 | http://specs.openid.net/auth/2.0/server 17 | http://www.livejournal.com/openid/server.bml 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_another_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://vroom.unittest/server 11 | http://smoker.myopenid.com/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_idp.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://specs.openid.net/auth/2.0/server 9 | http://www.myopenid.com/server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_idp_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | http://specs.openid.net/auth/2.0/server 9 | http://www.myopenid.com/server 10 | http://smoker.myopenid.com/ 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/test_discover_yadis_no_delegate.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | http://openid.net/signon/1.0 8 | http://www.myopenid.com/server 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Tests/Auth/OpenID/data/urinorm.txt: -------------------------------------------------------------------------------- 1 | Already normal form 2 | http://example.com/ 3 | http://example.com/ 4 | 5 | Add a trailing slash 6 | http://example.com 7 | http://example.com/ 8 | 9 | Remove an empty port segment 10 | http://example.com:/ 11 | http://example.com/ 12 | 13 | Remove a default port segment 14 | http://example.com:80/ 15 | http://example.com/ 16 | 17 | Capitalization in host names 18 | http://wWw.exaMPLE.COm/ 19 | http://www.example.com/ 20 | 21 | Capitalization in scheme names 22 | htTP://example.com/ 23 | http://example.com/ 24 | 25 | Capitalization in percent-escaped reserved characters 26 | http://example.com/foo%2cbar 27 | http://example.com/foo%2Cbar 28 | 29 | Unescape percent-encoded unreserved characters 30 | http://example.com/foo%2Dbar%2dbaz 31 | http://example.com/foo-bar-baz 32 | 33 | remove_dot_segments example 1 34 | http://example.com/a/b/c/./../../g 35 | http://example.com/a/g 36 | 37 | remove_dot_segments example 2 38 | http://example.com/mid/content=5/../6 39 | http://example.com/mid/6 40 | 41 | remove_dot_segments: single-dot 42 | http://example.com/a/./b 43 | http://example.com/a/b 44 | 45 | remove_dot_segments: double-dot 46 | http://example.com/a/../b 47 | http://example.com/b 48 | 49 | remove_dot_segments: leading double-dot 50 | http://example.com/../b 51 | http://example.com/b 52 | 53 | remove_dot_segments: trailing single-dot 54 | http://example.com/a/. 55 | http://example.com/a/ 56 | 57 | remove_dot_segments: trailing double-dot 58 | http://example.com/a/.. 59 | http://example.com/ 60 | 61 | remove_dot_segments: trailing single-dot-slash 62 | http://example.com/a/./ 63 | http://example.com/a/ 64 | 65 | remove_dot_segments: trailing double-dot-slash 66 | http://example.com/a/../ 67 | http://example.com/ 68 | 69 | Test of all kinds of syntax-based normalization 70 | hTTPS://a/./b/../b/%63/%7bfoo%7d 71 | https://a/b/c/%7Bfoo%7D 72 | 73 | Unsupported scheme 74 | ftp://example.com/ 75 | fail 76 | 77 | Non-absolute URI 78 | http:/foo 79 | fail 80 | 81 | Illegal character in URI 82 | http://.com/ 83 | fail 84 | 85 | Non-ascii character in URI 86 | http://foo.com/ 87 | fail -------------------------------------------------------------------------------- /Tests/Auth/Yadis/DiscoverData.php: -------------------------------------------------------------------------------- 1 | ', $example_xrds], 83 | ['YADIS_HEADER', 'X-XRDS-Location'], 84 | ['NAME', $test_name], 85 | ]; 86 | 87 | foreach ($mapping as $pair) { 88 | list($k, $v) = $pair; 89 | $template = str_replace($k, $v, $template); 90 | } 91 | 92 | return $template; 93 | } 94 | 95 | function generateSample($test_name, $base_url, 96 | $_example_xrds = null, $filename = null) 97 | { 98 | global $example_xrds, $default_test_file; 99 | 100 | if ($_example_xrds === null) { 101 | $_example_xrds = $example_xrds; 102 | } 103 | 104 | if ($filename === null) { 105 | $filename = $default_test_file; 106 | } 107 | 108 | $template = getData($filename, $test_name); 109 | 110 | if ($template === null) { 111 | return null; 112 | } 113 | 114 | return fillTemplate($test_name, $template, $base_url, $_example_xrds); 115 | } 116 | 117 | function generateResult($base_url, $input_name, $id_name, $result_name, $success) 118 | { 119 | $input_url = $base_url . $input_name; // urlparse.urljoin(base_url, input_name) 120 | 121 | // If the name is null then we expect the protocol to fail, which 122 | // we represent by null 123 | if ($id_name === null) { 124 | // assert result_name is null 125 | return [$input_url, null]; // DiscoveryFailure 126 | } 127 | 128 | $result = generateSample($result_name, $base_url); 129 | list($headers, $content) = explode("\n\n", $result, 2); 130 | $header_lines = explode("\n", $headers); 131 | $ctype = null; 132 | foreach ($header_lines as $header_line) { 133 | if (strpos($header_line, 'Content-Type:') === 0) { 134 | list($temp, $ctype) = explode(":", $header_line, 2); 135 | $ctype = trim($ctype); 136 | break; 137 | } 138 | } 139 | 140 | $id_url = $base_url . $id_name; 141 | 142 | $result = new Auth_Yadis_Yadis(); 143 | $result->uri = $id_url; 144 | if ($success) { 145 | $result->xrds_uri = $base_url . $result_name; 146 | } else { 147 | $result->xrds_uri = null; 148 | } 149 | $result->content_type = $ctype; 150 | $result->body = $content; 151 | return [$input_url, $result]; 152 | } 153 | 154 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/ParseHTML.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2005-2008 Janrain, Inc. 13 | * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 14 | */ 15 | 16 | require_once 'Tests/Auth/Yadis/TestUtil.php'; 17 | require_once 'Auth/Yadis/ParseHTML.php'; 18 | 19 | class Tests_Auth_Yadis_ParseTest extends PHPUnit_Framework_TestCase { 20 | function __construct($case) 21 | { 22 | list($result, $comment, $html) = $case; 23 | 24 | $this->result = $result; 25 | $this->comment = $comment; 26 | $this->html_string = $html; 27 | $this->parser = new Auth_Yadis_ParseHTML(); 28 | } 29 | 30 | function getName() 31 | { 32 | return $this->comment; 33 | } 34 | 35 | function runTest() 36 | { 37 | $value = $this->parser->getHTTPEquiv($this->html_string); 38 | 39 | if ($this->result == "EOF") { 40 | $this->assertTrue($value === null); 41 | } else if ($this->result == "None") { 42 | $this->assertTrue($value === null); 43 | } else { 44 | $this->assertEquals($this->result, $value); 45 | } 46 | } 47 | } 48 | 49 | class Tests_Auth_Yadis_ParseHTML extends PHPUnit_Framework_TestSuite { 50 | 51 | function getName() 52 | { 53 | return "Tests_Auth_Yadis_Parse"; 54 | } 55 | 56 | function parseTests($s) 57 | { 58 | $tests = []; 59 | 60 | $cases = preg_split("/\f\n/", $s); 61 | 62 | foreach ($cases as $case) { 63 | // Split the case text on newline, and keep the first two 64 | // lines and re-join the rest (those are the HTML). 65 | $parts = explode("\n", $case); 66 | $result = $parts[0]; 67 | $html_comment = $parts[1]; 68 | $html_string = implode("\n", array_slice($parts, 2)); 69 | $tests[] = [$result, $html_comment, $html_string]; 70 | } 71 | 72 | return $tests; 73 | } 74 | 75 | function __construct() 76 | { 77 | $test_data = Tests_Auth_Yadis_readdata('test1-parsehtml.txt'); 78 | 79 | $test_cases = $this->parseTests($test_data); 80 | 81 | foreach ($test_cases as $case) { 82 | $this->addTest(new Tests_Auth_Yadis_ParseTest($case)); 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/TestUtil.php: -------------------------------------------------------------------------------- 1 | input_url = $input_url; 15 | $this->redir_uri = $redir_uri; 16 | $this->xrds_uri = $xrds_uri; 17 | $this->num = $num; 18 | } 19 | 20 | function getName() 21 | { 22 | return "Yadis discovery test ".$this->num; 23 | } 24 | 25 | function runTest() 26 | { 27 | $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); 28 | $y = Auth_Yadis_Yadis::discover( 29 | $this->input_url, $fetcher); 30 | $this->assertTrue($y !== null); 31 | 32 | // Compare parts of returned Yadis object to expected URLs. 33 | $this->assertEquals($this->redir_uri, $y->normalized_uri, "tried $this->input_url"); 34 | 35 | if ($this->xrds_uri) { 36 | $this->assertEquals($this->xrds_uri, $y->xrds_uri); 37 | // Compare contents of actual HTTP GET with that of Yadis 38 | // response. 39 | $f = Auth_Yadis_Yadis::getHTTPFetcher(); 40 | $http_response = $f->get($this->xrds_uri); 41 | 42 | $this->assertEquals($http_response->body, $y->response_text); 43 | } else { 44 | $this->assertTrue($y->xrds_uri === null); 45 | } 46 | } 47 | } 48 | 49 | class Tests_Auth_Yadis_Yadis extends PHPUnit_Framework_TestSuite { 50 | 51 | function getName() 52 | { 53 | return "Tests_Auth_Yadis_Yadis"; 54 | } 55 | 56 | function parseTests($data) 57 | { 58 | $cases = explode("\n", $data); 59 | $tests = []; 60 | 61 | foreach ($cases as $line) { 62 | if ($line && ($line[0] != "#")) { 63 | $tests[] = explode("\t", $line, 3); 64 | } 65 | } 66 | 67 | return $tests; 68 | } 69 | 70 | function __construct() 71 | { 72 | $test_data = file_get_contents('http://www.openidenabled.com/resources/yadis-test/discover/manifest.txt'); 73 | 74 | $test_cases = $this->parseTests($test_data); 75 | 76 | $i = 0; 77 | foreach ($test_cases as $case) { 78 | $i++; 79 | list($input, $redir, $xrds) = $case; 80 | $this->addTest(new Tests_Auth_Yadis_DiscoveryTest($input, 81 | $redir, 82 | $xrds, $i)); 83 | } 84 | } 85 | 86 | } 87 | 88 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/README: -------------------------------------------------------------------------------- 1 | delegated-20060809.xrds - results from proxy.xri.net, determined by 2 | Drummond and Kevin to be incorrect. 3 | delegated-20060809-r1.xrds - Drummond's 1st correction 4 | delegated-20060809-r2.xrds - Drummond's 2nd correction 5 | 6 | spoofs: keturn's (=!E4)'s attempts to log in with Drummond's i-number (=!D2) 7 | spoof1.xrds 8 | spoof2.xrds 9 | spoof3.xrds - attempt to steal @!C0!D2 by having "at least one" CanonicalID 10 | match the $res service ProviderID. 11 | 12 | ref.xrds - resolving @ootao*test.ref, which refers to a neustar XRI. 13 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/accept.txt: -------------------------------------------------------------------------------- 1 | # Accept: [Accept: header value from RFC2616, 2 | # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html] 3 | # Available: [whitespace-separated content types] 4 | # Expected: [Accept-header like list, containing the available content 5 | # types with their q-values] 6 | 7 | Accept: */* 8 | Available: text/plain 9 | Expected: text/plain; q=1.0 10 | 11 | Accept: */* 12 | Available: text/plain, text/html 13 | Expected: text/plain; q=1.0, text/html; q=1.0 14 | 15 | # The order matters 16 | Accept: */* 17 | Available: text/html, text/plain 18 | Expected: text/html; q=1.0, text/plain; q=1.0 19 | 20 | Accept: text/*, */*; q=0.9 21 | Available: text/plain, image/jpeg 22 | Expected: text/plain; q=1.0, image/jpeg; q=0.9 23 | 24 | Accept: text/*, */*; q=0.9 25 | Available: image/jpeg, text/plain 26 | Expected: text/plain; q=1.0, image/jpeg; q=0.9 27 | 28 | # wildcard subtypes still reject differing main types 29 | Accept: text/* 30 | Available: image/jpeg, text/plain 31 | Expected: text/plain; q=1.0 32 | 33 | Accept: text/html 34 | Available: text/html 35 | Expected: text/html; q=1.0 36 | 37 | Accept: text/html, text/* 38 | Available: text/html 39 | Expected: text/html; q=1.0 40 | 41 | Accept: text/html, text/* 42 | Available: text/plain, text/html 43 | Expected: text/plain; q=1.0, text/html; q=1.0 44 | 45 | Accept: text/html, text/*; q=0.9 46 | Available: text/plain, text/html 47 | Expected: text/html; q=1.0, text/plain; q=0.9 48 | 49 | # If a more specific type has a higher q-value, then the higher value wins 50 | Accept: text/*; q=0.9, text/html 51 | Available: text/plain, text/html 52 | Expected: text/html; q=1.0, text/plain; q=0.9 53 | 54 | Accept: */*, text/*; q=0.9, text/html; q=0.1 55 | Available: text/plain, text/html, image/monkeys 56 | Expected: image/monkeys; q=1.0, text/plain; q=0.9, text/html; q=0.1 57 | 58 | Accept: text/*, text/html; q=0 59 | Available: text/html 60 | Expected: 61 | 62 | Accept: text/*, text/html; q=0 63 | Available: text/html, text/plain 64 | Expected: text/plain; q=1.0 65 | 66 | Accept: text/html 67 | Available: text/plain 68 | Expected: 69 | 70 | Accept: application/xrds+xml, text/html; q=0.9 71 | Available: application/xrds+xml, text/html 72 | Expected: application/xrds+xml; q=1.0, text/html; q=0.9 73 | 74 | Accept: application/xrds+xml, */*; q=0.9 75 | Available: application/xrds+xml, text/html 76 | Expected: application/xrds+xml; q=1.0, text/html; q=0.9 77 | 78 | Accept: application/xrds+xml, application/xhtml+xml; q=0.9, text/html; q=0.8, text/xml; q=0.7 79 | Available: application/xrds+xml, text/html 80 | Expected: application/xrds+xml; q=1.0, text/html; q=0.8 81 | 82 | # See http://www.rfc-editor.org/rfc/rfc3023.txt, section A.13 83 | Accept: application/xrds 84 | Available: application/xrds+xml 85 | Expected: 86 | 87 | Accept: application/xrds+xml 88 | Available: application/xrds 89 | Expected: 90 | 91 | Accept: application/xml 92 | Available: application/xrds+xml 93 | Expected: 94 | 95 | Available: application/xrds+xml 96 | Accept: application/xml 97 | Expected: 98 | 99 | 100 | 101 | ################################################# 102 | # The tests below this line are documentation of how this library 103 | # works. If the implementation changes, it's acceptable to change the 104 | # test to reflect that. These are specified so that we can make sure 105 | # that the current implementation actually works the way that we 106 | # expect it to given these inputs. 107 | 108 | Accept: text/html;level=1 109 | Available: text/html 110 | Expected: text/html; q=1.0 111 | 112 | Accept: text/html; level=1, text/html; level=9; q=0.1 113 | Available: text/html 114 | Expected: text/html; q=1.0 115 | 116 | Accept: text/html; level=9; q=0.1, text/html; level=1 117 | Available: text/html 118 | Expected: text/html; q=1.0 119 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/brian.multi.xrds: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.1 10 | http://www.myopenid.com/server 11 | http://frank.myopenid.com/ 12 | 13 | 14 | 15 | 16 | 17 | 18 | http://bar.com/ 19 | http://bar.com/server 20 | 21 | 22 | 23 | http://foo.com 24 | http://foo.com/server 25 | 26 | 27 | 28 | 29 | 30 | 31 | http://openid.net/signon/1.0 32 | http://www.myopenid.com/server 33 | http://brian.myopenid.com/ 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/brian.multi_uri.xrds: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://www.myopenid.com/server 11 | http://example.com/server 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/brian.xrds: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://www.myopenid.com/server 11 | http://brian.myopenid.com/ 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/brian_priority.xrds: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.0 10 | http://www.schtuff.com/?action=openid_server 11 | http://users.schtuff.com/brian 12 | 13 | 14 | 15 | http://openid.net/signon/1.0 16 | http://www.myopenid.com/server 17 | http://brian.myopenid.com/ 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/delegated-20060809-r1.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://!!1003 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://!!1003 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/delegated-20060809-r2.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/delegated-20060809.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://!!1003 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/example-xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | http://example.com/ 10 | http://www.openidenabled.com/ 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/no-xrd.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/not-xrds.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/pip.xrds: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | http://openid.net/signon/1.1 10 | http://openid.net/sreg/1.0 11 | https://pip.verisignlabs.com/server 12 | 13 | 14 | 15 | http://openid.net/signon/1.0 16 | http://openid.net/sreg/1.0 17 | https://pip.verisignlabs.com/server 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/prefixsometimes.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | xri://@!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/ref.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-15T18:56:09.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | @!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test.ref 24 | SUCCESS 25 | xri://!!1003 26 | !0000.0000.3B9A.CA03 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA03 28 | @!BAE.A650.823B.2475 29 | 30 | http://openid.net/signon/1.0 31 | 32 | https://linksafe.ezibroker.net/server/ 33 | 34 | 35 | 36 | 37 | !BAE.A650.823B.2475 38 | 39 | 2006-08-15T18:56:10.000Z 40 | xri://@ 41 | !BAE.A650.823B.2475 42 | @!BAE.A650.823B.2475 43 | 44 | (+wdnc) 45 | 46 | (+wdnc) 47 | http://www.tcpacompliance.us 48 | 49 | 50 | xri://$res*auth*($v*2.0) 51 | 52 | application/xrds+xml;trust=none 53 | http://dev.dready.org/cgi-bin/xri 54 | 55 | 56 | (+i-name) 57 | 58 | (+i-name) 59 | http://www.inames.net 60 | 61 | 62 | xri://+i-service*(+contact)*($v*1.0) 63 | 64 | xri://!!1001 65 | (+contact) 66 | 67 | text/html 68 | 69 | http://www.neustar.biz 70 | 71 | 72 | 73 | 74 | !BAE.A650.823B.2475 75 | 76 | 2006-08-15T18:56:10.000Z 77 | xri://@ 78 | !BAE.A650.823B.2475 79 | @!BAE.A650.823B.2475 80 | 81 | (+wdnc) 82 | 83 | (+wdnc) 84 | http://www.tcpacompliance.us 85 | 86 | 87 | xri://$res*auth*($v*2.0) 88 | 89 | application/xrds+xml;trust=none 90 | http://dev.dready.org/cgi-bin/xri 91 | 92 | 93 | (+i-name) 94 | 95 | (+i-name) 96 | http://www.inames.net 97 | 98 | 99 | xri://+i-service*(+contact)*($v*1.0) 100 | 101 | xri://!!1001 102 | (+contact) 103 | 104 | text/html 105 | 106 | http://www.neustar.biz 107 | 108 | 109 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/sometimesprefix.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *ootao 5 | 6 | 2006-08-09T22:07:13.000Z 7 | xri://@ 8 | !5BAD.2AA.3C72.AF46 9 | xri://@!5BAD.2AA.3C72.AF46 10 | 11 | xri://$res*auth*($v*2.0) 12 | xri://@!5BAD.2AA.3C72.AF46 13 | application/xrds+xml;trust=none 14 | http://resolve.ezibroker.net/resolve/@ootao/ 15 | 16 | 17 | http://openid.net/signon/1.0 18 | 19 | https://linksafe.ezibroker.net/server/ 20 | 21 | 22 | 23 | *test1 24 | SUCCESS 25 | xri://@!5BAD.2AA.3C72.AF46 26 | !0000.0000.3B9A.CA01 27 | @!5BAD.2AA.3C72.AF46!0000.0000.3B9A.CA01 28 | 29 | http://openid.net/signon/1.0 30 | 31 | https://linksafe.ezibroker.net/server/ 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/spoof1.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://= 6 | !E4 7 | =!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | =!E4 13 | 14 | 15 | 16 | *isDrummond 17 | =!E4 18 | !D2 19 | =!D2 20 | 21 | http://openid.net/signon/1.0 22 | http://keturn.example.com/openid 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/spoof2.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://= 6 | !E4 7 | =!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | xri://= 13 | 14 | 15 | 16 | *isDrummond 17 | xri://= 18 | !D2 19 | =!D2 20 | 21 | http://openid.net/signon/1.0 22 | http://keturn.example.com/openid 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/spoof3.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *keturn 5 | xri://@ 6 | @E4 7 | @!E4 8 | 9 | 10 | xri://$res*auth*($v*2.0) 11 | http://keturn.example.com/resolve/ 12 | @!E4 13 | 14 | 15 | 16 | *is 17 | @!E4 18 | !D2 19 | =!C0 20 | =!E4!01 21 | 22 | xri://$res*auth*($v*2.0) 23 | http://keturn.example.com/resolve/ 24 | @!C0 25 | 26 | 27 | 28 | *drummond 29 | @!C0 30 | !D2 31 | @!C0!D2 32 | 33 | http://openid.net/signon/1.0 34 | http://keturn.example.com/openid 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/subsegments.xrds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *nishitani 5 | 6 | 2007-12-25T11:33:39.000Z 7 | xri://= 8 | !E117.EF2F.454B.C707 9 | =!E117.EF2F.454B.C707 10 | 11 | http://openid.net/signon/1.0 12 | xri://!!1003!103 13 | https://linksafe.ezibroker.net/server/ 14 | 15 | 16 | xri://$res*auth*($v*2.0) 17 | xri://!!1003!103 18 | application/xrds+xml;trust=none 19 | http://resolve.ezibroker.net/resolve/=nishitani/ 20 | 21 | 22 | xri://+i-service*(+forwarding)*($v*1.0) 23 | 24 | xri://!!1003!103 25 | (+index) 26 | 27 | http://linksafe-forward.ezibroker.net/forwarding/ 28 | 29 | 30 | 31 | *masaki 32 | SUCCESS 33 | xri://!!1003 34 | !0000.0000.3B9A.CA01 35 | =!E117.EF2F.454B.C707!0000.0000.3B9A.CA01 36 | 37 | http://openid.net/signon/1.0 38 | xri://!!1003!103 39 | https://linksafe.ezibroker.net/server/ 40 | 41 | 42 | xri://+i-service*(+contact)*($v*1.0) 43 | 44 | xri://!!1003!103 45 | (+contact) 46 | 47 | http://linksafe-contact.ezibroker.net/contact/ 48 | 49 | 50 | xri://+i-service*(+forwarding)*($v*1.0) 51 | 52 | xri://!!1003!103 53 | (+index) 54 | 55 | http://linksafe-forward.ezibroker.net/forwarding/ 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/test1-discover.txt: -------------------------------------------------------------------------------- 1 | equiv 2 | Status: 200 OK 3 | Content-Type: text/html 4 | 5 | 6 | 7 | 8 | Joe Schmoe's Homepage 9 | 10 | 11 |

Joe Schmoe's Homepage

12 |

Blah blah blah blah blah blah blah

13 | 14 | 15 | 16 | header 17 | Status: 200 OK 18 | Content-Type: text/html 19 | YADIS_HEADER: URL_BASE/xrds 20 | 21 | 22 | 23 | Joe Schmoe's Homepage 24 | 25 | 26 |

Joe Schmoe's Homepage

27 |

Blah blah blah blah blah blah blah

28 | 29 | 30 | xrds 31 | Status: 200 OK 32 | Content-Type: application/xrds+xml 33 | 34 | 35 | 36 | xrds_ctparam 37 | Status: 200 OK 38 | Content-Type: application/xrds+xml; charset=UTF8 39 | 40 | 41 | 42 | xrds_ctcase 43 | Status: 200 OK 44 | Content-Type: appliCATION/XRDS+xml 45 | 46 | 47 | 48 | xrds_html 49 | Status: 200 OK 50 | Content-Type: text/html 51 | 52 | 53 | 54 | redir_equiv 55 | Status: 302 Found 56 | Content-Type: text/plain 57 | Location: URL_BASE/equiv 58 | 59 | You are presently being redirected. 60 | 61 | redir_header 62 | Status: 302 Found 63 | Content-Type: text/plain 64 | Location: URL_BASE/header 65 | 66 | You are presently being redirected. 67 | 68 | redir_xrds 69 | Status: 302 Found 70 | Content-Type: application/xrds+xml 71 | Location: URL_BASE/xrds 72 | 73 | 74 | 75 | redir_xrds_html 76 | Status: 302 Found 77 | Content-Type: text/plain 78 | Location: URL_BASE/xrds_html 79 | 80 | You are presently being redirected. 81 | 82 | redir_redir_equiv 83 | Status: 302 Found 84 | Content-Type: text/plain 85 | Location: URL_BASE/redir_equiv 86 | 87 | You are presently being redirected. 88 | 89 | lowercase_header 90 | Status: 200 OK 91 | Content-Type: text/html 92 | x-xrds-location: URL_BASE/xrds 93 | 94 | 95 | 96 | Joe Schmoe's Homepage 97 | 98 | 99 |

Joe Schmoe's Homepage

100 |

Blah blah blah blah blah blah blah

101 | 102 | 103 | 404_server_response 104 | Status: 404 Not Found 105 | 106 | EEk! 107 | 108 | 500_server_response 109 | Status: 500 Server error 110 | 111 | EEk! 112 | 113 | 201_server_response 114 | Status: 201 Created 115 | 116 | EEk! 117 | 118 | 404_with_header 119 | Status: 404 Not Found 120 | YADIS_HEADER: URL_BASE/xrds 121 | 122 | EEk! 123 | 124 | 404_with_meta 125 | Status: 404 Not Found 126 | Content-Type: text/html 127 | 128 | 129 | 130 | 131 | Joe Schmoe's Homepage 132 | 133 | 134 |

Joe Schmoe's Homepage

135 |

Blah blah blah blah blah blah blah

136 | 137 | 138 | -------------------------------------------------------------------------------- /Tests/Auth/Yadis/data/test1-parsehtml.txt: -------------------------------------------------------------------------------- 1 | found 2 | 3 | 4 | 5 | found 6 | 7 | 8 | 9 | found 10 | 11 | 12 | 13 | found 14 | 15 | 16 | 17 | found 18 | 19 | 20 | 21 | found 22 | 23 | 24 | 25 | found 26 | 27 | 28 | 29 | found 30 | 31 | 32 | 33 | EOF 34 | 35 |