diff options
Diffstat (limited to 'mod/oauth_api')
43 files changed, 7446 insertions, 0 deletions
| diff --git a/mod/oauth_api/manifest.xml b/mod/oauth_api/manifest.xml new file mode 100644 index 000000000..991be6a22 --- /dev/null +++ b/mod/oauth_api/manifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8"> +	<name>OAuth API</name> +	<author>Core developers</author> +	<version>1.8</version> +	<description>Provides OAuth libraries and API support.</description> +	<category>bundled</category> +	<category>api</category> +	<website>http://www.elgg.org/</website> +	<copyright>See COPYRIGHT.txt</copyright> +	<license>GNU General Public License version 2</license> +	<requires> +		<type>elgg_release</type> +		<version>1.8</version> +	</requires> + +	<conflicts> +		<type>plugin</type> +		<name>oauth_lib</name> +	</conflicts> +	<conflicts> +		<type>php_extension</type> +		<name>oauth</name> +	</conflicts> +</plugin_manifest> diff --git a/mod/oauth_api/start.php b/mod/oauth_api/start.php new file mode 100644 index 000000000..d087a13d1 --- /dev/null +++ b/mod/oauth_api/start.php @@ -0,0 +1,24 @@ +<?php +/** + * OAuth libs + * + * @todo Pull these out into an elgg_oauth lib and use elgg_register_library(). + * @package oauth_api + */ + +// require all vendor libraries +$plugin_path = dirname(__FILE__) . '/vendors/oauth/library'; +require_once "$plugin_path/OAuthDiscovery.php"; +require_once "$plugin_path/OAuthRequest.php"; +require_once "$plugin_path/OAuthRequester.php"; +require_once "$plugin_path/OAuthRequestVerifier.php"; +require_once "$plugin_path/OAuthServer.php"; + +require_once "$plugin_path/body/OAuthBodyMultipartFormdata.php"; + +require_once "$plugin_path/store/OAuthStoreAbstract.class.php"; + +require_once "$plugin_path/signature_method/OAuthSignatureMethod_HMAC_SHA1.php"; +require_once "$plugin_path/signature_method/OAuthSignatureMethod_MD5.php"; +require_once "$plugin_path/signature_method/OAuthSignatureMethod_PLAINTEXT.php"; +require_once "$plugin_path/signature_method/OAuthSignatureMethod_RSA_SHA1.php"; diff --git a/mod/oauth_api/vendors/oauth/LICENSE b/mod/oauth_api/vendors/oauth/LICENSE new file mode 100644 index 000000000..f64bcd50f --- /dev/null +++ b/mod/oauth_api/vendors/oauth/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2007-2008 Mediamatic Lab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/INSTALL b/mod/oauth_api/vendors/oauth/example/server/INSTALL new file mode 100644 index 000000000..249c85e9d --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/INSTALL @@ -0,0 +1,53 @@ +In this example I assume that oauth-php lives in /home/john/src/oauth-php + + +1) Create a virtual host and set the DB_DSN VARIABLE to the DSN of your (mysql) database. + +Example +<VirtualHost *> +        ServerAdmin admin@localhost +        ServerName hello.local +        DocumentRoot /home/john/src/oauth-php/example/server/www + +        UseCanonicalName Off +        ServerSignature On + +        SetEnv DB_DSN mysql://foo:bar@localhost/oauth_example_server_db + +        <Directory "home/john/src/oauth-php/example/server/www"> +                Options Indexes FollowSymLinks MultiViews +                AllowOverride None +                Order allow,deny +                Allow from all + +                <IfModule mod_php5.c> +                  php_value magic_quotes_gpc                0 +                  php_value register_globals                0 +                  php_value session.auto_start              0 +                </IfModule> + +        </Directory> +</VirtualHost> + + +2) Create the database structure for the server: + +# mysql -u foo -p bar -h localhost < /home/john/src/oauth-php/library/store/mysql/mysql.sql + + + +3) Download and install smarty into the smarty/core/smarty directory: + +# cd /home/john/src/oauth-php/example/server/core +# wget 'http://www.smarty.net/do_download.php?download_file=Smarty-2.6.19.tar.gz' +# tar zxf Smarty-2.6.19.tar.gz +# mv Smarty-2.6.19 smarty + + +4) That's it! Point your browser to  + +  http://hello.local/ + +To get started. + +Arjan Scherpenisse <arjan@mediamatic.nl>, July 2008 diff --git a/mod/oauth_api/vendors/oauth/example/server/core/init.php b/mod/oauth_api/vendors/oauth/example/server/core/init.php new file mode 100644 index 000000000..e5bb9de35 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/init.php @@ -0,0 +1,127 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * Global initialization file for the server, defines some helper + * functions, required includes, and starts the session. + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +/* + * Simple 'user management' + */ +define ('USERNAME', 'sysadmin'); +define ('PASSWORD', 'sysadmin'); + + +/* + * Always announce XRDS OAuth discovery + */ +header('X-XRDS-Location: http://' . $_SERVER['SERVER_NAME'] . '/services.xrds'); + + +/* + * Initialize the database connection + */ +$info = parse_url(getenv('DB_DSN')); +($GLOBALS['db_conn'] = mysql_connect($info['host'], $info['user'], $info['pass'])) || die(mysql_error()); +mysql_select_db(basename($info['path']), $GLOBALS['db_conn']) || die(mysql_error()); +unset($info); + + +require_once '../../../library/OAuthServer.php'; + +/* + * Initialize OAuth store + */ +require_once '../../../library/OAuthStore.php'; +OAuthStore::instance('MySQL', array('conn' => $GLOBALS['db_conn'])); + + +/* + * Session + */ +session_start(); + + +/* + * Template handling + */ +require_once 'smarty/libs/Smarty.class.php'; +function session_smarty() +{ +	if (!isset($GLOBALS['smarty'])) +	{ +		$GLOBALS['smarty'] = new Smarty; +		$GLOBALS['smarty']->template_dir = dirname(__FILE__) . '/templates/'; +		$GLOBALS['smarty']->compile_dir = dirname(__FILE__) . '/../cache/templates_c'; +	} +	 +	return $GLOBALS['smarty']; +} + +function assert_logged_in() +{ +	if (empty($_SESSION['authorized'])) +	{ +		$uri = $_SERVER['REQUEST_URI']; +		header('Location: /logon?goto=' . urlencode($uri)); +	} +} + +function assert_request_vars() +{ +	foreach(func_get_args() as $a) +	{ +		if (!isset($_REQUEST[$a])) +		{ +			header('HTTP/1.1 400 Bad Request'); +			echo 'Bad request.'; +			exit; +		} +	} +} + +function assert_request_vars_all() +{ +	foreach($_REQUEST as $row) +	{ +		foreach(func_get_args() as $a) +		{ +			if (!isset($row[$a])) +			{ +				header('HTTP/1.1 400 Bad Request'); +				echo 'Bad request.'; +				exit; +			} +		} +	} +} + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/footer.tpl b/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/footer.tpl new file mode 100644 index 000000000..308b1d01b --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/footer.tpl @@ -0,0 +1,2 @@ +</body> +</html> diff --git a/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/header.tpl b/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/header.tpl new file mode 100644 index 000000000..5046f54b0 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/templates/inc/header.tpl @@ -0,0 +1,2 @@ +<html> +    <body> diff --git a/mod/oauth_api/vendors/oauth/example/server/core/templates/index.tpl b/mod/oauth_api/vendors/oauth/example/server/core/templates/index.tpl new file mode 100644 index 000000000..7b065537d --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/templates/index.tpl @@ -0,0 +1,13 @@ +{include file='inc/header.tpl'} + +<h1>OAuth server</h1> +Go to: + +<ul> +  <li><a href="/logon">Logon</a></li> +  <li><a href="/register">Register your consumer</a></li> +</ul> + +Afterwards, make an OAuth test request to <strong>http://{$smarty.server.name}/hello</strong> to test your connection.</p> + +{include file='inc/footer.tpl'} diff --git a/mod/oauth_api/vendors/oauth/example/server/core/templates/logon.tpl b/mod/oauth_api/vendors/oauth/example/server/core/templates/logon.tpl new file mode 100644 index 000000000..5ccd432b5 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/templates/logon.tpl @@ -0,0 +1,21 @@ +{include file='inc/header.tpl'} + +<h1>Login</h1> + +<form method="post"> +    <input type="hidden" name="goto" value="{$smarty.request.goto}" /> + +    <label for="username">User name</label><br /> +    <input type="text" name="username" id="username" /> +     +    <br /><br /> + +    <label for="password">Password</label><br /> +    <input type="text" name="password" id="password" /> + +    <br /><br /> +     +    <input type="submit" value="Login" /> +</form> + +{include file='inc/footer.tpl'} diff --git a/mod/oauth_api/vendors/oauth/example/server/core/templates/register.tpl b/mod/oauth_api/vendors/oauth/example/server/core/templates/register.tpl new file mode 100644 index 000000000..0e28c1584 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/core/templates/register.tpl @@ -0,0 +1,41 @@ +{include file='inc/header.tpl'} + +<h1>Register server</h1> + +<p>Register a server which is gonna act as an identity client.</p> + +<form method="post"> + +    <fieldset> +	<legend>About You</legend> +	 +	<p> +	    <label for="requester_name">Your name</label><br/> +	    <input class="text" id="requester_name"  name="requester_name" type="text" value="{$consumer.requester_name|default:$smarty.request.requester_name|escape}" /> +	</p> +	 +	<p> +	    <label for="requester_email">Your email address</label><br/> +	    <input class="text" id="requester_email"  name="requester_email" type="text" value="{$consumer.requester_email|default:$smarty.request.requester_email|escape}" /> +	</p> +    </fieldset> +     +    <fieldset> +	<legend>Location Of Your Application Or Site</legend> +	 +	<p> +	    <label for="application_uri">URL of your application or site</label><br/> +	    <input id="application_uri" class="text" name="application_uri" type="text" value="{$consumer.application_uri|default:$smarty.request.application_uri|escape}" /> +	</p> +	 +	<p> +	    <label for="callback_uri">Callback URL</label><br/> +	    <input id="callback_uri" class="text" name="callback_uri" type="text" value="{$consumer.callback_uri|default:$smarty.request.callback_uri|escape}" /> +	</p> +    </fieldset> + +    <br /> +    <input type="submit" value="Register server" /> +</form> + +{include file='inc/footer.tpl'} diff --git a/mod/oauth_api/vendors/oauth/example/server/www/hello.php b/mod/oauth_api/vendors/oauth/example/server/www/hello.php new file mode 100644 index 000000000..8cb94bb1e --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/hello.php @@ -0,0 +1,65 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * An example service, http://hostname/hello. You will only get the + * 'Hello, world!' string back if you have signed your request with + * oauth. + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once '../core/init.php'; + +$authorized = false; +$server = new OAuthServer(); +try +{ +	if ($server->verifyIfSigned()) +	{ +		$authorized = true; +	} +} +catch (OAuthException $e) +{ +} + +if (!$authorized) +{ +	header('HTTP/1.1 401 Unauthorized'); +	header('Content-Type: text/plain'); +	 +	echo "OAuth Verification Failed: " . $e->getMessage(); +	die; +} + +// From here on we are authenticated with OAuth. + +header('Content-type: text/plain'); +echo 'Hello, world!'; + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/www/index.php b/mod/oauth_api/vendors/oauth/example/server/www/index.php new file mode 100644 index 000000000..f5cadbe61 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/index.php @@ -0,0 +1,37 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require '../core/init.php'; + +$smarty = session_smarty(); +$smarty->display('index.tpl'); + +?> diff --git a/mod/oauth_api/vendors/oauth/example/server/www/logon.php b/mod/oauth_api/vendors/oauth/example/server/www/logon.php new file mode 100644 index 000000000..5c937b719 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/logon.php @@ -0,0 +1,55 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * Simple logon for consumer registration at this server. + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once '../core/init.php'; + +if (isset($_POST['username']) && isset($_POST['password'])) +{ +	if ($_POST['username'] == USERNAME && $_POST['password'] == PASSWORD) +	{ +		$_SESSION['authorized'] = true; +		if (!empty($_REQUEST['goto'])) +		{ +			header('Location: ' . $_REQUEST['goto']); +			die; +		} + +		echo "Logon succesfull."; +		die; +	} +} + +$smarty = session_smarty(); +$smarty->display('logon.tpl'); + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/www/oauth.php b/mod/oauth_api/vendors/oauth/example/server/www/oauth.php new file mode 100644 index 000000000..e0badcc39 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/oauth.php @@ -0,0 +1,77 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * This file implements the OAuth server endpoints. The most basic + * implementation of an OAuth server. + * + * Call with: /oauth/request_token, /oauth/authorize, /oauth/access_token + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once '../core/init.php'; + +$server = new OAuthServer(); + +switch($_SERVER['PATH_INFO']) +{ +case '/request_token': +	$server->requestToken(); +	exit; + +case '/access_token': +	$server->accessToken(); +	exit; + +case '/authorize': +	# logon + +	assert_logged_in(); + +	try +	{ +		$server->authorizeVerify(); +		$server->authorizeFinish(true, 1); +	} +	catch (OAuthException $e) +	{ +		header('HTTP/1.1 400 Bad Request'); +		header('Content-Type: text/plain'); +		 +		echo "Failed OAuth Request: " . $e->getMessage(); +	} +	exit; + +	 +default: +	header('HTTP/1.1 500 Internal Server Error'); +	header('Content-Type: text/plain'); +	echo "Unknown request"; +} + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/www/register.php b/mod/oauth_api/vendors/oauth/example/server/www/register.php new file mode 100644 index 000000000..c5785c2c8 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/register.php @@ -0,0 +1,28 @@ +<?php + +require_once '../core/init.php'; + +assert_logged_in(); + +if ($_SERVER['REQUEST_METHOD'] == 'POST') +{ +	try +	{ +		$store = OAuthStore::instance(); +		$key   = $store->updateConsumer($_POST, 1, true); + +		$c = $store->getConsumer($key); +		echo 'Your consumer key is: <strong>' . $c['consumer_key'] . '</strong><br />'; +		echo 'Your consumer secret is: <strong>' . $c['consumer_secret'] . '</strong><br />'; +	} +	catch (OAuthException $e) +	{ +		echo '<strong>Error: ' . $e->getMessage() . '</strong><br />'; +	} +} +		 + +$smarty = session_smarty(); +$smarty->display('register.tpl'); + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/example/server/www/services.xrds.php b/mod/oauth_api/vendors/oauth/example/server/www/services.xrds.php new file mode 100644 index 000000000..4c50aa12b --- /dev/null +++ b/mod/oauth_api/vendors/oauth/example/server/www/services.xrds.php @@ -0,0 +1,71 @@ +<?php + +/** + * oauth-php: Example OAuth server + * + * XRDS discovery for OAuth. This file helps the consumer program to + * discover where the OAuth endpoints for this server are. + * + * @author Arjan Scherpenisse <arjan@scherpenisse.net> + * + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +header('Content-Type: application/xrds+xml'); + +$server = $_SERVER['SERVER_NAME']; + +echo '<?xml version="1.0" encoding="utf-8"?>' . "\n"; + +?> +<XRDS xmlns="xri://$xrds"> +    <XRD xmlns:simple="http://xrds-simple.net/core/1.0" xmlns="xri://$XRD*($v*2.0)" xmlns:openid="http://openid.net/xmlns/1.0" version="2.0" xml:id="main"> +	<Type>xri://$xrds*simple</Type> +	<Service> +	    <Type>http://oauth.net/discovery/1.0</Type> +	    <URI>#main</URI> +	</Service> +	<Service> +	    <Type>http://oauth.net/core/1.0/endpoint/request</Type> +	    <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +	    <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +	    <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +	    <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> +	    <URI>http://<?=$server?>/oauth/request_token</URI> +	</Service> +	<Service> +	    <Type>http://oauth.net/core/1.0/endpoint/authorize</Type> +	    <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +	    <URI>http://<?=$server?>/oauth/authorize</URI> +	</Service> +	<Service> +	    <Type>http://oauth.net/core/1.0/endpoint/access</Type> +	    <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +	    <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +	    <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +	    <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> +	    <URI>http://<?=$server?>/oauth/access_token</URI> +	</Service> +    </XRD> +</XRDS> diff --git a/mod/oauth_api/vendors/oauth/library/OAuthDiscovery.php b/mod/oauth_api/vendors/oauth/library/OAuthDiscovery.php new file mode 100644 index 000000000..d097756dd --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthDiscovery.php @@ -0,0 +1,226 @@ +<?php + +/** + * Handle the discovery of OAuth service provider endpoints and static consumer identity. + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 4, 2008 5:05:19 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__).'/discovery/xrds_parse.php'; + +require_once dirname(__FILE__).'/OAuthException.php'; +require_once dirname(__FILE__).'/OAuthRequestLogger.php'; + + +class OAuthDiscovery +{ +	/** +	 * Return a description how we can do a consumer allocation.  Prefers static allocation if +	 * possible.  If static allocation is possible +	 *  +	 * See also: http://oauth.net/discovery/#consumer_identity_types +	 *  +	 * @param string uri +	 * @return array		provider description +	 */ +	static function discover ( $uri ) +	{ +		// See what kind of consumer allocations are available +		$xrds_file = self::discoverXRDS($uri); +		if (!empty($xrds_file)) +		{ +			$xrds = xrds_parse($xrds_file); +			if (empty($xrds)) +			{ +				throw new OAuthException('Could not discover OAuth information for '.$uri); +			} +		} +		else +		{ +			throw new OAuthException('Could not discover XRDS file at '.$uri); +		} + +		// Fill an OAuthServer record for the uri found +		$ps			= parse_url($uri); +		$host		= isset($ps['host']) ? $ps['host'] : 'localhost'; +		$server_uri = $ps['scheme'].'://'.$host.'/'; + +		$p = array( +				'user_id'			=> null, +				'consumer_key'		=> '', +				'consumer_secret'	=> '', +				'signature_methods'	=> '', +				'server_uri'		=> $server_uri, +				'request_token_uri'	=> '', +				'authorize_uri'		=> '', +				'access_token_uri'	=> '' +			); + + +		// Consumer identity (out of bounds or static) +		if (isset($xrds['consumer_identity'])) +		{ +			// Try to find a static consumer allocation, we like those :) +			foreach ($xrds['consumer_identity'] as $ci) +			{ +				if ($ci['method'] == 'static' && !empty($ci['consumer_key'])) +				{ +					$p['consumer_key']    = $ci['consumer_key']; +					$p['consumer_secret'] = ''; +				} +				else if ($ci['method'] == 'oob' && !empty($ci['uri'])) +				{ +					// TODO: Keep this uri somewhere for the user? +					$p['consumer_oob_uri'] = $ci['uri']; +				} +			} +		} + +		// The token uris +		if (isset($xrds['request'][0]['uri'])) +		{ +			$p['request_token_uri'] = $xrds['request'][0]['uri']; +			if (!empty($xrds['request'][0]['signature_method'])) +			{ +				$p['signature_methods'] = $xrds['request'][0]['signature_method']; +			} +		} +		if (isset($xrds['authorize'][0]['uri'])) +		{ +			$p['authorize_uri'] = $xrds['authorize'][0]['uri']; +			if (!empty($xrds['authorize'][0]['signature_method'])) +			{ +				$p['signature_methods'] = $xrds['authorize'][0]['signature_method']; +			} +		} +		if (isset($xrds['access'][0]['uri'])) +		{ +			$p['access_token_uri'] = $xrds['access'][0]['uri']; +			if (!empty($xrds['access'][0]['signature_method'])) +			{ +				$p['signature_methods'] = $xrds['access'][0]['signature_method']; +			} +		} +		return $p; +	} +	 +	 +	/** +	 * Discover the XRDS file at the uri.  This is a bit primitive, you should overrule +	 * this function so that the XRDS file can be cached for later referral. +	 *  +	 * @param string uri +	 * @return string		false when no XRDS file found +	 */ +	static protected function discoverXRDS ( $uri, $recur = 0 ) +	{ +		// Bail out when we are following redirects +		if ($recur > 10) +		{ +			return false; +		} +		 +		$data = self::curl($uri); + +		// Check what we got back, could be: +		// 1. The XRDS discovery file itself (check content-type) +		// 2. The X-XRDS-Location header +		 +		if (is_string($data) && !empty($data)) +		{ +			list($head,$body) = explode("\r\n\r\n", $data); +			$body = trim($body); +			$m	  = false; + +			// See if we got the XRDS file itself or we have to follow a location header +			if (	preg_match('/^Content-Type:\s*application\/xrds+xml/im', $head) +				||	preg_match('/^<\?xml[^>]*\?>\s*<xrds\s/i', $body) +				||	preg_match('/^<xrds\s/i', $body) +				) +			{ +				$xrds = $body; +			} +			else if (	preg_match('/^X-XRDS-Location:\s*(.*)$/im', $head, $m) +					||	preg_match('/^Location:\s*(.*)$/im', $head, $m)) +			{ +				// Recurse to the given location +				if ($uri != $m[1]) +				{ +					$xrds = self::discoverXRDS($m[1], $recur+1); +				} +				else +				{ +					// Referring to the same uri, bail out +					$xrds = false; +				} +			} +			else +			{ +				// Not an XRDS file an nowhere else to check +				$xrds = false; +			} +		} +		else +		{ +			$xrds = false; +		} +		return $xrds; +	} +	 +	 +	/** +	 * Try to fetch an XRDS file at the given location.  Sends an accept header preferring the xrds file. +	 *  +	 * @param string uri +	 * @return array	(head,body), false on an error +	 */ +	static protected function curl ( $uri ) +	{ +		$ch = curl_init(); + +		curl_setopt($ch, CURLOPT_HTTPHEADER,	 array('Accept: application/xrds+xml, */*;q=0.1')); +		curl_setopt($ch, CURLOPT_USERAGENT,		 'anyMeta/OAuth 1.0 - (OAuth Discovery $LastChangedRevision: 45 $)'); +		curl_setopt($ch, CURLOPT_URL, 			 $uri); +		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +		curl_setopt($ch, CURLOPT_HEADER, 		 true); + +		$txt = curl_exec($ch); +		curl_close($ch); + +		// Tell the logger what we requested and what we received back +		$data = "GET $uri"; +		OAuthRequestLogger::setSent($data, ""); +		OAuthRequestLogger::setReceived($txt); + +		return $txt; +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthException.php b/mod/oauth_api/vendors/oauth/library/OAuthException.php new file mode 100644 index 000000000..cadd1d032 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthException.php @@ -0,0 +1,50 @@ +<?php + +/** + * Simple exception wrapper for OAuth + *  + * @version $Id: OAuthException.php 49 2008-10-01 09:43:19Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 29, 2007 5:33:54 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// TODO: something with the HTTP return code matching to the problem + +require_once dirname(__FILE__) . '/OAuthRequestLogger.php'; + +class OAuthException extends Exception +{ +	function __construct ( $message ) +	{ +		Exception::__construct($message); +		OAuthRequestLogger::addNote('OAuthException: '.$message); +	} + +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthRequest.php b/mod/oauth_api/vendors/oauth/library/OAuthRequest.php new file mode 100644 index 000000000..c0d6ddbc7 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthRequest.php @@ -0,0 +1,801 @@ +<?php + +/** + * Request wrapper class.  Prepares a request for consumption by the OAuth routines + *  + * @version $Id: OAuthRequest.php 50 2008-10-01 15:11:08Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 12:20:31 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +require_once dirname(__FILE__) . '/OAuthException.php'; + +/** + * Object to parse an incoming OAuth request or prepare an outgoing OAuth request + */ +class OAuthRequest  +{ +	/* the realm for this request */ +	protected $realm; +	 +	/* all the parameters, RFC3986 encoded name/value pairs */ +	protected $param = array(); + +	/* the parsed request uri */ +	protected $uri_parts; + +	/* the raw request uri */ +	protected $uri; + +	/* the request headers */ +	protected $headers; + +	/* the request method */ +	protected $method; +	 +	/* the body of the OAuth request */ +	protected $body; +	 + +	/** +	 * Construct from the current request. Useful for checking the signature of a request. +	 * When not supplied with any parameters this will use the current request. +	 *  +	 * @param string	uri				might include parameters +	 * @param string	method			GET, PUT, POST etc. +	 * @param string	parameters		additional post parameters, urlencoded (RFC1738) +	 * @param array		headers			headers for request +	 * @param string	body			optional body of the OAuth request (POST or PUT) +	 */ +	function __construct ( $uri = null, $method = 'GET', $parameters = '', $headers = array(), $body = null ) +	{ +		if (empty($uri)) +		{ +			if (is_object($_SERVER)) +			{ +				// Tainted arrays - the normal stuff in anyMeta +				$method	= $_SERVER->REQUEST_METHOD->getRawUnsafe(); +				$uri	= $_SERVER->REQUEST_URI->getRawUnsafe(); +			} +			else +			{ +				// non anyMeta systems +				$method	= $_SERVER['REQUEST_METHOD']; +				$uri	= $_SERVER['REQUEST_URI']; +			} +			$headers      = getallheaders(); +			$parameters   = ''; +			$this->method = strtoupper($method); +			 +			// If this is a post then also check the posted variables +			if (strcasecmp($method, 'POST') == 0) +			{ +				/* +				// TODO: what to do with 'multipart/form-data'? +				if ($this->getRequestContentType() == 'multipart/form-data') +				{ +					throw new OAuthException('Unsupported POST content type, expected "application/x-www-form-urlencoded" got "'.@$_SERVER['CONTENT_TYPE'].'"'); +				} +				*/ +				if ($this->getRequestContentType() == 'application/x-www-form-urlencoded') +				{ +					// Get the posted body (when available) +					if (!isset($headers['X-OAuth-Test'])) +					{ +						$parameters .= $this->getRequestBody(); +					} +				} +				else +				{ +					$body = $this->getRequestBody(); +				} +			} +			else if (strcasecmp($method, 'PUT') == 0) +			{ +				$body = $this->getRequestBody(); +			} +		} + +		$this->method  = strtoupper($method); +		$this->headers = $headers; +		// Store the values, prepare for oauth +		$this->uri     = $uri; +		$this->body    = $body; +		$this->parseUri($parameters); +		$this->parseHeaders(); +		$this->transcodeParams(); +	} + + +	/** +	 * Return the signature base string. +	 * Note that we can't use rawurlencode due to specified use of RFC3986. +	 *  +	 * @return string +	 */ +	function signatureBaseString () +	{ +		$sig 	= array(); +		$sig[]	= $this->method; +		$sig[]	= $this->getRequestUrl(); +		$sig[]	= $this->getNormalizedParams(); +		 +		return implode('&', array_map(array($this, 'urlencode'), $sig)); +	} +	 +	 +	/** +	 * Calculate the signature of the request, using the method in oauth_signature_method. +	 * The signature is returned encoded in the form as used in the url.  So the base64 and +	 * urlencoding has been done. +	 *  +	 * @param string consumer_secret +	 * @param string token_secret +	 * @exception when not all parts available +	 * @return string +	 */ +	function calculateSignature ( $consumer_secret, $token_secret, $token_type = 'access' ) +	{ +		$required = array( +						'oauth_consumer_key', +						'oauth_signature_method', +						'oauth_timestamp', +						'oauth_nonce' +					); + +		if ($token_type !== false) +		{ +			$required[] = 'oauth_token'; +		} + +		foreach ($required as $req) +		{ +			if (!isset($this->param[$req])) +			{ +				throw new OAuthException('Can\'t sign request, missing parameter "'.$req.'"'); +			} +		} + +		$this->checks(); + +		$base      = $this->signatureBaseString(); +		$signature = $this->calculateDataSignature($base, $consumer_secret, $token_secret, $this->param['oauth_signature_method']); +		return $signature; +	} + +	 +	/** +	 * Calculate the signature of a string. +	 * Uses the signature method from the current parameters. +	 *  +	 * @param string 	data +	 * @param string	consumer_secret +	 * @param string	token_secret +	 * @param string 	signature_method +	 * @exception OAuthException thrown when the signature method is unknown  +	 * @return string signature +	 */ +	function calculateDataSignature ( $data, $consumer_secret, $token_secret, $signature_method ) +	{ +		if (is_null($data)) +		{ +			$data = ''; +		} + +		$sig = $this->getSignatureMethod($signature_method); +		return $sig->signature($this, $data, $consumer_secret, $token_secret); +	} + + +	/** +	 * Select a signature method from the list of available methods. +	 * We try to check the most secure methods first. +	 *  +	 * @todo Let the signature method tell us how secure it is +	 * @param array methods +	 * @exception OAuthException when we don't support any method in the list +	 * @return string +	 */ +	public function selectSignatureMethod ( $methods ) +	{ +		if (in_array('HMAC-SHA1', $methods)) +		{ +			$method = 'HMAC-SHA1'; +		} +		else if (in_array('MD5', $methods)) +		{ +			$method = 'MD5'; +		} +		else +		{ +			$method = false; +			foreach ($methods as $m) +			{ +				$m = strtoupper($m); +				$m = preg_replace('/[^A-Z0-9]/', '_', $m); +				if (file_exists(dirname(__FILE__).'/signature_method/OAuthSignatureMethod_'.$m.'.php')) +				{ +					$method = $m; +					break; +				} +			} +			 +			if (empty($method)) +			{ +				throw new OAuthException('None of the signing methods is supported.'); +			} +		} +		return $method; +	} + +	 +	/** +	 * Fetch the signature object used for calculating and checking the signature base string +	 *  +	 * @param string method +	 * @return OAuthSignatureMethod object +	 */ +	function getSignatureMethod ( $method ) +	{ +		$m     = strtoupper($method); +		$m     = preg_replace('/[^A-Z0-9]/', '_', $m); +		$class = 'OAuthSignatureMethod_'.$m; + +		if (file_exists(dirname(__FILE__).'/signature_method/'.$class.'.php')) +		{ +			require_once dirname(__FILE__).'/signature_method/'.$class.'.php'; +			$sig = new $class(); +		} +		else +		{ +			throw new OAuthException('Unsupported signature method "'.$m.'".'); +		} +		return $sig; +	} + + +	/** +	 * Perform some sanity checks. +	 *  +	 * @exception OAuthException thrown when sanity checks failed +	 */ +	function checks () +	{ +		if (isset($this->param['oauth_version'])) +		{ +			$version = $this->urldecode($this->param['oauth_version']); +			if ($version != '1.0') +			{ +				throw new OAuthException('Expected OAuth version 1.0, got "'.$this->param['oauth_version'].'"'); +			} +		} +	} + + +	/** +	 * Return the request method +	 *  +	 * @return string +	 */ +	function getMethod () +	{ +		return $this->method; +	} + +	/** +	 * Return the complete parameter string for the signature check. +	 * All parameters are correctly urlencoded and sorted on name and value +	 *  +	 * @return string +	 */ +	function getNormalizedParams () +	{ +		/* +		// sort by name, then by value  +		// (needed when we start allowing multiple values with the same name) +		$keys   = array_keys($this->param); +		$values = array_values($this->param); +		array_multisort($keys, SORT_ASC, $values, SORT_ASC); +        */ +        $params     = $this->param; +		$normalized = array(); + +		ksort($params); +		foreach ($params as $key => $value) +		{ +		    // all names and values are already urlencoded, exclude the oauth signature +		    if ($key != 'oauth_signature') +		   	{ +				if (is_array($value)) +				{ +					$value_sort = $value; +					sort($value_sort); +					foreach ($value_sort as $v) +					{ +						$normalized[] = $key.'='.$v; +					} +				} +				else +				{ +					$normalized[] = $key.'='.$value; +				} +			} +		} +		return implode('&', $normalized); +	} + + +	/** +	 * Return the normalised url for signature checks +	 */ +	function getRequestUrl () +	{ +        $url =  $this->uri_parts['scheme'] . '://' +              . $this->uri_parts['user'] . (!empty($this->uri_parts['pass']) ? ':' : '') +              . $this->uri_parts['pass'] . (!empty($this->uri_parts['user']) ? '@' : '') +			  . $this->uri_parts['host']; +			   +		if (	$this->uri_parts['port']  +			&&	$this->uri_parts['port'] != $this->defaultPortForScheme($this->uri_parts['scheme'])) +		{ +			$url .= ':'.$this->uri_parts['port']; +		} +		if (!empty($this->uri_parts['path'])) +		{ +			$url .= $this->uri_parts['path']; +		} +		return $url; +	} +	 +	 +	/** +	 * Get a parameter, value is always urlencoded +	 *  +	 * @param string	name +	 * @param boolean	urldecode	set to true to decode the value upon return +	 * @return string value		false when not found +	 */ +	function getParam ( $name, $urldecode = false ) +	{ +		if (isset($this->param[$name])) +		{ +			$s = $this->param[$name]; +		} +		else if (isset($this->param[$this->urlencode($name)])) +		{ +			$s = $this->param[$this->urlencode($name)]; +		} +		else +		{ +			$s = false; +		} +		if (!empty($s) && $urldecode) +		{ +			if (is_array($s)) +			{ +				$s = array_map(array($this,'urldecode'), $s); +			} +			else +			{ +				$s = $this->urldecode($s); +			} +		} +		return $s; +	} + +	/** +	 * Set a parameter +	 *  +	 * @param string	name +	 * @param string	value +	 * @param boolean	encoded	set to true when the values are already encoded +	 */ +	function setParam ( $name, $value, $encoded = false ) +	{ +		if (!$encoded) +		{ +			$name_encoded = $this->urlencode($name); +			if (is_array($value)) +			{ +				foreach ($value as $v) +				{ +					$this->param[$name_encoded][] = $this->urlencode($v); +				} +			} +			else +			{ +				$this->param[$name_encoded] = $this->urlencode($value); +			} +		} +		else +		{ +			$this->param[$name] = $value; +		} +	} + + +	/** +	 * Re-encode all parameters so that they are encoded using RFC3986. +	 * Updates the $this->param attribute. +	 */ +	protected function transcodeParams () +	{ +		$params      = $this->param; +		$this->param = array(); +		 +		foreach ($params as $name=>$value) +		{ +			if (is_array($value)) +			{ +				$this->param[$this->urltranscode($name)] = array_map(array($this,'urltranscode'), $value); +			} +			else +			{ +				$this->param[$this->urltranscode($name)] = $this->urltranscode($value); +			} +		} +	} + + + +	/** +	 * Return the body of the OAuth request. +	 *  +	 * @return string		null when no body +	 */ +	function getBody () +	{ +		return $this->body; +	} + + +	/** +	 * Return the body of the OAuth request. +	 *  +	 * @return string		null when no body +	 */ +	function setBody ( $body ) +	{ +		$this->body = $body; +	} + + +	/** +	 * Parse the uri into its parts.  Fill in the missing parts. +	 *  +	 * @todo  check for the use of https, right now we default to http +	 * @todo  support for multiple occurences of parameters +	 * @param string $parameters  optional extra parameters (from eg the http post) +	 */ +	protected function parseUri ( $parameters ) +	{ +		$ps = parse_url($this->uri); + +		// Get the current/requested method +		if (empty($ps['scheme'])) +		{ +			$ps['scheme'] = 'http'; +		} +		else +		{ +			$ps['scheme'] = strtolower($ps['scheme']); +		} + +		// Get the current/requested host +		if (empty($ps['host'])) +		{ +			if (isset($_SERVER['HTTP_HOST'])) +			{ +				$ps['host'] = $_SERVER['HTTP_HOST']; +			} +			else +			{ +				$ps['host'] = ''; +			} +		} +		$ps['host'] = mb_strtolower($ps['host']); +		if (!preg_match('/^[a-z0-9\.\-]+$/', $ps['host'])) +		{ +			throw new OAuthException('Unsupported characters in host name'); +		} + +		// Get the port we are talking on +		if (empty($ps['port'])) +		{ +			$ps['port'] = $this->defaultPortForScheme($ps['scheme']); +		} + +		if (empty($ps['user'])) +		{ +			$ps['user'] = ''; +		} +		if (empty($ps['pass'])) +		{ +			$ps['pass'] = ''; +		} +		if (empty($ps['path'])) +		{ +			$ps['path'] = '/'; +		} +		if (empty($ps['query'])) +		{ +			$ps['query'] = ''; +		} +		if (empty($ps['fragment'])) +		{ +			$ps['fragment'] = ''; +		} + +		// Now all is complete - parse all parameters +		foreach (array($ps['query'], $parameters) as $params) +		{ +			if (strlen($params) > 0) +			{ +				$params = explode('&', $params); +				foreach ($params as $p) +				{ +					@list($name, $value) = explode('=', $p, 2); +					$this->param[$name]  = $value; +				} +			} +		} +		$this->uri_parts = $ps; +	} + + +	/** +	 * Return the default port for a scheme +	 *  +	 * @param string scheme +	 * @return int +	 */ +	protected function defaultPortForScheme ( $scheme ) +	{ +		switch ($scheme) +		{ +		case 'http':	return 80; +		case 'https':	return 43; +		default: +			throw new OAuthException('Unsupported scheme type, expected http or https, got "'.$scheme.'"'); +			break; +		} +	} +	 +	 +	/** +	 * Encode a string according to the RFC3986 +	 *  +	 * @param string s +	 * @return string +	 */ +	function urlencode ( $s ) +	{ +		if ($s === false) +		{ +			return $s; +		} +		else +		{ +			return str_replace('%7E', '~', rawurlencode($s)); +		} +	} +	 +	/** +	 * Decode a string according to RFC3986. +	 * Also correctly decodes RFC1738 urls. +	 *  +	 * @param string s +	 * @return string +	 */ +	function urldecode ( $s ) +	{ +		if ($s === false) +		{ +			return $s; +		} +		else +		{ +			return rawurldecode($s); +		} +	} + +	/** +	 * urltranscode - make sure that a value is encoded using RFC3986. +	 * We use a basic urldecode() function so that any use of '+' as the +	 * encoding of the space character is correctly handled. +	 *  +	 * @param string s +	 * @return string +	 */ +	function urltranscode ( $s ) +	{ +		if ($s === false) +		{ +			return $s; +		} +		else +		{ +			return $this->urlencode(urldecode($s)); +		} +	} + + +	/** +	 * Parse the oauth parameters from the request headers +	 * Looks for something like: +	 * +     * Authorization: OAuth realm="http://photos.example.net/authorize", +     *           oauth_consumer_key="dpf43f3p2l4k3l03", +     *           oauth_token="nnch734d00sl2jdk", +     *           oauth_signature_method="HMAC-SHA1", +     *           oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", +     *           oauth_timestamp="1191242096", +     *           oauth_nonce="kllo9940pd9333jh", +     *           oauth_version="1.0" +     */ +	private function parseHeaders () +	{ +/* +		$this->headers['Authorization'] = 'OAuth realm="http://photos.example.net/authorize", +                oauth_consumer_key="dpf43f3p2l4k3l03", +                oauth_token="nnch734d00sl2jdk", +                oauth_signature_method="HMAC-SHA1", +                oauth_signature="tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D", +                oauth_timestamp="1191242096", +                oauth_nonce="kllo9940pd9333jh", +                oauth_version="1.0"'; +*/		 +		if (isset($this->headers['Authorization'])) +		{ +			$auth = trim($this->headers['Authorization']); +			if (strncasecmp($auth, 'OAuth', 4) == 0) +			{ +				$vs = explode(',', substr($auth, 6)); +				foreach ($vs as $v) +				{ +					if (strpos($v, '=')) +					{ +						$v = trim($v); +						list($name,$value) = explode('=', $v, 2); +						if (!empty($value) && $value{0} == '"' && substr($value, -1) == '"') +						{ +							$value = substr(substr($value, 1), 0, -1); +						} +						 +						if (strcasecmp($name, 'realm') == 0) +						{ +							$this->realm = $value; +						} +						else +						{ +							$this->param[$name] = $value; +						} +					} +				} +			} +		} +	} + + +	/** +	 * Fetch the content type of the current request +	 *  +	 * @return string +	 */ +	private function getRequestContentType () +	{ +		$content_type = 'application/octet-stream'; +		if (!empty($_SERVER) && array_key_exists('CONTENT_TYPE', $_SERVER)) +		{ +			list($content_type) = explode(';', $_SERVER['CONTENT_TYPE']); +		} +		return trim($content_type); +	} + + +	/** +	 * Get the body of a POST or PUT. +	 *  +	 * Used for fetching the post parameters and to calculate the body signature. +	 *  +	 * @return string		null when no body present (or wrong content type for body) +	 */ +	private function getRequestBody () +	{ +		$body = null; +		if ($this->method == 'POST' || $this->method == 'PUT') +		{ +			$body = ''; +			$fh   = @fopen('php://input', 'r'); +			if ($fh) +			{ +				while (!feof($fh)) +				{ +					$s = fread($fh, 1024); +					if (is_string($s)) +					{ +						$body .= $s; +					} +				} +				fclose($fh); +			} +		} +		return $body; +	} + +	 +	/** +	 * Simple function to perform a redirect (GET). +	 * Redirects the User-Agent, does not return. +	 *  +	 * @param string uri +	 * @param array params		parameters, urlencoded +	 * @exception OAuthException when redirect uri is illegal +	 */ +	public function redirect ( $uri, $params ) +	{ +		if (!empty($params)) +		{ +			$q = array(); +			foreach ($params as $name=>$value) +			{ +				$q[] = $name.'='.$value; +			} +			$q_s = implode('&', $q); +			 +			if (strpos($uri, '?')) +			{ +				$uri .= '&'.$q_s; +			} +			else +			{ +				$uri .= '?'.$q_s; +			} +		} +		 +		// simple security - multiline location headers can inject all kinds of extras +		$uri = preg_replace('/\s/', '%20', $uri); +		if (strncasecmp($uri, 'http://', 7) && strncasecmp($uri, 'https://', 8)) +		{ +			if (strpos($uri, '://')) +			{ +				throw new OAuthException('Illegal protocol in redirect uri '.$uri); +			} +			$uri = 'http://'.$uri; +		} +		 +		header('HTTP/1.1 302 Found'); +		header('Location: '.$uri); +		echo ''; +		exit(); +	} +	 +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthRequestLogger.php b/mod/oauth_api/vendors/oauth/library/OAuthRequestLogger.php new file mode 100644 index 000000000..934c1c53c --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthRequestLogger.php @@ -0,0 +1,274 @@ +<?php + +/** + * Log OAuth requests + *  + * @version $Id: OAuthRequestLogger.php 55 2009-01-14 15:27:36Z scherpenisse $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Dec 7, 2007 12:22:43 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +class OAuthRequestLogger  +{ +	static private $logging			= 0; +	static private $enable_logging	= null; +	static private $store_log		= null; +	static private $note 			= ''; +	static private $user_id			= null; +	static private $request_object	= null; +	static private $sent			= null; +	static private $received		= null; +	static private $log				= array(); +	 +	/** +	 * Start any logging, checks the system configuration if logging is needed. +	 *  +	 * @param OAuthRequest  $request_object +	 */ +	static function start ( $request_object = null ) +	{ +		if (defined('OAUTH_LOG_REQUEST')) +		{ +			if (is_null(OAuthRequestLogger::$enable_logging)) +			{ +				OAuthRequestLogger::$enable_logging = true; +			} +			if (is_null(OAuthRequestLogger::$store_log)) +			{ +				OAuthRequestLogger::$store_log = true; +			} +		} + +		if (OAuthRequestLogger::$enable_logging && !OAuthRequestLogger::$logging) +		{ +			OAuthRequestLogger::$logging        = true; +			OAuthRequestLogger::$request_object = $request_object; +			ob_start(); + +			// Make sure we flush our log entry when we stop the request (eg on an exception) +			register_shutdown_function(array('OAuthRequestLogger','flush'));		 +		} +	} +	 + +	/** +	 * Force logging, needed for performing test connects independent from the debugging setting. +	 *  +	 * @param boolean  store_log		(optional) true to store the log in the db +	 */ +	static function enableLogging ( $store_log = null ) +	{ +		OAuthRequestLogger::$enable_logging = true; +		if (!is_null($store_log)) +		{ +			OAuthRequestLogger::$store_log = $store_log; +		} +	}	 + + +	/** +	 * Logs the request to the database, sends any cached output. +	 * Also called on shutdown, to make sure we always log the request being handled. +	 */ +	static function flush () +	{ +		if (OAuthRequestLogger::$logging) +		{ +			OAuthRequestLogger::$logging = false; + +			if (is_null(OAuthRequestLogger::$sent)) +			{ +				// What has been sent to the user-agent? +				$data  = ob_get_contents(); +				if (strlen($data) > 0) +				{ +					ob_end_flush(); +				} +				elseif (ob_get_level()) +				{ +					ob_end_clean(); +				} +				$hs    = headers_list(); +				$sent  = implode("\n", $hs) . "\n\n" . $data; +			} +			else +			{ +				// The request we sent +				$sent  = OAuthRequestLogger::$sent; +			} +			 +			if (is_null(OAuthRequestLogger::$received)) +			{ +				// Build the request we received +				$hs0   = getallheaders(); +				$hs    = array(); +				foreach ($hs0 as $h => $v) +				{ +					$hs[] = "$h: $v"; +				} + +				$data  = ''; +				$fh    = @fopen('php://input', 'r'); +				if ($fh) +				{ +					while (!feof($fh)) +					{ +						$s = fread($fh, 1024); +						if (is_string($s)) +						{ +							$data .= $s; +						} +					} +					fclose($fh); +				} +				$received = implode("\n", $hs) . "\n\n" . $data; +			} +			else +			{ +				// The answer we received +				$received  = OAuthRequestLogger::$received; +			} + +			// The request base string +			if (OAuthRequestLogger::$request_object) +			{ +				$base_string = OAuthRequestLogger::$request_object->signatureBaseString(); +			} +			else +			{ +				$base_string = ''; +			} + +			// Figure out to what keys we want to log this request +			$keys = array(); +			if (OAuthRequestLogger::$request_object) +			{ +				$consumer_key = OAuthRequestLogger::$request_object->getParam('oauth_consumer_key', true); +				$token        = OAuthRequestLogger::$request_object->getParam('oauth_token',        true); + +				switch (get_class(OAuthRequestLogger::$request_object)) +				{ +				// tokens are access/request tokens by a consumer +				case 'OAuthServer': +				case 'OAuthRequestVerifier': +					$keys['ocr_consumer_key'] = $consumer_key; +					$keys['oct_token']        = $token; +					break; + +				// tokens are access/request tokens to a server +				case 'OAuthRequester': +				case 'OAuthRequestSigner': +					$keys['osr_consumer_key'] = $consumer_key; +					$keys['ost_token']        = $token; +					break; +				} +			} +			 +			// Log the request +			if (OAuthRequestLogger::$store_log) +			{ +				$store = OAuthStore::instance(); +				$store->addLog($keys, $received, $sent, $base_string, OAuthRequestLogger::$note, OAuthRequestLogger::$user_id); +			} +			 +			OAuthRequestLogger::$log[] = array( +					'keys'    		=> $keys, +					'received'		=> $received, +					'sent'			=> $sent, +					'base_string'	=> $base_string, +					'note'			=> OAuthRequestLogger::$note +					); +		} +	} + + +	/** +	 * Add a note, used by the OAuthException to log all exceptions. +	 *  +	 * @param string note +	 */ +	static function addNote ( $note ) +	{ +		OAuthRequestLogger::$note .= $note . "\n\n"; +	} + +	/** +	 * Set the OAuth request object being used +	 *  +	 * @param OAuthRequest request_object +	 */ +	static function setRequestObject ( $request_object ) +	{ +		OAuthRequestLogger::$request_object = $request_object; +	} + + +	/** +	 * Set the relevant user (defaults to the current user) +	 *  +	 * @param int user_id +	 */ +	static function setUser ( $user_id ) +	{ +		OAuthRequestLogger::$user_id = $user_id; +	} +	 +	 +	/** +	 * Set the request we sent +	 *  +	 * @param string request +	 */ +	static function setSent ( $request ) +	{ +		OAuthRequestLogger::$sent = $request; +	} + +	/** +	 * Set the reply we received +	 *  +	 * @param string request +	 */ +	static function setReceived ( $reply ) +	{ +		OAuthRequestLogger::$received = $reply; +	} +	 +	 +	/** +	 * Get the the log till now +	 *  +	 * @return array +	 */ +	static function getLog () +	{ +		return OAuthRequestLogger::$log; +	} +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthRequestSigner.php b/mod/oauth_api/vendors/oauth/library/OAuthRequestSigner.php new file mode 100644 index 000000000..9f83f287f --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthRequestSigner.php @@ -0,0 +1,209 @@ +<?php + +/** + * Sign requests before performing the request. + *  + * @version $Id: OAuthRequestSigner.php 58 2009-02-23 01:47:23Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 4:02:49 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +require_once dirname(__FILE__) . '/OAuthStore.php'; +require_once dirname(__FILE__) . '/OAuthRequest.php'; + + +class OAuthRequestSigner extends OAuthRequest +{ +	protected $request; +	protected $store; +	protected $usr_id = 0; +	private   $signed = false; + +	 +	/** +	 * Construct the request to be signed.  Parses or appends the parameters in the params url. +	 * When you supply an params array, then the params should not be urlencoded. +	 * When you supply a string, then it is assumed it is of the type application/x-www-form-urlencoded +	 *  +	 * @param string request	url +	 * @param string method		PUT, GET, POST etc. +	 * @param mixed params 		string (for urlencoded data, or array with name/value pairs) +	 * @param string body		optional body for PUT and/or POST requests +	 */ +	function __construct ( $request, $method = 'GET', $params = null, $body = null ) +	{ +		$this->store = OAuthStore::instance(); +		 +		if (is_string($params)) +		{ +			parent::__construct($request, $method, $params); +		} +		else +		{ +			parent::__construct($request, $method); +			if (is_array($params)) +			{ +				foreach ($params as $name => $value) +				{ +					$this->setParam($name, $value); +				} +			} +		} +		 +		// With put/ post we might have a body (not for application/x-www-form-urlencoded requests) +		if ($method == 'PUT' || $method == 'POST') +		{ +			$this->setBody($body); +		} +	} + + +	/** +	 * Reset the 'signed' flag, so that any changes in the parameters force a recalculation +	 * of the signature. +	 */ +	function setUnsigned () +	{ +		$this->signed = false; +	} + + +	/** +	 * Sign our message in the way the server understands. +	 * Set the needed oauth_xxxx parameters. +	 *  +	 * @param int usr_id		(optional) user that wants to sign this request +	 * @param array secrets		secrets used for signing, when empty then secrets will be fetched from the token registry +	 * @param string name		name of the token to be used for signing +	 * @exception OAuthException when there is no oauth relation with the server +	 * @exception OAuthException when we don't support the signing methods of the server +	 */	 +	function sign ( $usr_id = 0, $secrets = null, $name = '' ) +	{ +		$url = $this->getRequestUrl(); +		if (empty($secrets)) +		{ +			// get the access tokens for the site (on an user by user basis) +			$secrets = $this->store->getSecretsForSignature($url, $usr_id, $name); +		} +		if (empty($secrets)) +		{ +			throw new OAuthException('No OAuth relation with the server for at "'.$url.'"'); +		} + +		$signature_method = $this->selectSignatureMethod($secrets['signature_methods']); + +		$token		  = isset($secrets['token'])        ? $secrets['token']        : ''; +		$token_secret = isset($secrets['token_secret']) ? $secrets['token_secret'] : ''; + +		$this->setParam('oauth_signature_method',$signature_method); +		$this->setParam('oauth_signature',		 ''); +		$this->setParam('oauth_nonce', 			 !empty($secrets['nonce'])     ? $secrets['nonce']     : uniqid('')); +		$this->setParam('oauth_timestamp', 		 !empty($secrets['timestamp']) ? $secrets['timestamp'] : time()); +		$this->setParam('oauth_token', 		 	 $token); +		$this->setParam('oauth_consumer_key',	 $secrets['consumer_key']); +		$this->setParam('oauth_version',		 '1.0'); +		 +		$body = $this->getBody(); +		if (!is_null($body)) +		{ +			// We also need to sign the body, use the default signature method +			$body_signature = $this->calculateDataSignature($body, $secrets['consumer_secret'], $token_secret, $signature_method); +			$this->setParam('xoauth_body_signature', $body_signature, true); +		} +		 +		$signature = $this->calculateSignature($secrets['consumer_secret'], $token_secret); +		$this->setParam('oauth_signature',		 $signature, true); +		 +		$this->signed = true; +		$this->usr_id = $usr_id; +	} + + +	/** +	 * Builds the Authorization header for the request. +	 * Adds all oauth_ and xoauth_ parameters to the Authorization header. +	 *  +	 * @return string +	 */ +	function getAuthorizationHeader () +	{ +		if (!$this->signed) +		{ +			$this->sign($this->usr_id); +		} +		$h   = array(); +		$h[] = 'Authorization: OAuth realm=""'; +		foreach ($this->param as $name => $value) +		{ +			if (strncmp($name, 'oauth_', 6) == 0 || strncmp($name, 'xoauth_', 7) == 0) +          	{ +				$h[] = $name.'="'.$value.'"'; +			} +		} +		$hs = implode(', ', $h); +		return $hs; +	} + + +	/** +	 * Builds the application/x-www-form-urlencoded parameter string.  Can be appended as +	 * the query part to a GET or inside the request body for a POST. +	 *  +	 * @param boolean oauth_as_header		(optional) set to false to include oauth parameters +	 * @return string +	 */	 +	function getQueryString ( $oauth_as_header = true ) +	{ +		$parms = array(); +		foreach ($this->param as $name => $value) +		{ +			if (	!$oauth_as_header  +				||	(strncmp($name, 'oauth_', 6) != 0 && strncmp($name, 'xoauth_', 7) != 0)) +			{ +				if (is_array($value)) +				{ +					foreach ($value as $v) +					{ +						$parms[] = $name.'='.$v; +					} +				} +				else +				{ +					$parms[] = $name.'='.$value; +				} +			} +		} +		return implode('&', $parms); +	} + +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthRequestVerifier.php b/mod/oauth_api/vendors/oauth/library/OAuthRequestVerifier.php new file mode 100644 index 000000000..4b4db9685 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthRequestVerifier.php @@ -0,0 +1,262 @@ +<?php + +/** + * Verify the current request.  Checks if signed and if the signature is correct. + * When correct then also figures out on behalf of which user this request is being made. + *   + * @version $Id: OAuthRequestVerifier.php 51 2008-10-15 15:15:47Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 4:35:03 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__) . '/OAuthStore.php'; +require_once dirname(__FILE__) . '/OAuthRequest.php'; + + +class OAuthRequestVerifier extends OAuthRequest +{ +	private $request; +	private $store; +	 +	/** +	 * Construct the request to be verified +	 *  +	 * @param string request +	 * @param string method +	 */ +	function __construct ( $uri = null, $method = 'GET' ) +	{ +		$this->store = OAuthStore::instance(); +		parent::__construct($uri, $method); +		 +		OAuthRequestLogger::start($this); +	} +	 +	 +	/** +	 * See if the current request is signed with OAuth +	 *  +	 * @return boolean +	 */ +	static public function requestIsSigned () +	{ +		if (isset($_REQUEST['oauth_signature'])) +		{ +			$signed = true; +		} +		else +		{ +			$hs = getallheaders(); +			if (isset($hs['Authorization']) && strpos($hs['Authorization'], 'oauth_signature') !== false) +			{ +				$signed = true; +			} +			else +			{ +				$signed = false; +			} +		} +		return $signed; +	} + + +	/** +	 * Verify the request if it seemed to be signed. +	 *  +	 * @param string token_type the kind of token needed, defaults to 'access' +	 * @exception OAuthException thrown when the request did not verify +	 * @return boolean	true when signed, false when not signed +	 */ +	public function verifyIfSigned ( $token_type = 'access' ) +	{ +		if ($this->getParam('oauth_consumer_key')) +		{ +			OAuthRequestLogger::start($this); +			$this->verify($token_type); +			$signed = true; +			OAuthRequestLogger::flush(); +		} +		else +		{ +			$signed = false; +		} +		return $signed; +	} + +	 +	/** +	 * Verify the request +	 *  +	 * @param string token_type the kind of token needed, defaults to 'access' (false, 'access', 'request') +	 * @exception OAuthException thrown when the request did not verify +	 * @return int user_id associated with token (false when no user associated) +	 */ +	public function verify ( $token_type = 'access' ) +	{ +		$consumer_key = $this->getParam('oauth_consumer_key'); +		$token        = $this->getParam('oauth_token'); +		$user_id      = false; + +		if ($consumer_key && ($token_type === false || $token)) +		{ +			$secrets = $this->store->getSecretsForVerify(	$this->urldecode($consumer_key),  +															$this->urldecode($token),  +															$token_type); + +			$this->store->checkServerNonce(	$this->urldecode($consumer_key), +											$this->urldecode($token), +											$this->getParam('oauth_timestamp', true), +											$this->getParam('oauth_nonce', true)); + +			$oauth_sig = $this->getParam('oauth_signature'); +			if (empty($oauth_sig)) +			{ +				throw new OAuthException('Verification of signature failed (no oauth_signature in request).'); +			}  +			 +			try +			{ +				$this->verifySignature($secrets['consumer_secret'], $secrets['token_secret'], $token_type); +			} +			catch (OAuthException $e) +			{ +				throw new OAuthException('Verification of signature failed (signature base string was "'.$this->signatureBaseString().'").'); +			} +			 +			// Check the optional body signature +			if ($this->getParam('xoauth_body_signature')) +			{ +				$method = $this->getParam('xoauth_body_signature_method'); +				if (empty($method)) +				{ +					$method = $this->getParam('oauth_signature_method'); +				} + +				try +				{ +					$this->verifyDataSignature($this->getBody(), $secrets['consumer_secret'], $secrets['token_secret'], $method, $this->getParam('xoauth_body_signature')); +				} +				catch (OAuthException $e) +				{ +					throw new OAuthException('Verification of body signature failed.'); +				} +			} +			 +			// All ok - fetch the user associated with this request +			if (isset($secrets['user_id'])) +			{ +				$user_id = $secrets['user_id']; +			} +			 +			// Check if the consumer wants us to reset the ttl of this token +			$ttl = $this->getParam('xoauth_token_ttl', true); +			if (is_numeric($ttl)) +			{ +				$this->store->setConsumerAccessTokenTtl($this->urldecode($token), $ttl); +			} +		} +		else +		{ +			throw new OAuthException('Can\'t verify request, missing oauth_consumer_key or oauth_token'); +		} +		return $user_id; +	} + + + +	/** +	 * Verify the signature of the request, using the method in oauth_signature_method. +	 * The signature is returned encoded in the form as used in the url.  So the base64 and +	 * urlencoding has been done. +	 *  +	 * @param string consumer_secret +	 * @param string token_secret +	 * @exception OAuthException thrown when the signature method is unknown  +	 * @exception OAuthException when not all parts available +	 * @exception OAuthException when signature does not match +	 */ +	public function verifySignature ( $consumer_secret, $token_secret, $token_type = 'access' ) +	{ +		$required = array( +						'oauth_consumer_key', +						'oauth_signature_method', +						'oauth_timestamp', +						'oauth_nonce', +						'oauth_signature' +					); + +		if ($token_type !== false) +		{ +			$required[] = 'oauth_token'; +		} + +		foreach ($required as $req) +		{ +			if (!isset($this->param[$req])) +			{ +				throw new OAuthException('Can\'t verify request signature, missing parameter "'.$req.'"'); +			} +		} + +		$this->checks(); + +		$base = $this->signatureBaseString(); +		$this->verifyDataSignature($base, $consumer_secret, $token_secret, $this->param['oauth_signature_method'], $this->param['oauth_signature']); +	} + + + +	/** +	 * Verify the signature of a string. +	 *  +	 * @param string 	data +	 * @param string	consumer_secret +	 * @param string	token_secret +	 * @param string 	signature_method +	 * @param string 	signature +	 * @exception OAuthException thrown when the signature method is unknown  +	 * @exception OAuthException when signature does not match +	 */ +	public function verifyDataSignature ( $data, $consumer_secret, $token_secret, $signature_method, $signature ) +	{ +		if (is_null($data)) +		{ +			$data = ''; +		} + +		$sig = $this->getSignatureMethod($signature_method); +		if (!$sig->verify($this, $data, $consumer_secret, $token_secret, $signature)) +		{ +			throw new OAuthException('Signature verification failed ('.$signature_method.')'); +		} +	} + +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthRequester.php b/mod/oauth_api/vendors/oauth/library/OAuthRequester.php new file mode 100644 index 000000000..87f9586c0 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthRequester.php @@ -0,0 +1,508 @@ +<?php + +/** + * Perform a signed OAuth request with a GET, POST, PUT or DELETE operation. + *  + * @version $Id: OAuthRequester.php 63 2009-02-25 10:24:33Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 20, 2007 1:41:38 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__) . '/OAuthRequestSigner.php'; +require_once dirname(__FILE__) . '/body/OAuthBodyContentDisposition.php'; + + +class OAuthRequester extends OAuthRequestSigner +{ +	protected $files; + +	/** +	 * Construct a new request signer.  Perform the request with the doRequest() method below. +	 *  +	 * A request can have either one file or a body, not both.  +	 *  +	 * The files array consists of arrays: +	 * - file			the filename/path containing the data for the POST/PUT +	 * - data			data for the file, omit when you have a file +	 * - mime			content-type of the file +	 * - filename		filename for content disposition header +	 *  +	 * When OAuth (and PHP) can support multipart/form-data then we can handle more than one file. +	 * For now max one file, with all the params encoded in the query string. +	 *  +	 * @param string request +	 * @param string method		http method.  GET, PUT, POST etc. +	 * @param array params		name=>value array with request parameters +	 * @param string body		optional body to send +	 * @param array files		optional files to send (max 1 till OAuth support multipart/form-data posts) +	 */ +	function __construct ( $request, $method = 'GET', $params = null, $body = null, $files = null ) +	{ +		parent::__construct($request, $method, $params, $body); + +		// When there are files, then we can construct a POST with a single file +		if (!empty($files)) +		{ +			$empty = true; +			foreach ($files as $f) +			{ +				$empty = $empty && empty($f['file']) && !isset($f['data']); +			} +			 +			if (!$empty) +			{ +				if (!is_null($body)) +				{ +					throw new OAuthException('When sending files, you can\'t send a body as well.'); +				} +				$this->files = $files; +			} +		} +	} + + +	/** +	 * Perform the request, returns the response code, headers and body. +	 *  +	 * @param int usr_id			optional user id for which we make the request +	 * @param array curl_options	optional extra options for curl request +	 * @param array options			options like name and token_ttl +	 * @exception OAuthException when authentication not accepted +	 * @exception OAuthException when signing was not possible +	 * @return array (code=>int, headers=>array(), body=>string) +	 */ +	function doRequest ( $usr_id = 0, $curl_options = array(), $options = array() ) +	{ +		$name = isset($options['name']) ? $options['name'] : ''; +		if (isset($options['token_ttl'])) +		{ +			$this->setParam('xoauth_token_ttl', intval($options['token_ttl'])); +		} + +		if (!empty($this->files)) +		{ +			// At the moment OAuth does not support multipart/form-data, so try to encode +			// the supplied file (or data) as the request body and add a content-disposition header. +			list($extra_headers, $body) = OAuthBodyContentDisposition::encodeBody($this->files); +			$this->setBody($body); +			$curl_options = $this->prepareCurlOptions($curl_options, $extra_headers); +		} +		$this->sign($usr_id, null, $name); +		$text   = $this->curl_raw($curl_options); +		$result = $this->curl_parse($text);	 +		if ($result['code'] >= 400) +		{ +			throw new OAuthException('Request failed with code ' . $result['code'] . ': ' . $result['body']); +		} + +		// Record the token time to live for this server access token, immediate delete iff ttl <= 0 +		// Only done on a succesful request.	 +		$token_ttl = $this->getParam('xoauth_token_ttl', false); +		if (is_numeric($token_ttl)) +		{ +			$this->store->setServerTokenTtl($this->getParam('oauth_consumer_key',true), $this->getParam('oauth_token',true), $token_ttl); +		} + +		return $result; +	} + +	 +	/** +	 * Request a request token from the site belonging to consumer_key +	 *  +	 * @param string consumer_key +	 * @param int usr_id +	 * @param array params (optional) extra arguments for when requesting the request token +	 * @param string method (optional) change the method of the request, defaults to POST (as it should be) +	 * @param array options (optional) options like name and token_ttl +	 * @exception OAuthException when no key could be fetched +	 * @exception OAuthException when no server with consumer_key registered +	 * @return array (authorize_uri, token) +	 */ +	static function requestRequestToken ( $consumer_key, $usr_id, $params = null, $method = 'POST', $options = array() ) +	{ +		OAuthRequestLogger::start(); + +		if (isset($options['token_ttl']) && is_numeric($options['token_ttl'])) +		{ +			$params['xoauth_token_ttl'] = intval($options['token_ttl']); +		} + +		$store	= OAuthStore::instance(); +		$r		= $store->getServer($consumer_key, $usr_id); +		$uri 	= $r['request_token_uri']; + +		$oauth 	= new OAuthRequester($uri, $method, $params); +		$oauth->sign($usr_id, $r); +		$text	= $oauth->curl_raw(); + +		if (empty($text)) +		{ +			throw new OAuthException('No answer from the server "'.$uri.'" while requesting a request token'); +		} +		$data	= $oauth->curl_parse($text); +		if ($data['code'] != 200) +		{ +			throw new OAuthException('Unexpected result from the server "'.$uri.'" ('.$data['code'].') while requesting a request token'); +		} +		$token  = array(); +		$params = explode('&', $data['body']); +		foreach ($params as $p) +		{ +			@list($name, $value) = explode('=', $p, 2); +			$token[$name] = $oauth->urldecode($value); +		} +		 +		if (!empty($token['oauth_token']) && !empty($token['oauth_token_secret'])) +		{ +			$opts = array(); +			if (isset($options['name'])) +			{ +				$opts['name'] = $options['name']; +			} +			if (isset($token['xoauth_token_ttl'])) +			{ +				$opts['token_ttl'] = $token['xoauth_token_ttl']; +			} +			$store->addServerToken($consumer_key, 'request', $token['oauth_token'], $token['oauth_token_secret'], $usr_id, $opts); +		} +		else +		{ +			throw new OAuthException('The server "'.$uri.'" did not return the oauth_token or the oauth_token_secret'); +		} + +		OAuthRequestLogger::flush(); + +		// Now we can direct a browser to the authorize_uri +		return array( +					'authorize_uri' => $r['authorize_uri'], +					'token'			=> $token['oauth_token'] +				); +	} + + +	/** +	 * Request an access token from the site belonging to consumer_key. +	 * Before this we got an request token, now we want to exchange it for +	 * an access token. +	 *  +	 * @param string consumer_key +	 * @param string token +	 * @param int usr_id		user requesting the access token +	 * @param string method (optional) change the method of the request, defaults to POST (as it should be) +	 * @param array options (optional) extra options for request, eg token_ttl +	 * @exception OAuthException when no key could be fetched +	 * @exception OAuthException when no server with consumer_key registered +	 */ +	static function requestAccessToken ( $consumer_key, $token, $usr_id, $method = 'POST', $options = array() ) +	{ +		OAuthRequestLogger::start(); + +		$store	    = OAuthStore::instance(); +		$r		    = $store->getServerTokenSecrets($consumer_key, $token, 'request', $usr_id); +		$uri 	    = $r['access_token_uri']; +		$token_name	= $r['token_name']; + +		// Delete the server request token, this one was for one use only +		$store->deleteServerToken($consumer_key, $r['token'], 0, true); + +		// Try to exchange our request token for an access token +		$oauth 	= new OAuthRequester($uri, $method); + +		if (isset($options['token_ttl']) && is_numeric($options['token_ttl'])) +		{ +			$oauth->setParam('xoauth_token_ttl', intval($options['token_ttl'])); +		} + +		OAuthRequestLogger::setRequestObject($oauth); + +		$oauth->sign($usr_id, $r); +		$text	= $oauth->curl_raw(); +		if (empty($text)) +		{ +			throw new OAuthException('No answer from the server "'.$uri.'" while requesting a request token'); +		} +		$data	= $oauth->curl_parse($text); + +		if ($data['code'] != 200) +		{ +			throw new OAuthException('Unexpected result from the server "'.$uri.'" ('.$data['code'].') while requesting a request token'); +		} + +		$token  = array(); +		$params = explode('&', $data['body']); +		foreach ($params as $p) +		{ +			@list($name, $value) = explode('=', $p, 2); +			$token[$oauth->urldecode($name)] = $oauth->urldecode($value); +		} +		 +		if (!empty($token['oauth_token']) && !empty($token['oauth_token_secret'])) +		{ +			$opts         = array(); +			$opts['name'] = $token_name; +			if (isset($token['xoauth_token_ttl'])) +			{ +				$opts['token_ttl'] = $token['xoauth_token_ttl']; +			} +			$store->addServerToken($consumer_key, 'access', $token['oauth_token'], $token['oauth_token_secret'], $usr_id, $opts); +		} +		else +		{ +			throw new OAuthException('The server "'.$uri.'" did not return the oauth_token or the oauth_token_secret'); +		} + +		OAuthRequestLogger::flush(); +	} + + + +	/** +	 * Open and close a curl session passing all the options to the curl libs +	 *  +	 * @param string url the http address to fetch +	 * @exception OAuthException when temporary file for PUT operation could not be created +	 * @return string the result of the curl action +	 */ +	protected function curl_raw ( $opts = array() ) +	{ +		if (isset($opts[CURLOPT_HTTPHEADER])) +		{ +			$header = $opts[CURLOPT_HTTPHEADER]; +		} +		else +		{ +			$header = array(); +		} + +		$ch 		= curl_init(); +		$method		= $this->getMethod(); +		$url		= $this->getRequestUrl(); +		$header[]	= $this->getAuthorizationHeader(); +		$query		= $this->getQueryString(); +		$body		= $this->getBody(); + +		$has_content_type = false; +		foreach ($header as $h) +		{ +			if (strncasecmp($h, 'Content-Type:', 13) == 0) +			{ +				$has_content_type = true; +			} +		} +		 +		if (!is_null($body)) +		{ +			if ($method == 'TRACE') +			{ +				throw new OAuthException('A body can not be sent with a TRACE operation'); +			} + +			// PUT and POST allow a request body +			if (!empty($query)) +			{ +				$url .= '?'.$query; +			} + +			// Make sure that the content type of the request is ok +			if (!$has_content_type) +			{ +				$header[]         = 'Content-Type: application/octet-stream'; +				$has_content_type = true; +			} +			 +			// When PUTting, we need to use an intermediate file (because of the curl implementation) +			if ($method == 'PUT') +			{ +				/* +				if (version_compare(phpversion(), '5.2.0') >= 0) +				{ +					// Use the data wrapper to create the file expected by the put method +					$put_file = fopen('data://application/octet-stream;base64,'.base64_encode($body)); +				} +				*/ +				 +				$put_file = @tmpfile(); +				if (!$put_file) +				{ +					throw new OAuthException('Could not create tmpfile for PUT operation'); +				} +				fwrite($put_file, $body); +				fseek($put_file, 0); + +				curl_setopt($ch, CURLOPT_PUT, 		  true); +  				curl_setopt($ch, CURLOPT_INFILE, 	  $put_file); +  				curl_setopt($ch, CURLOPT_INFILESIZE,  strlen($body)); +			} +			else +			{ +				curl_setopt($ch, CURLOPT_POST,		  true); +				curl_setopt($ch, CURLOPT_POSTFIELDS,  $body); +  			} +		} +		else +		{ +			// a 'normal' request, no body to be send +			if ($method == 'POST') +			{ +				if (!$has_content_type) +				{ +					$header[]         = 'Content-Type: application/x-www-form-urlencoded'; +					$has_content_type = true; +				} + +				curl_setopt($ch, CURLOPT_POST, 		  true); +				curl_setopt($ch, CURLOPT_POSTFIELDS,  $query); +			} +			else +			{ +				if (!empty($query)) +				{ +					$url .= '?'.$query; +				} +				if ($method != 'GET') +				{ +					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); +				} +			} +		} + +		curl_setopt($ch, CURLOPT_HTTPHEADER,	 $header); +		curl_setopt($ch, CURLOPT_USERAGENT,		 'anyMeta/OAuth 1.0 - ($LastChangedRevision: 63 $)'); +		curl_setopt($ch, CURLOPT_URL, 			 $url); +		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +		curl_setopt($ch, CURLOPT_HEADER, 		 true); +	 +		foreach ($opts as $k => $v) +		{ +			if ($k != CURLOPT_HTTPHEADER) +			{ +				curl_setopt($ch, $k, $v); +			} +		} + +		$txt = curl_exec($ch); +		curl_close($ch); +		 +		if (!empty($put_file)) +		{ +			fclose($put_file); +		} + +		// Tell the logger what we requested and what we received back +		$data = $method . " $url\n".implode("\n",$header); +		if (is_string($body)) +		{ +			$data .= "\n\n".$body; +		} +		else if ($method == 'POST') +		{ +			$data .= "\n\n".$query; +		} + +		OAuthRequestLogger::setSent($data, $body); +		OAuthRequestLogger::setReceived($txt); + +		return $txt; +	} +	 +	 +	/** +	 * Parse an http response +	 *  +	 * @param string response the http text to parse +	 * @return array (code=>http-code, headers=>http-headers, body=>body) +	 */ +	protected function curl_parse ( $response ) +	{ +		if (empty($response)) +		{ +			return array(); +		} +	 +		@list($headers,$body) = explode("\r\n\r\n",$response,2); +		$lines = explode("\r\n",$headers); + +		if (preg_match('@^HTTP/[0-9]\.[0-9] +100@', $lines[0])) +		{ +			/* HTTP/1.x 100 Continue +			 * the real data is on the next line +			 */ +			@list($headers,$body) = explode("\r\n\r\n",$body,2); +			$lines = explode("\r\n",$headers); +		} +	 +		// first line of headers is the HTTP response code  +		$http_line = array_shift($lines); +		if (preg_match('@^HTTP/[0-9]\.[0-9] +([0-9]{3})@', $http_line, $matches)) +		{ +			$code = $matches[1]; +		} +	 +		// put the rest of the headers in an array +		$headers = array(); +		foreach ($lines as $l) +		{ +			list($k, $v) = explode(': ', $l, 2); +			$headers[strtolower($k)] = $v; +		} +	 +		return array( 'code' => $code, 'headers' => $headers, 'body' => $body); +	} + + +	/** +	 * Mix the given headers into the headers that were given to curl +	 *  +	 * @param array curl_options +	 * @param array extra_headers +	 * @return array new curl options +	 */ +	protected function prepareCurlOptions ( $curl_options, $extra_headers ) +	{ +		$hs = array(); +		if (!empty($curl_options[CURLOPT_HTTPHEADER]) && is_array($curl_options[CURLOPT_HTTPHEADER])) +		{ +			foreach ($curl_options[CURLOPT_HTTPHEADER] as $h) +			{ +				list($opt, $val) = explode(':', $h, 2); +				$opt      = str_replace(' ', '-', ucwords(str_replace('-', ' ', $opt))); +				$hs[$opt] = $val; +			} +		} + +		$curl_options[CURLOPT_HTTPHEADER] = array(); +		$hs = array_merge($hs, $extra_headers);		 +		foreach ($hs as $h => $v) +		{ +			$curl_options[CURLOPT_HTTPHEADER][] = "$h: $v"; +		} +		return $curl_options; +	} +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthServer.php b/mod/oauth_api/vendors/oauth/library/OAuthServer.php new file mode 100644 index 000000000..c7f9097b3 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthServer.php @@ -0,0 +1,232 @@ +<?php + +/** + * Server layer over the OAuthRequest handler + *  + * @version $Id: OAuthServer.php 51 2008-10-15 15:15:47Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 27, 2007 12:36:38 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once 'OAuthRequestVerifier.php'; + +class OAuthServer extends OAuthRequestVerifier +{ +	/** +	 * Handle the request_token request. +	 * Returns the new request token and request token secret. +	 *  +	 * TODO: add correct result code to exception +	 *  +	 * @return string 	returned request token, false on an error +	 */ +	public function requestToken () +	{ +		OAuthRequestLogger::start($this); +		try +		{ +			$this->verify(false); +			 +			$options = array(); +			$ttl     = $this->getParam('xoauth_token_ttl', false); +			if ($ttl) +			{ +				$options['token_ttl'] = $ttl; +			} + +			// Create a request token +			$store  = OAuthStore::instance(); +			$token  = $store->addConsumerRequestToken($this->getParam('oauth_consumer_key', true), $options); +			$result = 'oauth_token='.$this->urlencode($token['token']) +					.'&oauth_token_secret='.$this->urlencode($token['token_secret']); + +			if (!empty($token['token_ttl'])) +			{ +				$result .= '&xoauth_token_ttl='.$this->urlencode($token['token_ttl']); +			} + +			$request_token = $token['token']; +					 +			header('HTTP/1.1 200 OK'); +			header('Content-Length: '.strlen($result)); +			header('Content-Type: application/x-www-form-urlencoded'); + +			echo $result; +		} +		catch (OAuthException $e) +		{ +			$request_token = false; + +			header('HTTP/1.1 401 Unauthorized'); +			header('Content-Type: text/plain'); + +			echo "OAuth Verification Failed: " . $e->getMessage(); +		} + +		OAuthRequestLogger::flush(); +		return $request_token; +	} +	 +	 +	/** +	 * Verify the start of an authorization request.  Verifies if the request token is valid. +	 * Next step is the method authorizeFinish() +	 *  +	 * Nota bene: this stores the current token, consumer key and callback in the _SESSION +	 *  +	 * @exception OAuthException thrown when not a valid request +	 * @return array token description +	 */ +	public function authorizeVerify ( ) +	{ +		OAuthRequestLogger::start($this); + +		$store = OAuthStore::instance(); +		$token = $this->getParam('oauth_token', true); +		$rs    = $store->getConsumerRequestToken($token); +		if (empty($rs)) +		{ +			throw new OAuthException('Unknown request token "'.$token.'"'); +		} + +		// We need to remember the callback		 +		if (	empty($_SESSION['verify_oauth_token']) +			||	strcmp($_SESSION['verify_oauth_token'], $rs['token'])) +		{ +			$_SESSION['verify_oauth_token'] 		= $rs['token']; +			$_SESSION['verify_oauth_consumer_key']	= $rs['consumer_key']; +			$_SESSION['verify_oauth_callback']		= $this->getParam('oauth_callback', true); +		} +		OAuthRequestLogger::flush(); +		return $rs; +	} +	 +	 +	/** +	 * Overrule this method when you want to display a nice page when +	 * the authorization is finished.  This function does not know if the authorization was +	 * succesfull, you need to check the token in the database. +	 *  +	 * @param boolean authorized	if the current token (oauth_token param) is authorized or not +	 * @param int user_id			user for which the token was authorized (or denied) +	 */ +	public function authorizeFinish ( $authorized, $user_id ) +	{ +		OAuthRequestLogger::start($this); + +		$token = $this->getParam('oauth_token', true); +		if (	isset($_SESSION['verify_oauth_token'])  +			&&	$_SESSION['verify_oauth_token'] == $token) +		{ +			// Flag the token as authorized, or remove the token when not authorized +			$store = OAuthStore::instance(); + +			// Fetch the referrer host from the oauth callback parameter +			$referrer_host  = ''; +			$oauth_callback = false; +			if (!empty($_SESSION['verify_oauth_callback'])) +			{ +				$oauth_callback = $_SESSION['verify_oauth_callback']; +				$ps = parse_url($oauth_callback); +				if (isset($ps['host'])) +				{ +					$referrer_host = $ps['host']; +				} +			} +			 +			if ($authorized) +			{ +				OAuthRequestLogger::addNote('Authorized token "'.$token.'" for user '.$user_id.' with referrer "'.$referrer_host.'"'); +				$store->authorizeConsumerRequestToken($token, $user_id, $referrer_host); +			} +			else +			{ +				OAuthRequestLogger::addNote('Authorization rejected for token "'.$token.'" for user '.$user_id."\nToken has been deleted"); +				$store->deleteConsumerRequestToken($token); +			} +			 +			if (!empty($oauth_callback)) +			{ +				$this->redirect($oauth_callback, array('oauth_token'=>rawurlencode($token))); +			} +		} +		OAuthRequestLogger::flush(); +	} +	 +	 +	/** +	 * Exchange a request token for an access token. +	 * The exchange is only succesful iff the request token has been authorized. +	 *  +	 * Never returns, calls exit() when token is exchanged or when error is returned. +	 */ +	public function accessToken () +	{ +		OAuthRequestLogger::start($this); + +		try +		{ +			$this->verify('request'); + +			$options = array(); +			$ttl     = $this->getParam('xoauth_token_ttl', false); +			if ($ttl) +			{ +				$options['token_ttl'] = $ttl; +			} +			 +			$store  = OAuthStore::instance(); +			$token  = $store->exchangeConsumerRequestForAccessToken($this->getParam('oauth_token', true), $options); +			$result = 'oauth_token='.$this->urlencode($token['token']) +					.'&oauth_token_secret='.$this->urlencode($token['token_secret']); +					 +			if (!empty($token['token_ttl'])) +			{ +				$result .= '&xoauth_token_ttl='.$this->urlencode($token['token_ttl']); +			} +					 +			header('HTTP/1.1 200 OK'); +			header('Content-Length: '.strlen($result)); +			header('Content-Type: application/x-www-form-urlencoded'); + +			echo $result; +		} +		catch (OAuthException $e) +		{ +			header('HTTP/1.1 401 Access Denied'); +			header('Content-Type: text/plain'); + +			echo "OAuth Verification Failed: " . $e->getMessage(); +		} +		 +		OAuthRequestLogger::flush(); +		exit(); +	}	 +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/OAuthStore.php b/mod/oauth_api/vendors/oauth/library/OAuthStore.php new file mode 100644 index 000000000..1841ab5fa --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/OAuthStore.php @@ -0,0 +1,86 @@ +<?php + +/** + * Storage container for the oauth credentials, both server and consumer side. + * This is the factory to select the store you want to use + *  + * @version $Id: OAuthStore.php 49 2008-10-01 09:43:19Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 4:03:30 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__) . '/OAuthException.php'; + +class OAuthStore +{ +	static private $instance = false; + +	/** +	 * Request an instance of the OAuthStore +	 */ +	public static function instance ( $store = 'MySQL', $options = array() ) +	{ +	    if (!OAuthStore::$instance) +	    { +			// Select the store you want to use +			if (strpos($store, '/') === false) +			{ +				$class = 'OAuthStore'.$store; +				$file  = dirname(__FILE__) . '/store/'.$class.'.php'; +			} +			else +			{ +				$file  = $store; +				$store = basename($file, '.php'); +				$class = $store; +			} + +			if (is_file($file)) +			{ +				require_once $file; +				 +				if (class_exists($class)) +				{ +					OAuthStore::$instance = new $class($options); +				} +				else +				{ +					throw new OAuthException('Could not find class '.$class.' in file '.$file); +				} +			} +			else +			{ +				throw new OAuthException('No OAuthStore for '.$store.' (file '.$file.')'); +			} +	    } +	    return OAuthStore::$instance;	 +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/body/OAuthBodyContentDisposition.php b/mod/oauth_api/vendors/oauth/library/body/OAuthBodyContentDisposition.php new file mode 100644 index 000000000..84123b6d0 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/body/OAuthBodyContentDisposition.php @@ -0,0 +1,129 @@ +<?php + +/** + * Add the extra headers for a PUT or POST request with a file. + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +class OAuthBodyContentDisposition +{ +    /** +     * Builds the request string. +     *  +     * The files array can be a combination of the following (either data or file): +     *  +     * file => "path/to/file", filename=, mime=, data= +     * +     * @param array files		(name => filedesc) (not urlencoded) +     * @return array (headers, body) +     */ +    static function encodeBody ( $files ) +    { +    	$headers  	= array(); +		$body		= null; + +		// 1. Add all the files to the post +		if (!empty($files)) +		{ +			foreach ($files as $name => $f) +			{ +				$data     = false; +				$filename = false; + +				if (isset($f['filename'])) +				{ +					$filename = $f['filename']; +				} + +				if (!empty($f['file'])) +				{ +					$data = @file_get_contents($f['file']); +					if ($data === false) +					{ +						throw new OAuthException(sprintf('Could not read the file "%s" for request body', $f['file'])); +					} +					if (empty($filename)) +					{ +						$filename = basename($f['file']); +					} +				} +				else if (isset($f['data'])) +				{ +					$data = $f['data']; +				} +				 +				// When there is data, add it as a request body, otherwise silently skip the upload +				if ($data !== false) +				{ +					if (isset($headers['Content-Disposition'])) +					{ +						throw new OAuthException('Only a single file (or data) allowed in a signed PUT/POST request body.'); +					} + +					if (empty($filename)) +					{ +						$filename = 'untitled'; +					} +					$mime  = !empty($f['mime']) ? $f['mime'] : 'application/octet-stream'; +					 +					$headers['Content-Disposition'] = 'attachment; filename="'.OAuthBodyContentDisposition::encodeParameterName($filename).'"'; +					$headers['Content-Type']		= $mime; + +					$body = $data; +				} +				 +			} + +			// When we have a body, add the content-length +			if (!is_null($body)) +			{ +				$headers['Content-Length'] = strlen($body); +			} +		} +		return array($headers, $body); +	} +	 +	 +	/** +	 * Encode a parameter's name for use in a multipart header. +	 * For now we do a simple filter that removes some unwanted characters. +	 * We might want to implement RFC1522 here.  See http://tools.ietf.org/html/rfc1522 +	 *  +	 * @param string name +	 * @return string +	 */ +	static function encodeParameterName ( $name ) +	{ +		return preg_replace('/[^\x20-\x7f]|"/', '-', $name); +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/body/OAuthBodyMultipartFormdata.php b/mod/oauth_api/vendors/oauth/library/body/OAuthBodyMultipartFormdata.php new file mode 100644 index 000000000..048fdeb63 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/body/OAuthBodyMultipartFormdata.php @@ -0,0 +1,143 @@ +<?php + +/** + * Create the body for a multipart/form-data message. + *  + * @version $Id: OAuthMultipartFormdata.php 6 2008-02-13 12:35:09Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Jan 31, 2008 12:50:05 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +class OAuthBodyMultipartFormdata +{ +    /** +     * Builds the request string. +     *  +     * The files array can be a combination of the following (either data or file): +     *  +     * file => "path/to/file", filename=, mime=, data= +     * +     * @param array params		(name => value) (all names and values should be urlencoded) +     * @param array files		(name => filedesc) (not urlencoded) +     * @return array (headers, body) +     */ +    static function encodeBody ( $params, $files ) +    { +    	$headers  	= array(); +		$body		= ''; +		$boundary	= 'OAuthRequester_'.md5(uniqid('multipart') . microtime()); +		$headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary; + + +		// 1. Add the parameters to the post +		if (!empty($params)) +		{ +			foreach ($params as $name => $value) +			{ +				$body .= '--'.$boundary."\r\n"; +				$body .= 'Content-Disposition: form-data; name="'.OAuthBodyMultipartFormdata::encodeParameterName(rawurldecode($name)).'"'; +				$body .= "\r\n\r\n"; +				$body .= urldecode($value); +				$body .= "\r\n"; +			} +		} +		 +		// 2. Add all the files to the post +		if (!empty($files)) +		{ +			$untitled = 1; +			 +			foreach ($files as $name => $f) +			{ +				$data     = false; +				$filename = false; + +				if (isset($f['filename'])) +				{ +					$filename = $f['filename']; +				} + +				if (!empty($f['file'])) +				{ +					$data = @file_get_contents($f['file']); +					if ($data === false) +					{ +						throw new OAuthException(sprintf('Could not read the file "%s" for form-data part', $f['file'])); +					} +					if (empty($filename)) +					{ +						$filename = basename($f['file']); +					} +				} +				else if (isset($f['data'])) +				{ +					$data = $f['data']; +				} +				 +				// When there is data, add it as a form-data part, otherwise silently skip the upload +				if ($data !== false) +				{ +					if (empty($filename)) +					{ +						$filename = sprintf('untitled-%d', $untitled++); +					} +					$mime  = !empty($f['mime']) ? $f['mime'] : 'application/octet-stream'; +					$body .= '--'.$boundary."\r\n"; +					$body .= 'Content-Disposition: form-data; name="'.OAuthBodyMultipartFormdata::encodeParameterName($name).'"; filename="'.OAuthBodyMultipartFormdata::encodeParameterName($filename).'"'."\r\n"; +					$body .= 'Content-Type: '.$mime; +					$body .= "\r\n\r\n"; +					$body .= $data; +					$body .= "\r\n"; +				} +				 +			} +		} +		$body .= '--'.$boundary."--\r\n"; + +		$headers['Content-Length'] = strlen($body); +		return array($headers, $body); +	} +	 +	 +	/** +	 * Encode a parameter's name for use in a multipart header. +	 * For now we do a simple filter that removes some unwanted characters. +	 * We might want to implement RFC1522 here.  See http://tools.ietf.org/html/rfc1522 +	 *  +	 * @param string name +	 * @return string +	 */ +	static function encodeParameterName ( $name ) +	{ +		return preg_replace('/[^\x20-\x7f]|"/', '-', $name); +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.php b/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.php new file mode 100644 index 000000000..c9cf94997 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.php @@ -0,0 +1,304 @@ +<?php + +/** + * Parse a XRDS discovery description to a simple array format. + *  + * For now a simple parse of the document. Better error checking + * in a later version. + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/* example of use: + +header('content-type: text/plain'); +$file = file_get_contents('../../test/discovery/xrds-magnolia.xrds'); +$xrds = xrds_parse($file); +print_r($xrds); + + */  + +/** + * Parse the xrds file in the argument.  The xrds description must have been  + * fetched via curl or something else. + *  + * TODO: more robust checking, support for more service documents + * TODO: support for URIs to definition instead of local xml:id + *  + * @param string data contents of xrds file + * @exception Exception when the file is in an unknown format + * @return array + */ +function xrds_parse ( $data ) +{ +	$oauth = array(); +	$doc   = @DOMDocument::loadXML($data); +	if ($doc === false) +	{ +		throw new Exception('Error in XML, can\'t load XRDS document'); +	} +	 +	$xpath = new DOMXPath($doc); +	$xpath->registerNamespace('xrds',	'xri://$xrds'); +	$xpath->registerNamespace('xrd',  	'xri://$XRD*($v*2.0)'); +	$xpath->registerNamespace('simple', 'http://xrds-simple.net/core/1.0'); + +	// Yahoo! uses this namespace, with lowercase xrd in it +	$xpath->registerNamespace('xrd2',  	'xri://$xrd*($v*2.0)'); + +	$uris = xrds_oauth_service_uris($xpath); + +	foreach ($uris as $uri) +	{ +		// TODO: support uris referring to service documents outside this one +		if ($uri{0} == '#') +		{ +			$id    = substr($uri, 1); +			$oauth = xrds_xrd_oauth($xpath, $id); +			if (is_array($oauth) && !empty($oauth)) +			{ +				return $oauth; +			} +		} +	} + +	return false; +} + + +/** + * Parse a XRD definition for OAuth and return the uris etc. + *  + * @param XPath xpath + * @param string id + * @return array + */ +function xrds_xrd_oauth ( $xpath, $id ) +{ +	$oauth = array(); +	$xrd   = $xpath->query('//xrds:XRDS/xrd:XRD[@xml:id="'.$id.'"]'); +	if ($xrd->length == 0) +	{ +		// Yahoo! uses another namespace +		$xrd = $xpath->query('//xrds:XRDS/xrd2:XRD[@xml:id="'.$id.'"]'); +	} + +	if ($xrd->length >= 1) +	{ +		$x 		  = $xrd->item(0); +		$services = array(); +		foreach ($x->childNodes as $n) +		{ +			switch ($n->nodeName) +			{ +			case 'Type': +				if ($n->nodeValue != 'xri://$xrds*simple') +				{ +					// Not a simple XRDS document +					return false; +				} +				break; +			case 'Expires': +				$oauth['expires'] = $n->nodeValue; +				break; +			case 'Service': +				list($type,$service) = xrds_xrd_oauth_service($n); +				if ($type) +				{ +					$services[$type][xrds_priority($n)][] = $service; +				} +				break; +			} +		} +		 +		// Flatten the services on priority +		foreach ($services as $type => $service) +		{ +			$oauth[$type] = xrds_priority_flatten($service); +		} +	} +	else +	{ +		$oauth = false; +	} +	return $oauth; +} + + +/** + * Parse a service definition for OAuth in a simple xrd element + *  + * @param DOMElement n + * @return array (type, service desc) + */ +function xrds_xrd_oauth_service ( $n ) +{ +	$service = array( +				'uri'				=> '', +				'signature_method'	=> array(), +				'parameters'		=> array() +				); + +	$type    = false; +	foreach ($n->childNodes as $c) +	{ +		$name  = $c->nodeName; +		$value = $c->nodeValue; +		 +		if ($name == 'URI') +		{ +			$service['uri'] = $value; +		} +		else if ($name == 'Type') +		{ +			if (strncmp($value, 'http://oauth.net/core/1.0/endpoint/', 35) == 0) +			{ +				$type = basename($value); +			} +			else if (strncmp($value, 'http://oauth.net/core/1.0/signature/', 36) == 0) +			{ +				$service['signature_method'][] = basename($value); +			} +			else if (strncmp($value, 'http://oauth.net/core/1.0/parameters/', 37) == 0) +			{ +				$service['parameters'][] = basename($value); +			} +			else if (strncmp($value, 'http://oauth.net/discovery/1.0/consumer-identity/', 49) == 0) +			{ +				$type = 'consumer_identity'; +				$service['method'] = basename($value); +				unset($service['signature_method']); +				unset($service['parameters']); +			} +			else +			{ +				$service['unknown'][] = $value; +			} +		} +		else if ($name == 'LocalID') +		{ +			$service['consumer_key'] = $value; +		} +		else if ($name{0} != '#') +		{ +			$service[strtolower($name)] = $value; +		} +	} +	return array($type, $service); +} + + +/** + * Return the OAuth service uris in order of the priority. + *  + * @param XPath xpath + * @return array + */ +function xrds_oauth_service_uris ( $xpath ) +{ +	$uris	   = array(); +	$xrd_oauth = $xpath->query('//xrds:XRDS/xrd:XRD/xrd:Service/xrd:Type[.=\'http://oauth.net/discovery/1.0\']'); +	if ($xrd_oauth->length > 0) +	{ +		$service = array(); +		foreach ($xrd_oauth as $xo) +		{ +			// Find the URI of the service definition +			$cs = $xo->parentNode->childNodes; +			foreach ($cs as $c) +			{ +				if ($c->nodeName == 'URI') +				{ +					$prio 			  = xrds_priority($xo); +					$service[$prio][] = $c->nodeValue; +				} +			} +		} +		$uris = xrds_priority_flatten($service); +	} +	return $uris; +} + + + +/** + * Flatten an array according to the priority + *  + * @param array  ps buckets per prio + * @return array one dimensional array + */ +function xrds_priority_flatten ( $ps ) +{ +	$prio = array(); +	$null = array(); +	ksort($ps); +	foreach ($ps as $idx => $bucket) +	{ +		if (!empty($bucket)) +		{ +			if ($idx == 'null') +			{ +				$null = $bucket; +			} +			else +			{ +				$prio = array_merge($prio, $bucket); +			} +		} +	} +	$prio = array_merge($prio, $bucket); +	return $prio; +} + + +/** + * Fetch the priority of a element + *  + * @param DOMElement elt + * @return mixed		'null' or int + */ +function xrds_priority ( $elt ) +{ +	if ($elt->hasAttribute('priority')) +	{ +		$prio = $elt->getAttribute('priority'); +		if (is_numeric($prio)) +		{ +			$prio = intval($prio); +		} +	} +	else +	{ +		$prio = 'null'; +	} +	return $prio; +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ +  +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.txt b/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.txt new file mode 100644 index 000000000..fd867ea9f --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/discovery/xrds_parse.txt @@ -0,0 +1,101 @@ +The xrds_parse.php script contains the function: + +	 function xrds_parse ( $data. ) + +$data Contains the contents of a XRDS XML file. +When the data is invalid XML then this will throw an exception. + +After parsing a XRDS definition it will return a datastructure much like the one below. + +Array +( +    [expires] => 2008-04-13T07:34:58Z +    [request] => Array +        ( +            [0] => Array +                ( +                    [uri] => https://ma.gnolia.com/oauth/get_request_token +                    [signature_method] => Array +                        ( +                            [0] => HMAC-SHA1 +                            [1] => RSA-SHA1 +                            [2] => PLAINTEXT +                        ) + +                    [parameters] => Array +                        ( +                            [0] => auth-header +                            [1] => post-body +                            [2] => uri-query +                        ) +                ) +        ) + +    [authorize] => Array +        ( +            [0] => Array +                ( +                    [uri] => http://ma.gnolia.com/oauth/authorize +                    [signature_method] => Array +                        ( +                        ) + +                    [parameters] => Array +                        ( +                            [0] => auth-header +                            [1] => uri-query +                        ) +                ) +        ) + +    [access] => Array +        ( +            [0] => Array +                ( +                    [uri] => https://ma.gnolia.com/oauth/get_access_token +                    [signature_method] => Array +                        ( +                            [0] => HMAC-SHA1 +                            [1] => RSA-SHA1 +                            [2] => PLAINTEXT +                        ) + +                    [parameters] => Array +                        ( +                            [0] => auth-header +                            [1] => post-body +                            [2] => uri-query +                        ) +                ) +        ) + +    [resource] => Array +        ( +            [0] => Array +                ( +                    [uri] =>  +                    [signature_method] => Array +                        ( +                            [0] => HMAC-SHA1 +                            [1] => RSA-SHA1 +                        ) + +                    [parameters] => Array +                        ( +                            [0] => auth-header +                            [1] => post-body +                            [2] => uri-query +                        ) +                ) +        ) + +    [consumer_identity] => Array +        ( +            [0] => Array +                ( +                    [uri] => http://ma.gnolia.com/applications/new +                    [method] => oob +                ) +        ) +) + diff --git a/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod.class.php b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod.class.php new file mode 100644 index 000000000..34ccb428c --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod.class.php @@ -0,0 +1,69 @@ +<?php + +/** + * Interface for OAuth signature methods + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 8, 2008 12:04:35 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +abstract class OAuthSignatureMethod +{ +	/** +	 * Return the name of this signature +	 *  +	 * @return string +	 */ +	abstract public function name(); +	 +	/** +	 * Return the signature for the given request +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @return string   +	 */ +	abstract public function signature ( $request, $base_string, $consumer_secret, $token_secret ); + +	/** +	 * Check if the request signature corresponds to the one calculated for the request. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string	data to be signed, usually the base string, can be a request body +	 * @param string consumer_secret +	 * @param string token_secret +	 * @param string signature		from the request, still urlencoded +	 * @return string +	 */ +	abstract public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ); +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_HMAC_SHA1.php b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_HMAC_SHA1.php new file mode 100644 index 000000000..4bc949c10 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_HMAC_SHA1.php @@ -0,0 +1,115 @@ +<?php + +/** + * OAuth signature implementation using HMAC-SHA1 + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 8, 2008 12:21:19 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +require_once dirname(__FILE__).'/OAuthSignatureMethod.class.php'; + + +class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod +{ +	public function name () +	{ +		return 'HMAC-SHA1'; +	} + + +	/** +	 * Calculate the signature using HMAC-SHA1 +	 * This function is copyright Andy Smith, 2007. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @return string   +	 */ +	function signature ( $request, $base_string, $consumer_secret, $token_secret ) +	{ +		$key = $request->urlencode($consumer_secret).'&'.$request->urlencode($token_secret); +		if (function_exists('hash_hmac')) +		{ +			$signature = base64_encode(hash_hmac("sha1", $base_string, $key, true)); +		} +		else +		{ +		    $blocksize	= 64; +		    $hashfunc	= 'sha1'; +		    if (strlen($key) > $blocksize) +		    { +		        $key = pack('H*', $hashfunc($key)); +		    } +		    $key	= str_pad($key,$blocksize,chr(0x00)); +		    $ipad	= str_repeat(chr(0x36),$blocksize); +		    $opad	= str_repeat(chr(0x5c),$blocksize); +		    $hmac 	= pack( +		                'H*',$hashfunc( +		                    ($key^$opad).pack( +		                        'H*',$hashfunc( +		                            ($key^$ipad).$base_string +		                        ) +		                    ) +		                ) +		            ); +			$signature = base64_encode($hmac); +		} +		return $request->urlencode($signature); +	} + + +	/** +	 * Check if the request signature corresponds to the one calculated for the request. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string	data to be signed, usually the base string, can be a request body +	 * @param string consumer_secret +	 * @param string token_secret +	 * @param string signature		from the request, still urlencoded +	 * @return string +	 */ +	public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ) +	{ +		$a = $request->urldecode($signature); +		$b = $request->urldecode($this->signature($request, $base_string, $consumer_secret, $token_secret)); + +		// We have to compare the decoded values +		$valA  = base64_decode($a); +		$valB  = base64_decode($b); + +		// Crude binary comparison +		return rawurlencode($a) == rawurlencode($b); +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_MD5.php b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_MD5.php new file mode 100644 index 000000000..6f593a47f --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_MD5.php @@ -0,0 +1,95 @@ +<?php + +/** + * OAuth signature implementation using MD5 + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 8, 2008 12:09:43 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__).'/OAuthSignatureMethod.class.php'; + + +class OAuthSignatureMethod_MD5 extends OAuthSignatureMethod +{ +	public function name () +	{ +		return 'MD5'; +	} + + +	/** +	 * Calculate the signature using MD5 +	 * Binary md5 digest, as distinct from PHP's built-in hexdigest. +	 * This function is copyright Andy Smith, 2007. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @return string   +	 */ +	function signature ( $request, $base_string, $consumer_secret, $token_secret ) +	{ +		$s  .= '&'.$request->urlencode($consumer_secret).'&'.$request->urlencode($token_secret); +		$md5 = md5($base_string); +		$bin = ''; +		 +		for ($i = 0; $i < strlen($md5); $i += 2) +		{ +		    $bin .= chr(hexdec($md5{$i+1}) + hexdec($md5{$i}) * 16); +		} +		return $request->urlencode(base64_encode($bin)); +	} + + +	/** +	 * Check if the request signature corresponds to the one calculated for the request. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string	data to be signed, usually the base string, can be a request body +	 * @param string consumer_secret +	 * @param string token_secret +	 * @param string signature		from the request, still urlencoded +	 * @return string +	 */ +	public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ) +	{ +		$a = $request->urldecode($signature); +		$b = $request->urldecode($this->signature($request, $base_string, $consumer_secret, $token_secret)); + +		// We have to compare the decoded values +		$valA  = base64_decode($a); +		$valB  = base64_decode($b); + +		// Crude binary comparison +		return rawurlencode($a) == rawurlencode($b); +	} +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_PLAINTEXT.php b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_PLAINTEXT.php new file mode 100644 index 000000000..92ef30867 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_PLAINTEXT.php @@ -0,0 +1,80 @@ +<?php + +/** + * OAuth signature implementation using PLAINTEXT + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 8, 2008 12:09:43 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__).'/OAuthSignatureMethod.class.php'; + + +class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod +{ +	public function name () +	{ +		return 'PLAINTEXT'; +	} + + +	/** +	 * Calculate the signature using PLAINTEXT +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @return string   +	 */ +	function signature ( $request, $base_string, $consumer_secret, $token_secret ) +	{ +		return $request->urlencode($request->urlencode($consumer_secret).'&'.$request->urlencode($token_secret)); +	} + + +	/** +	 * Check if the request signature corresponds to the one calculated for the request. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string	data to be signed, usually the base string, can be a request body +	 * @param string consumer_secret +	 * @param string token_secret +	 * @param string signature		from the request, still urlencoded +	 * @return string +	 */ +	public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ) +	{ +		$a = $request->urldecode($signature); +		$b = $request->urldecode($this->signature($request, $base_string, $consumer_secret, $token_secret)); + +		return $request->urldecode($a) == $request->urldecode($b); +	} +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_RSA_SHA1.php b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_RSA_SHA1.php new file mode 100644 index 000000000..3bbde7d90 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/signature_method/OAuthSignatureMethod_RSA_SHA1.php @@ -0,0 +1,136 @@ +<?php + +/** + * OAuth signature implementation using PLAINTEXT + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Sep 8, 2008 12:00:14 PM + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod +{ +	public function name()  +	{ +		return 'RSA-SHA1'; +	} +	 + +	/** +	 * Fetch the public CERT key for the signature +	 *  +	 * @param OAuthRequest request +	 * @return string public key +	 */ +	protected function fetch_public_cert ( $request ) +	{ +		// not implemented yet, ideas are: +		// (1) do a lookup in a table of trusted certs keyed off of consumer +		// (2) fetch via http using a url provided by the requester +		// (3) some sort of specific discovery code based on request +		// +		// either way should return a string representation of the certificate +		throw OAuthException("OAuthSignatureMethod_RSA_SHA1::fetch_public_cert not implemented"); +	} +	 +	 +	/** +	 * Fetch the private CERT key for the signature +	 *  +	 * @param OAuthRequest request +	 * @return string private key +	 */ +	protected function fetch_private_cert ( $request ) +	{ +		// not implemented yet, ideas are: +		// (1) do a lookup in a table of trusted certs keyed off of consumer +		// +		// either way should return a string representation of the certificate +		throw OAuthException("OAuthSignatureMethod_RSA_SHA1::fetch_private_cert not implemented"); +	} + + +	/** +	 * Calculate the signature using RSA-SHA1 +	 * This function is copyright Andy Smith, 2008. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @return string   +	 */ +	public function signature ( $request, $base_string, $consumer_secret, $token_secret ) +	{ +		// Fetch the private key cert based on the request +		$cert = $this->fetch_private_cert($request); +		 +		// Pull the private key ID from the certificate +		$privatekeyid = openssl_get_privatekey($cert); +		 +		// Sign using the key +		$sig = false; +		$ok  = openssl_sign($base_string, $sig, $privatekeyid);    +		 +		// Release the key resource +		openssl_free_key($privatekeyid); +		   +		return $request->urlencode(base64_encode($sig)); +	} +	 + +	/** +	 * Check if the request signature is the same as the one calculated for the request. +	 *  +	 * @param OAuthRequest request +	 * @param string base_string +	 * @param string consumer_secret +	 * @param string token_secret +	 * @param string signature +	 * @return string   +	 */ +	public function verify ( $request, $base_string, $consumer_secret, $token_secret, $signature ) +	{ +		$decoded_sig = base64_decode($request->urldecode($signature)); +		   +		// Fetch the public key cert based on the request +		$cert = $this->fetch_public_cert($request); +		 +		// Pull the public key ID from the certificate +		$publickeyid = openssl_get_publickey($cert); +		 +		// Check the computed signature against the one passed in the query +		$ok = openssl_verify($base_string, $decoded_sig, $publickeyid);    +		 +		// Release the key resource +		openssl_free_key($publickeyid); +		return $ok == 1; +	} + +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAbstract.class.php b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAbstract.class.php new file mode 100644 index 000000000..e7cca981a --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAbstract.class.php @@ -0,0 +1,149 @@ +<?php + +/** + * Abstract base class for OAuthStore implementations + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +abstract class OAuthStoreAbstract +{ +	abstract public function getSecretsForVerify ( $consumer_key, $token, $token_type = 'access' ); +	abstract public function getSecretsForSignature ( $uri, $user_id ); +	abstract public function getServerTokenSecrets ( $consumer_key, $token, $token_type, $user_id, $name = '' ); +	abstract public function addServerToken ( $consumer_key, $token_type, $token, $token_secret, $user_id, $options = array() ); + +	abstract public function deleteServer ( $consumer_key, $user_id, $user_is_admin = false ); +	abstract public function getServer( $consumer_key, $user_id, $user_is_admin = false ); +	abstract public function getServerForUri ( $uri, $user_id ); +	abstract public function listServerTokens ( $user_id ); +	abstract public function countServerTokens ( $consumer_key ); +	abstract public function getServerToken ( $consumer_key, $token, $user_id ); +	abstract public function deleteServerToken ( $consumer_key, $token, $user_id, $user_is_admin = false ); +	abstract public function listServers ( $q = '', $user_id ); +	abstract public function updateServer ( $server, $user_id, $user_is_admin = false ); + +	abstract public function updateConsumer ( $consumer, $user_id, $user_is_admin = false ); +	abstract public function deleteConsumer ( $consumer_key, $user_id, $user_is_admin = false ); +	abstract public function getConsumer ( $consumer_key, $user_id, $user_is_admin = false ); +	abstract public function getConsumerStatic (); + +	abstract public function addConsumerRequestToken ( $consumer_key, $options = array() ); +	abstract public function getConsumerRequestToken ( $token ); +	abstract public function deleteConsumerRequestToken ( $token ); +	abstract public function authorizeConsumerRequestToken ( $token, $user_id, $referrer_host = '' ); +	abstract public function countConsumerAccessTokens ( $consumer_key ); +	abstract public function exchangeConsumerRequestForAccessToken ( $token, $options = array() ); +	abstract public function getConsumerAccessToken ( $token, $user_id ); +	abstract public function deleteConsumerAccessToken ( $token, $user_id, $user_is_admin = false ); +	abstract public function setConsumerAccessTokenTtl ( $token, $ttl ); +	 +	abstract public function listConsumers ( $user_id ); +	abstract public function listConsumerTokens ( $user_id ); + +	abstract public function checkServerNonce ( $consumer_key, $token, $timestamp, $nonce ); +	 +	abstract public function addLog ( $keys, $received, $sent, $base_string, $notes, $user_id = null ); +	abstract public function listLog ( $options, $user_id ); +	 +	abstract public function install ();	 +	 +	/** +	 * Fetch the current static consumer key for this site, create it when it was not found. +	 * The consumer secret for the consumer key is always empty. +	 *  +	 * @return string	consumer key  +	 */ +	 +	 +	/* ** Some handy utility functions ** */ +	 +	/** +	 * Generate a unique key +	 *  +	 * @param boolean unique	force the key to be unique +	 * @return string +	 */ +	public function generateKey ( $unique = false ) +	{ +		$key = md5(uniqid(rand(), true)); +		if ($unique) +		{ +			list($usec,$sec) = explode(' ',microtime()); +			$key .= dechex($usec).dechex($sec); +		} +		return $key; +	} + +	/** +	 * Check to see if a string is valid utf8 +	 *  +	 * @param string $s +	 * @return boolean +	 */ +	protected function isUTF8 ( $s ) +	{ +		return preg_match('%(?: +	       [\xC2-\xDF][\x80-\xBF]              # non-overlong 2-byte +	       |\xE0[\xA0-\xBF][\x80-\xBF]         # excluding overlongs +	       |[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte +	       |\xED[\x80-\x9F][\x80-\xBF]         # excluding surrogates +	       |\xF0[\x90-\xBF][\x80-\xBF]{2}      # planes 1-3 +	       |[\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15 +	       |\xF4[\x80-\x8F][\x80-\xBF]{2}      # plane 16 +	       )+%xs', $s); +	} +	 +	 +	/** +	 * Make a string utf8, replacing all non-utf8 chars with a '.' +	 *  +	 * @param string +	 * @return string +	 */ +	protected function makeUTF8 ( $s ) +	{ +		if (function_exists('iconv')) +		{ +			do +			{ +				$ok   = true; +				$text = @iconv('UTF-8', 'UTF-8//TRANSLIT', $s); +				if (strlen($text) != strlen($s)) +				{ +					// Remove the offending character... +					$s  = $text . '.' . substr($s, strlen($text) + 1); +					$ok = false; +				} +			} +			while (!$ok); +		} +		return $s; +	} +	 +} + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAnyMeta.php b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAnyMeta.php new file mode 100644 index 000000000..9c971733f --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreAnyMeta.php @@ -0,0 +1,265 @@ +<?php + +/** + * Storage container for the oauth credentials, both server and consumer side. + * This file can only be used in conjunction with anyMeta. + *  + * @version $Id: OAuthStoreAnyMeta.php 49 2008-10-01 09:43:19Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 4:03:30 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__) . '/../../../../core/inc/any_database.inc.php'; +require_once dirname(__FILE__) . '/OAuthStoreMySQL.php'; + + +class OAuthStoreAnymeta extends OAuthStoreMySQL +{ +	/** +	 * Construct the OAuthStoreAnymeta +	 *  +	 * @param array options +	 */ +	function __construct ( $options = array() ) +	{ +		parent::__construct(array('conn' => any_db_conn())); +	} + + +	/** +	 * Add an entry to the log table +	 *  +	 * @param array keys (osr_consumer_key, ost_token, ocr_consumer_key, oct_token) +	 * @param string received +	 * @param string sent +	 * @param string base_string +	 * @param string notes +	 * @param int (optional) user_id +	 */ +	public function addLog ( $keys, $received, $sent, $base_string, $notes, $user_id = null ) +	{ +		if (is_null($user_id) && isset($GLOBALS['any_auth'])) +		{ +			$user_id = $GLOBALS['any_auth']->getUserId(); +		} +		parent::addLog($keys, $received, $sent, $base_string, $notes, $user_id); +	} +	 +	 +	/** +	 * Get a page of entries from the log.  Returns the last 100 records +	 * matching the options given. +	 *  +	 * @param array options +	 * @param int user_id	current user +	 * @return array log records +	 */ +	public function listLog ( $options, $user_id ) +	{ +		$where = array(); +		$args  = array(); +		if (empty($options)) +		{ +			$where[] = 'olg_usa_id_ref = %d'; +			$args[]  = $user_id; +		} +		else +		{ +			foreach ($options as $option => $value) +			{ +				if (strlen($value) > 0) +				{ +					switch ($option) +					{ +					case 'osr_consumer_key': +					case 'ocr_consumer_key': +					case 'ost_token': +					case 'oct_token': +						$where[] = 'olg_'.$option.' = \'%s\''; +						$args[]  = $value;	 +						break;				 +					} +				} +			} +			 +			$where[] = '(olg_usa_id_ref IS NULL OR olg_usa_id_ref = %d)'; +			$args[]  = $user_id; +		} + +		$rs = any_db_query_all_assoc(' +					SELECT olg_id, +							olg_osr_consumer_key 	AS osr_consumer_key, +							olg_ost_token			AS ost_token, +							olg_ocr_consumer_key	AS ocr_consumer_key, +							olg_oct_token			AS oct_token, +							olg_usa_id_ref			AS user_id, +							olg_received			AS received, +							olg_sent				AS sent, +							olg_base_string			AS base_string, +							olg_notes				AS notes, +							olg_timestamp			AS timestamp, +							INET_NTOA(olg_remote_ip) AS remote_ip +					FROM oauth_log +					WHERE '.implode(' AND ', $where).' +					ORDER BY olg_id DESC +					LIMIT 0,100', $args); + +		return $rs; +	} + + + +	/** +	 * Initialise the database +	 */ +	public function install () +	{ +		parent::install(); + +		any_db_query("ALTER TABLE oauth_consumer_registry MODIFY ocr_usa_id_ref int(11) unsigned"); +		any_db_query("ALTER TABLE oauth_consumer_token    MODIFY oct_usa_id_ref int(11) unsigned not null"); +		any_db_query("ALTER TABLE oauth_server_registry   MODIFY osr_usa_id_ref int(11) unsigned"); +		any_db_query("ALTER TABLE oauth_server_token      MODIFY ost_usa_id_ref int(11) unsigned not null"); +		any_db_query("ALTER TABLE oauth_log               MODIFY olg_usa_id_ref int(11) unsigned"); + +		any_db_alter_add_fk('oauth_consumer_registry', 'ocr_usa_id_ref', 'any_user_auth(usa_id_ref)', 'on update cascade on delete set null'); +		any_db_alter_add_fk('oauth_consumer_token',    'oct_usa_id_ref', 'any_user_auth(usa_id_ref)', 'on update cascade on delete cascade'); +		any_db_alter_add_fk('oauth_server_registry',   'osr_usa_id_ref', 'any_user_auth(usa_id_ref)', 'on update cascade on delete set null'); +		any_db_alter_add_fk('oauth_server_token',      'ost_usa_id_ref', 'any_user_auth(usa_id_ref)', 'on update cascade on delete cascade'); +		any_db_alter_add_fk('oauth_log',               'olg_usa_id_ref', 'any_user_auth(usa_id_ref)', 'on update cascade on delete cascade'); +	} + +	 +	 +	/** Some simple helper functions for querying the mysql db **/ + +	/** +	 * Perform a query, ignore the results +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 */ +	protected function query ( $sql ) +	{ +		list($sql, $args) = $this->sql_args(func_get_args()); +		any_db_query($sql, $args); +	} +	 + +	/** +	 * Perform a query, ignore the results +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_all_assoc ( $sql ) +	{ +		list($sql, $args) = $this->sql_args(func_get_args()); +		return any_db_query_all_assoc($sql, $args); +	} +	 +	 +	/** +	 * Perform a query, return the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_row_assoc ( $sql ) +	{ +		list($sql, $args) = $this->sql_args(func_get_args()); +		return any_db_query_row_assoc($sql, $args); +	} + +	 +	/** +	 * Perform a query, return the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_row ( $sql ) +	{ +		list($sql, $args) = $this->sql_args(func_get_args()); +		return any_db_query_row($sql, $args); +	} +	 +		 +	/** +	 * Perform a query, return the first column of the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return mixed +	 */ +	protected function query_one ( $sql ) +	{ +		list($sql, $args) = $this->sql_args(func_get_args()); +		return any_db_query_one($sql, $args); +	} +	 +	 +	/** +	 * Return the number of rows affected in the last query +	 *  +	 * @return int +	 */ +	protected function query_affected_rows () +	{ +		return any_db_affected_rows(); +	} + + +	/** +	 * Return the id of the last inserted row +	 *  +	 * @return int +	 */ +	protected function query_insert_id () +	{ +		return any_db_insert_id(); +	} +	 +	 +	private function sql_args ( $args ) +	{ +		$sql = array_shift($args); +		if (count($args) == 1 && is_array($args[0])) +		{ +			$args = $args[0]; +		} +		return array($sql, $args); +	} + +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/store/OAuthStoreMySQL.php b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreMySQL.php new file mode 100644 index 000000000..a1b04c5c8 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/store/OAuthStoreMySQL.php @@ -0,0 +1,1879 @@ +<?php + +/** + * Storage container for the oauth credentials, both server and consumer side. + * Based on MySQL + *  + * @version $Id: OAuthStoreMySQL.php 64 2009-08-16 19:37:00Z marcw@pobox.com $ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 16, 2007 4:03:30 PM + *  + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +require_once dirname(__FILE__) . '/OAuthStoreAbstract.class.php'; + + +class OAuthStoreMySQL extends OAuthStoreAbstract +{ +	/** +	 * The MySQL connection  +	 */ +	protected $conn; + +	/** +	 * Maximum delta a timestamp may be off from a previous timestamp. +	 * Allows multiple consumers with some clock skew to work with the same token. +	 * Unit is seconds, default max skew is 10 minutes. +	 */ +	protected $max_timestamp_skew = 600; + +	/** +	 * Default ttl for request tokens +	 */ +	protected $max_request_token_ttl = 3600; +	 + +	/** +	 * Construct the OAuthStoreMySQL. +	 * In the options you have to supply either: +	 * - server, username, password and database (for a mysql_connect) +	 * - conn (for the connection to be used) +	 *  +	 * @param array options +	 */ +	function __construct ( $options = array() ) +	{ +		if (isset($options['conn'])) +		{ +			$this->conn = $options['conn']; +		} +		else +		{ +			if (isset($options['server'])) +			{ +				$server   = $options['server']; +				$username = $options['username']; +				 +				if (isset($options['password'])) +				{ +					$this->conn = mysql_connect($server, $username, $options['password']); +				} +				else +				{ +					$this->conn = mysql_connect($server, $username); +				} +			} +			else +			{ +				// Try the default mysql connect +				$this->conn = mysql_connect(); +			} + +			if ($this->conn === false) +			{ +				throw new OAuthException('Could not connect to MySQL database: ' . mysql_error()); +			} + +			if (isset($options['database'])) +			{ +				if (!mysql_select_db($options['database'], $this->conn)) +				{ +					$this->sql_errcheck(); +				} +			} +			$this->query('set character set utf8'); +		} +	} + + +	/** +	 * Find stored credentials for the consumer key and token. Used by an OAuth server +	 * when verifying an OAuth request. +	 *  +	 * @param string consumer_key +	 * @param string token +	 * @param string token_type		false, 'request' or 'access' +	 * @exception OAuthException when no secrets where found +	 * @return array	assoc (consumer_secret, token_secret, osr_id, ost_id, user_id) +	 */ +	public function getSecretsForVerify ( $consumer_key, $token, $token_type = 'access' ) +	{ +		if ($token_type === false) +		{ +			$rs = $this->query_row_assoc(' +						SELECT	osr_id,  +								osr_consumer_key		as consumer_key, +								osr_consumer_secret		as consumer_secret +						FROM oauth_server_registry +						WHERE osr_consumer_key	= \'%s\' +						  AND osr_enabled		= 1 +						',  +						$consumer_key); +			 +			if ($rs) +			{ +				$rs['token'] 		= false; +				$rs['token_secret']	= false; +				$rs['user_id']		= false; +				$rs['ost_id']		= false; +			} +		} +		else +		{ +			$rs = $this->query_row_assoc(' +						SELECT	osr_id,  +								ost_id, +								ost_usa_id_ref			as user_id, +								osr_consumer_key		as consumer_key, +								osr_consumer_secret		as consumer_secret, +								ost_token				as token, +								ost_token_secret		as token_secret +						FROM oauth_server_registry +								JOIN oauth_server_token +								ON ost_osr_id_ref = osr_id +						WHERE ost_token_type	= \'%s\' +						  AND osr_consumer_key	= \'%s\' +						  AND ost_token			= \'%s\' +					 	  AND osr_enabled		= 1 +						  AND ost_token_ttl     >= NOW() +						', +						$token_type, $consumer_key, $token); +		} +		 +		if (empty($rs)) +		{ +			throw new OAuthException('The consumer_key "'.$consumer_key.'" token "'.$token.'" combination does not exist or is not enabled.'); +		} +		return $rs; +	} + + +	/** +	 * Find the server details for signing a request, always looks for an access token. +	 * The returned credentials depend on which local user is making the request. +	 *  +	 * The consumer_key must belong to the user or be public (user id is null) +	 *  +	 * For signing we need all of the following: +	 *  +	 * consumer_key			consumer key associated with the server +	 * consumer_secret		consumer secret associated with this server +	 * token				access token associated with this server +	 * token_secret			secret for the access token +	 * signature_methods	signing methods supported by the server (array) +	 *  +	 * @todo filter on token type (we should know how and with what to sign this request, and there might be old access tokens) +	 * @param string uri	uri of the server +	 * @param int user_id	id of the logged on user +	 * @param string name	(optional) name of the token (case sensitive) +	 * @exception OAuthException when no credentials found +	 * @return array +	 */ +	public function getSecretsForSignature ( $uri, $user_id, $name = '' ) +	{ +		// Find a consumer key and token for the given uri +		$ps		= parse_url($uri); +		$host	= isset($ps['host']) ? $ps['host'] : 'localhost'; +		$path	= isset($ps['path']) ? $ps['path'] : ''; +		 +		if (empty($path) || substr($path, -1) != '/') +		{ +			$path .= '/'; +		} + +		// The owner of the consumer_key is either the user or nobody (public consumer key) +		$secrets = $this->query_row_assoc(' +					SELECT	ocr_consumer_key		as consumer_key, +							ocr_consumer_secret		as consumer_secret, +							oct_token				as token, +							oct_token_secret		as token_secret, +							ocr_signature_methods	as signature_methods +					FROM oauth_consumer_registry +						JOIN oauth_consumer_token ON oct_ocr_id_ref = ocr_id +					WHERE ocr_server_uri_host = \'%s\' +					  AND ocr_server_uri_path = LEFT(\'%s\', LENGTH(ocr_server_uri_path)) +					  AND (ocr_usa_id_ref = %s OR ocr_usa_id_ref IS NULL) +					  AND oct_usa_id_ref	  = %d +					  AND oct_token_type      = \'access\' +					  AND oct_name			  = \'%s\' +					  AND oct_token_ttl       >= NOW() +					ORDER BY ocr_usa_id_ref DESC, ocr_consumer_secret DESC, LENGTH(ocr_server_uri_path) DESC +					LIMIT 0,1 +					', $host, $path, $user_id, $user_id, $name +					); +		 +		if (empty($secrets)) +		{ +			throw new OAuthException('No server tokens available for '.$uri); +		} +		$secrets['signature_methods'] = explode(',', $secrets['signature_methods']); +		return $secrets; +	} + + +	/** +	 * Get the token and token secret we obtained from a server. +	 *  +	 * @param string	consumer_key +	 * @param string 	token +	 * @param string	token_type +	 * @param int		user_id			the user owning the token +	 * @param string	name			optional name for a named token +	 * @exception OAuthException when no credentials found +	 * @return array +	 */ +	public function getServerTokenSecrets ( $consumer_key, $token, $token_type, $user_id, $name = '' ) +	{ +		if ($token_type != 'request' && $token_type != 'access') +		{ +			throw new OAuthException('Unkown token type "'.$token_type.'", must be either "request" or "access"'); +		} + +		// Take the most recent token of the given type +		$r = $this->query_row_assoc(' +					SELECT	ocr_consumer_key		as consumer_key, +							ocr_consumer_secret		as consumer_secret, +							oct_token				as token, +							oct_token_secret		as token_secret, +							oct_name				as token_name, +							ocr_signature_methods	as signature_methods, +							ocr_server_uri			as server_uri, +							ocr_request_token_uri	as request_token_uri, +							ocr_authorize_uri		as authorize_uri, +							ocr_access_token_uri	as access_token_uri, +							IF(oct_token_ttl >= \'9999-12-31\', NULL, UNIX_TIMESTAMP(oct_token_ttl) - UNIX_TIMESTAMP(NOW())) as token_ttl +					FROM oauth_consumer_registry +							JOIN oauth_consumer_token +							ON oct_ocr_id_ref = ocr_id +					WHERE ocr_consumer_key = \'%s\' +					  AND oct_token_type   = \'%s\' +					  AND oct_token        = \'%s\' +					  AND oct_usa_id_ref   = %d +					  AND oct_token_ttl    >= NOW() +					', $consumer_key, $token_type, $token, $user_id +					); +					 +		if (empty($r)) +		{ +			throw new OAuthException('Could not find a "'.$token_type.'" token for consumer "'.$consumer_key.'" and user '.$user_id); +		} +		if (isset($r['signature_methods']) && !empty($r['signature_methods'])) +		{ +			$r['signature_methods'] = explode(',',$r['signature_methods']); +		} +		else +		{ +			$r['signature_methods'] = array(); +		} +		return $r;		 +	} + + +	/** +	 * Add a request token we obtained from a server. +	 *  +	 * @todo remove old tokens for this user and this ocr_id +	 * @param string consumer_key	key of the server in the consumer registry +	 * @param string token_type		one of 'request' or 'access' +	 * @param string token +	 * @param string token_secret +	 * @param int 	 user_id			the user owning the token +	 * @param array  options			extra options, name and token_ttl +	 * @exception OAuthException when server is not known +	 * @exception OAuthException when we received a duplicate token +	 */ +	public function addServerToken ( $consumer_key, $token_type, $token, $token_secret, $user_id, $options = array() ) +	{ +		if ($token_type != 'request' && $token_type != 'access') +		{ +			throw new OAuthException('Unknown token type "'.$token_type.'", must be either "request" or "access"'); +		} + +		// Maximum time to live for this token +		if (isset($options['token_ttl']) && is_numeric($options['token_ttl'])) +		{ +			$ttl = 'DATE_ADD(NOW(), INTERVAL '.intval($options['token_ttl']).' SECOND)'; +		} +		else if ($token == 'request') +		{ +			$ttl = 'DATE_ADD(NOW(), INTERVAL '.$this->max_request_token_ttl.' SECOND)'; +		} +		else +		{ +			$ttl = "'9999-12-31'"; +		} +		 +		$ocr_id = $this->query_one(' +					SELECT ocr_id +					FROM oauth_consumer_registry +					WHERE ocr_consumer_key = \'%s\' +					', $consumer_key); +					 +		if (empty($ocr_id)) +		{ +			throw new OAuthException('No server associated with consumer_key "'.$consumer_key.'"'); +		} +		 +		// Named tokens, unique per user/consumer key +		if (isset($options['name']) && $options['name'] != '') +		{ +			$name = $options['name']; +		} +		else +		{ +			$name = ''; +		} + +		// Delete any old tokens with the same type and name for this user/server combination +		$this->query(' +					DELETE FROM oauth_consumer_token +					WHERE oct_ocr_id_ref = %d +					  AND oct_usa_id_ref = %d +					  AND oct_token_type = LOWER(\'%s\') +					  AND oct_name       = \'%s\' +					', +					$ocr_id, +					$user_id, +					$token_type, +					$name); + +		// Insert the new token +		$this->query(' +					INSERT IGNORE INTO oauth_consumer_token +					SET oct_ocr_id_ref	= %d, +						oct_usa_id_ref  = %d, +						oct_name		= \'%s\', +						oct_token		= \'%s\', +						oct_token_secret= \'%s\', +						oct_token_type	= LOWER(\'%s\'), +						oct_timestamp	= NOW(), +						oct_token_ttl	= '.$ttl.' +					', +					$ocr_id, +					$user_id, +					$name, +					$token, +					$token_secret, +					$token_type); +		 +		if (!$this->query_affected_rows()) +		{ +			throw new OAuthException('Received duplicate token "'.$token.'" for the same consumer_key "'.$consumer_key.'"'); +		} +	} + + +	/** +	 * Delete a server key.  This removes access to that site. +	 *  +	 * @param string consumer_key +	 * @param int user_id	user registering this server +	 * @param boolean user_is_admin +	 */ +	public function deleteServer ( $consumer_key, $user_id, $user_is_admin = false ) +	{ +		if ($user_is_admin) +		{ +			$this->query(' +					DELETE FROM oauth_consumer_registry +					WHERE ocr_consumer_key = \'%s\' +					  AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL) +					', $consumer_key, $user_id); +		} +		else +		{ +			$this->query(' +					DELETE FROM oauth_consumer_registry +					WHERE ocr_consumer_key = \'%s\' +					  AND ocr_usa_id_ref   = %d +					', $consumer_key, $user_id); +		} +	} +	 +	 +	/** +	 * Get a server from the consumer registry using the consumer key +	 *  +	 * @param string consumer_key +	 * @param int user_id +	 * @param boolean user_is_admin (optional) +	 * @exception OAuthException when server is not found +	 * @return array +	 */	 +	public function getServer ( $consumer_key, $user_id, $user_is_admin = false ) +	{ +		$r = $this->query_row_assoc(' +				SELECT	ocr_id					as id, +						ocr_usa_id_ref			as user_id, +						ocr_consumer_key 		as consumer_key, +						ocr_consumer_secret 	as consumer_secret, +						ocr_signature_methods	as signature_methods, +						ocr_server_uri			as server_uri, +						ocr_request_token_uri	as request_token_uri, +						ocr_authorize_uri		as authorize_uri, +						ocr_access_token_uri	as access_token_uri +				FROM oauth_consumer_registry +				WHERE ocr_consumer_key = \'%s\' +				  AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL) +				',	$consumer_key, $user_id); +		 +		if (empty($r)) +		{ +			throw new OAuthException('No server with consumer_key "'.$consumer_key.'" has been registered (for this user)'); +		} +			 +		if (isset($r['signature_methods']) && !empty($r['signature_methods'])) +		{ +			$r['signature_methods'] = explode(',',$r['signature_methods']); +		} +		else +		{ +			$r['signature_methods'] = array(); +		} +		return $r; +	} + + + +	/** +	 * Find the server details that might be used for a request +	 *  +	 * The consumer_key must belong to the user or be public (user id is null) +	 *  +	 * @param string uri	uri of the server +	 * @param int user_id	id of the logged on user +	 * @exception OAuthException when no credentials found +	 * @return array +	 */ +	public function getServerForUri ( $uri, $user_id ) +	{ +		// Find a consumer key and token for the given uri +		$ps		= parse_url($uri); +		$host	= isset($ps['host']) ? $ps['host'] : 'localhost'; +		$path	= isset($ps['path']) ? $ps['path'] : ''; +		 +		if (empty($path) || substr($path, -1) != '/') +		{ +			$path .= '/'; +		} + +		// The owner of the consumer_key is either the user or nobody (public consumer key) +		$server = $this->query_row_assoc(' +					SELECT	ocr_id					as id, +							ocr_usa_id_ref			as user_id, +							ocr_consumer_key		as consumer_key, +							ocr_consumer_secret		as consumer_secret, +							ocr_signature_methods	as signature_methods, +							ocr_server_uri			as server_uri, +							ocr_request_token_uri	as request_token_uri, +							ocr_authorize_uri		as authorize_uri, +							ocr_access_token_uri	as access_token_uri +					FROM oauth_consumer_registry +					WHERE ocr_server_uri_host = \'%s\' +					  AND ocr_server_uri_path = LEFT(\'%s\', LENGTH(ocr_server_uri_path)) +					  AND (ocr_usa_id_ref = %s OR ocr_usa_id_ref IS NULL) +					ORDER BY ocr_usa_id_ref DESC, consumer_secret DESC, LENGTH(ocr_server_uri_path) DESC +					LIMIT 0,1 +					', $host, $path, $user_id +					); +		 +		if (empty($server)) +		{ +			throw new OAuthException('No server available for '.$uri); +		} +		$server['signature_methods'] = explode(',', $server['signature_methods']); +		return $server; +	} + + +	/** +	 * Get a list of all server token this user has access to. +	 *  +	 * @param int usr_id +	 * @return array +	 */ +	public function listServerTokens ( $user_id ) +	{ +		$ts = $this->query_all_assoc(' +					SELECT	ocr_consumer_key		as consumer_key, +							ocr_consumer_secret		as consumer_secret, +							oct_id					as token_id, +							oct_token				as token, +							oct_token_secret		as token_secret, +							oct_usa_id_ref			as user_id, +							ocr_signature_methods	as signature_methods, +							ocr_server_uri			as server_uri, +							ocr_server_uri_host		as server_uri_host, +							ocr_server_uri_path		as server_uri_path, +							ocr_request_token_uri	as request_token_uri, +							ocr_authorize_uri		as authorize_uri, +							ocr_access_token_uri	as access_token_uri, +							oct_timestamp			as timestamp +					FROM oauth_consumer_registry +							JOIN oauth_consumer_token +							ON oct_ocr_id_ref = ocr_id +					WHERE oct_usa_id_ref = %d +					  AND oct_token_type = \'access\' +					  AND oct_token_ttl  >= NOW() +					ORDER BY ocr_server_uri_host, ocr_server_uri_path +					', $user_id); +		return $ts; +	} + + +	/** +	 * Count how many tokens we have for the given server +	 *  +	 * @param string consumer_key +	 * @return int +	 */ +	public function countServerTokens ( $consumer_key ) +	{ +		$count = $this->query_one(' +					SELECT COUNT(oct_id) +					FROM oauth_consumer_token +							JOIN oauth_consumer_registry +							ON oct_ocr_id_ref = ocr_id +					WHERE oct_token_type   = \'access\' +					  AND ocr_consumer_key = \'%s\' +					  AND oct_token_ttl    >= NOW() +					', $consumer_key); +		 +		return $count; +	} + + +	/** +	 * Get a specific server token for the given user +	 *  +	 * @param string consumer_key +	 * @param string token +	 * @param int user_id +	 * @exception OAuthException when no such token found +	 * @return array +	 */ +	public function getServerToken ( $consumer_key, $token, $user_id ) +	{ +		$ts = $this->query_row_assoc(' +					SELECT	ocr_consumer_key		as consumer_key, +							ocr_consumer_secret		as consumer_secret, +							oct_token				as token, +							oct_token_secret		as token_secret, +							oct_usa_id_ref			as usr_id, +							ocr_signature_methods	as signature_methods, +							ocr_server_uri			as server_uri, +							ocr_server_uri_host		as server_uri_host, +							ocr_server_uri_path		as server_uri_path, +							ocr_request_token_uri	as request_token_uri, +							ocr_authorize_uri		as authorize_uri, +							ocr_access_token_uri	as access_token_uri, +							oct_timestamp			as timestamp +					FROM oauth_consumer_registry +							JOIN oauth_consumer_token +							ON oct_ocr_id_ref = ocr_id +					WHERE ocr_consumer_key = \'%s\' +					  AND oct_usa_id_ref   = %d +					  AND oct_token_type   = \'access\' +					  AND oct_token        = \'%s\' +					  AND oct_token_ttl    >= NOW() +					', $consumer_key, $user_id, $token); +		 +		if (empty($ts)) +		{ +			throw new OAuthException('No such consumer key ('.$consumer_key.') and token ('.$token.') combination for user "'.$user_id.'"'); +		} +		return $ts; +	} + + +	/** +	 * Delete a token we obtained from a server. +	 *  +	 * @param string consumer_key +	 * @param string token +	 * @param int user_id +	 * @param boolean user_is_admin +	 */ +	public function deleteServerToken ( $consumer_key, $token, $user_id, $user_is_admin = false ) +	{ +		if ($user_is_admin) +		{ +			$this->query(' +				DELETE oauth_consumer_token  +				FROM oauth_consumer_token +						JOIN oauth_consumer_registry +						ON oct_ocr_id_ref = ocr_id +				WHERE ocr_consumer_key	= \'%s\' +				  AND oct_token			= \'%s\' +				', $consumer_key, $token); +		} +		else +		{ +			$this->query(' +				DELETE oauth_consumer_token  +				FROM oauth_consumer_token +						JOIN oauth_consumer_registry +						ON oct_ocr_id_ref = ocr_id +				WHERE ocr_consumer_key	= \'%s\' +				  AND oct_token			= \'%s\' +				  AND oct_usa_id_ref	= %d +				', $consumer_key, $token, $user_id); +		} +	} + + +	/** +	 * Set the ttl of a server access token.  This is done when the +	 * server receives a valid request with a xoauth_token_ttl parameter in it. +	 *  +	 * @param string consumer_key +	 * @param string token +	 * @param int token_ttl +	 */ +	public function setServerTokenTtl ( $consumer_key, $token, $token_ttl ) +	{ +		if ($token_ttl <= 0) +		{ +			// Immediate delete when the token is past its ttl +			$this->deleteServerToken($consumer_key, $token, 0, true); +		} +		else +		{ +			// Set maximum time to live for this token +			$this->query(' +						UPDATE oauth_consumer_token, oauth_consumer_registry +						SET ost_token_ttl = DATE_ADD(NOW(), INTERVAL %d SECOND) +						WHERE ocr_consumer_key	= \'%s\' +						  AND oct_ocr_id_ref    = ocr_id +						  AND oct_token 	    = \'%s\' +						', $token_ttl, $consumer_key, $token); +		} +	} + + +	/** +	 * Get a list of all consumers from the consumer registry. +	 * The consumer keys belong to the user or are public (user id is null) +	 *  +	 * @param string q	query term +	 * @param int user_id +	 * @return array +	 */	 +	public function listServers ( $q = '', $user_id ) +	{ +		$q    = trim(str_replace('%', '', $q)); +		$args = array(); + +		if (!empty($q)) +		{ +			$where = ' WHERE (	ocr_consumer_key like \'%%%s%%\' +						  	 OR ocr_server_uri like \'%%%s%%\' +						  	 OR ocr_server_uri_host like \'%%%s%%\' +						  	 OR ocr_server_uri_path like \'%%%s%%\') +						 AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL) +					'; +			 +			$args[] = $q; +			$args[] = $q; +			$args[] = $q; +			$args[] = $q; +			$args[] = $user_id; +		} +		else +		{ +			$where  = ' WHERE ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL'; +			$args[] = $user_id; +		} + +		$servers = $this->query_all_assoc(' +					SELECT	ocr_id					as id, +							ocr_usa_id_ref			as user_id, +							ocr_consumer_key 		as consumer_key, +							ocr_consumer_secret 	as consumer_secret, +							ocr_signature_methods	as signature_methods, +							ocr_server_uri			as server_uri, +							ocr_server_uri_host		as server_uri_host, +							ocr_server_uri_path		as server_uri_path, +							ocr_request_token_uri	as request_token_uri, +							ocr_authorize_uri		as authorize_uri, +							ocr_access_token_uri	as access_token_uri +					FROM oauth_consumer_registry +					'.$where.' +					ORDER BY ocr_server_uri_host, ocr_server_uri_path +					', $args); +		return $servers; +	} + + +	/** +	 * Register or update a server for our site (we will be the consumer) +	 *  +	 * (This is the registry at the consumers, registering servers ;-) ) +	 *  +	 * @param array server +	 * @param int user_id	user registering this server +	 * @param boolean user_is_admin +	 * @exception OAuthException when fields are missing or on duplicate consumer_key +	 * @return consumer_key +	 */ +	public function updateServer ( $server, $user_id, $user_is_admin = false ) +	{ +		foreach (array('consumer_key', 'server_uri') as $f) +		{ +			if (empty($server[$f])) +			{ +				throw new OAuthException('The field "'.$f.'" must be set and non empty'); +			} +		} +		 +		if (!empty($server['id'])) +		{ +			$exists = $this->query_one(' +						SELECT ocr_id +						FROM oauth_consumer_registry +						WHERE ocr_consumer_key = \'%s\' +						  AND ocr_id <> %d +						  AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL) +						', $server['consumer_key'], $server['id'], $user_id); +		} +		else +		{ +			$exists = $this->query_one(' +						SELECT ocr_id +						FROM oauth_consumer_registry +						WHERE ocr_consumer_key = \'%s\' +						  AND (ocr_usa_id_ref = %d OR ocr_usa_id_ref IS NULL) +						', $server['consumer_key'], $user_id); +		} + +		if ($exists) +		{ +			throw new OAuthException('The server with key "'.$server['consumer_key'].'" has already been registered'); +		} + +		$parts = parse_url($server['server_uri']); +		$host  = (isset($parts['host']) ? $parts['host'] : 'localhost'); +		$path  = (isset($parts['path']) ? $parts['path'] : '/'); + +		if (isset($server['signature_methods'])) +		{ +			if (is_array($server['signature_methods'])) +			{ +				$server['signature_methods'] = strtoupper(implode(',', $server['signature_methods'])); +			} +		}	 +		else +		{ +			$server['signature_methods'] = ''; +		} + +		// When the user is an admin, then the user can update the user_id of this record +		if ($user_is_admin && array_key_exists('user_id', $server)) +		{ +			if (is_null($server['user_id'])) +			{ +				$update_user =  ', ocr_usa_id_ref = NULL'; +			} +			else +			{ +				$update_user =  ', ocr_usa_id_ref = '.intval($server['user_id']); +			} +		} +		else +		{ +			$update_user = ''; +		} +		 +		if (!empty($server['id'])) +		{ +			// Check if the current user can update this server definition +			if (!$user_is_admin) +			{ +				$ocr_usa_id_ref = $this->query_one(' +									SELECT ocr_usa_id_ref +									FROM oauth_consumer_registry +									WHERE ocr_id = %d +									', $server['id']); +				 +				if ($ocr_usa_id_ref != $user_id) +				{ +					throw new OAuthException('The user "'.$user_id.'" is not allowed to update this server'); +				} +			} +			 +			// Update the consumer registration	 +			$this->query(' +					UPDATE oauth_consumer_registry +					SET ocr_consumer_key    	= \'%s\', +						ocr_consumer_secret 	= \'%s\', +						ocr_server_uri	    	= \'%s\', +						ocr_server_uri_host 	= \'%s\', +						ocr_server_uri_path 	= \'%s\', +						ocr_timestamp       	= NOW(), +						ocr_request_token_uri	= \'%s\', +						ocr_authorize_uri		= \'%s\', +						ocr_access_token_uri	= \'%s\', +						ocr_signature_methods	= \'%s\' +						'.$update_user.' +					WHERE ocr_id = %d +					',  +					$server['consumer_key'], +					$server['consumer_secret'], +					$server['server_uri'], +					strtolower($host), +					$path, +					isset($server['request_token_uri']) ? $server['request_token_uri'] : '', +					isset($server['authorize_uri'])     ? $server['authorize_uri']     : '', +					isset($server['access_token_uri'])  ? $server['access_token_uri']  : '', +					$server['signature_methods'], +					$server['id'] +					); +		} +		else +		{ +			if (empty($update_user)) +			{ +				// Per default the user owning the key is the user registering the key +				$update_user =  ', ocr_usa_id_ref = '.intval($user_id); +			} + +			$this->query(' +					INSERT INTO oauth_consumer_registry +					SET ocr_consumer_key    	= \'%s\', +						ocr_consumer_secret 	= \'%s\', +						ocr_server_uri	    	= \'%s\', +						ocr_server_uri_host 	= \'%s\', +						ocr_server_uri_path 	= \'%s\', +						ocr_timestamp       	= NOW(), +						ocr_request_token_uri	= \'%s\', +						ocr_authorize_uri		= \'%s\', +						ocr_access_token_uri	= \'%s\', +						ocr_signature_methods	= \'%s\' +						'.$update_user,  +					$server['consumer_key'], +					$server['consumer_secret'], +					$server['server_uri'], +					strtolower($host), +					$path, +					isset($server['request_token_uri']) ? $server['request_token_uri'] : '', +					isset($server['authorize_uri'])     ? $server['authorize_uri']     : '', +					isset($server['access_token_uri'])  ? $server['access_token_uri']  : '', +					$server['signature_methods'] +					); +		 +			$ocr_id = $this->query_insert_id(); +		} +		return $server['consumer_key']; +	} + + +	/** +	 * Insert/update a new consumer with this server (we will be the server) +	 * When this is a new consumer, then also generate the consumer key and secret. +	 * Never updates the consumer key and secret. +	 * When the id is set, then the key and secret must correspond to the entry +	 * being updated. +	 *  +	 * (This is the registry at the server, registering consumers ;-) ) +	 *  +	 * @param array consumer +	 * @param int user_id	user registering this consumer +	 * @param boolean user_is_admin +	 * @return string consumer key +	 */ +	public function updateConsumer ( $consumer, $user_id, $user_is_admin = false ) +	{ +		if (!$user_is_admin) +		{ +			foreach (array('requester_name', 'requester_email') as $f) +			{ +				if (empty($consumer[$f])) +				{ +					throw new OAuthException('The field "'.$f.'" must be set and non empty'); +				} +			} +		} +		 +		if (!empty($consumer['id'])) +		{ +			if (empty($consumer['consumer_key'])) +			{ +				throw new OAuthException('The field "consumer_key" must be set and non empty'); +			} +			if (!$user_is_admin && empty($consumer['consumer_secret'])) +			{ +				throw new OAuthException('The field "consumer_secret" must be set and non empty'); +			} + +			// Check if the current user can update this server definition +			if (!$user_is_admin) +			{ +				$osr_usa_id_ref = $this->query_one(' +									SELECT osr_usa_id_ref +									FROM oauth_server_registry +									WHERE osr_id = %d +									', $consumer['id']); +				 +				if ($osr_usa_id_ref != $user_id) +				{ +					throw new OAuthException('The user "'.$user_id.'" is not allowed to update this consumer'); +				} +			} +			else +			{ +				// User is an admin, allow a key owner to be changed or key to be shared +				if (array_key_exists('user_id',$consumer)) +				{ +					if (is_null($consumer['user_id'])) +					{ +						$this->query(' +							UPDATE oauth_server_registry +							SET osr_usa_id_ref = NULL +							WHERE osr_id = %d +							', $consumer['id']); +					} +					else +					{ +						$this->query(' +							UPDATE oauth_server_registry +							SET osr_usa_id_ref = %d +							WHERE osr_id = %d +							', $consumer['user_id'], $consumer['id']);	 +					} +				} +			} +			 +			$this->query(' +				UPDATE oauth_server_registry +				SET osr_requester_name		= \'%s\', +					osr_requester_email		= \'%s\', +					osr_callback_uri		= \'%s\', +					osr_application_uri		= \'%s\', +					osr_application_title	= \'%s\', +					osr_application_descr	= \'%s\', +					osr_application_notes	= \'%s\', +					osr_application_type	= \'%s\', +					osr_application_commercial = IF(%d,1,0), +					osr_timestamp			= NOW() +				WHERE osr_id              = %d +				  AND osr_consumer_key    = \'%s\' +				  AND osr_consumer_secret = \'%s\' +				', +				$consumer['requester_name'], +				$consumer['requester_email'], +				isset($consumer['callback_uri']) 		? $consumer['callback_uri'] 			 : '', +				isset($consumer['application_uri']) 	? $consumer['application_uri'] 			 : '', +				isset($consumer['application_title'])	? $consumer['application_title'] 		 : '', +				isset($consumer['application_descr'])	? $consumer['application_descr'] 		 : '', +				isset($consumer['application_notes'])	? $consumer['application_notes'] 		 : '', +				isset($consumer['application_type']) 	? $consumer['application_type'] 		 : '', +				isset($consumer['application_commercial']) ? $consumer['application_commercial'] : 0, +				$consumer['id'], +				$consumer['consumer_key'], +				$consumer['consumer_secret'] +				); +				 + +			$consumer_key = $consumer['consumer_key']; +		} +		else +		{ +			$consumer_key	= $this->generateKey(true); +			$consumer_secret= $this->generateKey(); + +			// When the user is an admin, then the user can be forced to something else that the user +			if ($user_is_admin && array_key_exists('user_id',$consumer)) +			{ +				if (is_null($consumer['user_id'])) +				{ +					$owner_id = 'NULL'; +				} +				else +				{ +					$owner_id = intval($consumer['user_id']); +				} +			} +			else +			{ +				// No admin, take the user id as the owner id. +				$owner_id = intval($user_id); +			} + +			$this->query(' +				INSERT INTO oauth_server_registry +				SET osr_enabled				= 1, +					osr_status				= \'active\', +					osr_usa_id_ref			= %s, +					osr_consumer_key		= \'%s\', +					osr_consumer_secret		= \'%s\', +					osr_requester_name		= \'%s\', +					osr_requester_email		= \'%s\', +					osr_callback_uri		= \'%s\', +					osr_application_uri		= \'%s\', +					osr_application_title	= \'%s\', +					osr_application_descr	= \'%s\', +					osr_application_notes	= \'%s\', +					osr_application_type	= \'%s\', +					osr_application_commercial = IF(%d,1,0), +					osr_timestamp			= NOW(), +					osr_issue_date			= NOW() +				', +				$owner_id, +				$consumer_key, +				$consumer_secret, +				$consumer['requester_name'], +				$consumer['requester_email'], +				isset($consumer['callback_uri']) 		? $consumer['callback_uri'] 			 : '', +				isset($consumer['application_uri']) 	? $consumer['application_uri'] 			 : '', +				isset($consumer['application_title'])	? $consumer['application_title'] 		 : '', +				isset($consumer['application_descr'])	? $consumer['application_descr'] 		 : '', +				isset($consumer['application_notes'])	? $consumer['application_notes'] 		 : '', +				isset($consumer['application_type']) 	? $consumer['application_type'] 		 : '', +				isset($consumer['application_commercial']) ? $consumer['application_commercial'] : 0 +				); +		} +		return $consumer_key; + +	} + + + +	/** +	 * Delete a consumer key.  This removes access to our site for all applications using this key. +	 *  +	 * @param string consumer_key +	 * @param int user_id	user registering this server +	 * @param boolean user_is_admin +	 */ +	public function deleteConsumer ( $consumer_key, $user_id, $user_is_admin = false ) +	{ +		if ($user_is_admin) +		{ +			$this->query(' +					DELETE FROM oauth_server_registry +					WHERE osr_consumer_key = \'%s\' +					  AND (osr_usa_id_ref = %d OR osr_usa_id_ref IS NULL) +					', $consumer_key, $user_id); +		} +		else +		{ +			$this->query(' +					DELETE FROM oauth_server_registry +					WHERE osr_consumer_key = \'%s\' +					  AND osr_usa_id_ref   = %d +					', $consumer_key, $user_id); +		} +	}	 +	 +	 +	 +	/** +	 * Fetch a consumer of this server, by consumer_key. +	 *  +	 * @param string consumer_key +	 * @param int user_id +	 * @param boolean user_is_admin (optional) +	 * @exception OAuthException when consumer not found +	 * @return array +	 */ +	public function getConsumer ( $consumer_key, $user_id, $user_is_admin = false ) +	{ +		$consumer = $this->query_row_assoc(' +						SELECT	* +						FROM oauth_server_registry +						WHERE osr_consumer_key = \'%s\' +						', $consumer_key); +		 +		if (!is_array($consumer)) +		{ +			throw new OAuthException('No consumer with consumer_key "'.$consumer_key.'"'); +		} + +		$c = array(); +		foreach ($consumer as $key => $value) +		{ +			$c[substr($key, 4)] = $value; +		} +		$c['user_id'] = $c['usa_id_ref']; + +		if (!$user_is_admin && !empty($c['user_id']) && $c['user_id'] != $user_id) +		{ +			throw new OAuthException('No access to the consumer information for consumer_key "'.$consumer_key.'"'); +		} +		return $c; +	} + + +	/** +	 * Fetch the static consumer key for this provider.  The user for the static consumer  +	 * key is NULL (no user, shared key).  If the key did not exist then the key is created. +	 *  +	 * @return string +	 */ +	public function getConsumerStatic () +	{ +		$consumer = $this->query_one(' +						SELECT osr_consumer_key +						FROM oauth_server_registry +						WHERE osr_consumer_key LIKE \'sc-%%\' +						  AND osr_usa_id_ref IS NULL +						'); + +		if (empty($consumer)) +		{ +			$consumer_key = 'sc-'.$this->generateKey(true); +			$this->query(' +				INSERT INTO oauth_server_registry +				SET osr_enabled				= 1, +					osr_status				= \'active\', +					osr_usa_id_ref			= NULL, +					osr_consumer_key		= \'%s\', +					osr_consumer_secret		= \'\', +					osr_requester_name		= \'\', +					osr_requester_email		= \'\', +					osr_callback_uri		= \'\', +					osr_application_uri		= \'\', +					osr_application_title	= \'Static shared consumer key\', +					osr_application_descr	= \'\', +					osr_application_notes	= \'Static shared consumer key\', +					osr_application_type	= \'\', +					osr_application_commercial = 0, +					osr_timestamp			= NOW(), +					osr_issue_date			= NOW() +				', +				$consumer_key +				); +			 +			// Just make sure that if the consumer key is truncated that we get the truncated string +			$consumer = $this->getConsumerStatic(); +		} +		return $consumer; +	} + + +	/** +	 * Add an unautorized request token to our server. +	 *  +	 * @param string consumer_key +	 * @param array options		(eg. token_ttl) +	 * @return array (token, token_secret) +	 */ +	public function addConsumerRequestToken ( $consumer_key, $options = array() ) +	{ +		$token  = $this->generateKey(true); +		$secret = $this->generateKey(); +		$osr_id	= $this->query_one(' +						SELECT osr_id +						FROM oauth_server_registry +						WHERE osr_consumer_key = \'%s\' +						  AND osr_enabled      = 1 +						', $consumer_key); + +		if (!$osr_id) +		{ +			throw new OAuthException('No server with consumer_key "'.$consumer_key.'" or consumer_key is disabled'); +		} + +		if (isset($options['token_ttl']) && is_numeric($options['token_ttl'])) +		{ +			$ttl = intval($options['token_ttl']); +		} +		else +		{ +			$ttl = $this->max_request_token_ttl; +		} + +		$this->query(' +				INSERT INTO oauth_server_token +				SET ost_osr_id_ref		= %d, +					ost_usa_id_ref		= 1, +					ost_token			= \'%s\', +					ost_token_secret	= \'%s\', +					ost_token_type		= \'request\', +					ost_token_ttl       = DATE_ADD(NOW(), INTERVAL %d SECOND) +				ON DUPLICATE KEY UPDATE +					ost_osr_id_ref		= VALUES(ost_osr_id_ref), +					ost_usa_id_ref		= VALUES(ost_usa_id_ref), +					ost_token			= VALUES(ost_token), +					ost_token_secret	= VALUES(ost_token_secret), +					ost_token_type		= VALUES(ost_token_type), +					ost_token_ttl       = VALUES(ost_token_ttl), +					ost_timestamp		= NOW() +				', $osr_id, $token, $secret, $ttl); +		 +		return array('token'=>$token, 'token_secret'=>$secret, 'token_ttl'=>$ttl); +	} +	 +	 +	/** +	 * Fetch the consumer request token, by request token. +	 *  +	 * @param string token +	 * @return array  token and consumer details +	 */ +	public function getConsumerRequestToken ( $token ) +	{ +		$rs = $this->query_row_assoc(' +				SELECT	ost_token			as token, +						ost_token_secret	as token_secret, +						osr_consumer_key	as consumer_key, +						osr_consumer_secret	as consumer_secret, +						ost_token_type		as token_type +				FROM oauth_server_token +						JOIN oauth_server_registry +						ON ost_osr_id_ref = osr_id +				WHERE ost_token_type = \'request\' +				  AND ost_token      = \'%s\' +				  AND ost_token_ttl  >= NOW() +				', $token); +		 +		return $rs; +	} +	 + +	/** +	 * Delete a consumer token.  The token must be a request or authorized token. +	 *  +	 * @param string token +	 */ +	public function deleteConsumerRequestToken ( $token ) +	{ +		$this->query(' +					DELETE FROM oauth_server_token +					WHERE ost_token 	 = \'%s\' +					  AND ost_token_type = \'request\' +					', $token); +	} +	 + +	/** +	 * Upgrade a request token to be an authorized request token. +	 *  +	 * @param string token +	 * @param int	 user_id  user authorizing the token +	 * @param string referrer_host used to set the referrer host for this token, for user feedback +	 */ +	public function authorizeConsumerRequestToken ( $token, $user_id, $referrer_host = '' ) +	{ +		$this->query(' +					UPDATE oauth_server_token +					SET ost_authorized    = 1, +						ost_usa_id_ref    = %d, +						ost_timestamp     = NOW(), +						ost_referrer_host = \'%s\' +					WHERE ost_token      = \'%s\' +					  AND ost_token_type = \'request\' +					', $user_id, $referrer_host, $token); +	} + + +	/** +	 * Count the consumer access tokens for the given consumer. +	 *  +	 * @param string consumer_key +	 * @return int +	 */ +	public function countConsumerAccessTokens ( $consumer_key ) +	{ +		$count = $this->query_one(' +					SELECT COUNT(ost_id) +					FROM oauth_server_token +							JOIN oauth_server_registry +							ON ost_osr_id_ref = osr_id +					WHERE ost_token_type   = \'access\' +					  AND osr_consumer_key = \'%s\' +					  AND ost_token_ttl    >= NOW() +					', $consumer_key); +		 +		return $count; +	} + + +	/** +	 * Exchange an authorized request token for new access token. +	 *  +	 * @param string token +	 * @param array options		options for the token, token_ttl +	 * @exception OAuthException when token could not be exchanged +	 * @return array (token, token_secret) +	 */ +	public function exchangeConsumerRequestForAccessToken ( $token, $options = array() ) +	{ +		$new_token  = $this->generateKey(true); +		$new_secret = $this->generateKey(); + +		// Maximum time to live for this token +		if (isset($options['token_ttl']) && is_numeric($options['token_ttl'])) +		{ +			$ttl_sql = 'DATE_ADD(NOW(), INTERVAL '.intval($options['token_ttl']).' SECOND)'; +		} +		else +		{ +			$ttl_sql = "'9999-12-31'"; +		} + +		$this->query(' +					UPDATE oauth_server_token +					SET ost_token			= \'%s\', +						ost_token_secret	= \'%s\', +						ost_token_type		= \'access\', +						ost_timestamp		= NOW(), +						ost_token_ttl       = '.$ttl_sql.' +					WHERE ost_token      = \'%s\' +					  AND ost_token_type = \'request\' +					  AND ost_authorized = 1 +					  AND ost_token_ttl  >= NOW() +					', $new_token, $new_secret, $token); +		 +		if ($this->query_affected_rows() != 1) +		{ +			throw new OAuthException('Can\'t exchange request token "'.$token.'" for access token. No such token or not authorized'); +		} + +		$ret = array('token' => $new_token, 'token_secret' => $new_secret); +		$ttl = $this->query_one(' +					SELECT	IF(ost_token_ttl >= \'9999-12-31\', NULL, UNIX_TIMESTAMP(ost_token_ttl) - UNIX_TIMESTAMP(NOW())) as token_ttl +					FROM oauth_server_token +					WHERE ost_token = \'%s\'', $new_token); + +		if (is_numeric($ttl)) +		{ +			$ret['token_ttl'] = intval($ttl); +		} +		return $ret; +	} + + +	/** +	 * Fetch the consumer access token, by access token. +	 *  +	 * @param string token +	 * @param int user_id +	 * @exception OAuthException when token is not found +	 * @return array  token and consumer details +	 */ +	public function getConsumerAccessToken ( $token, $user_id ) +	{ +		$rs = $this->query_row_assoc(' +				SELECT	ost_token				as token, +						ost_token_secret		as token_secret, +						ost_referrer_host		as token_referrer_host, +						osr_consumer_key		as consumer_key, +						osr_consumer_secret		as consumer_secret, +						osr_application_uri		as application_uri, +						osr_application_title	as application_title, +						osr_application_descr	as application_descr +				FROM oauth_server_token +						JOIN oauth_server_registry +						ON ost_osr_id_ref = osr_id +				WHERE ost_token_type = \'access\' +				  AND ost_token      = \'%s\' +				  AND ost_usa_id_ref = %d +				  AND ost_token_ttl  >= NOW() +				', $token, $user_id); +		 +		if (empty($rs)) +		{ +			throw new OAuthException('No server_token "'.$token.'" for user "'.$user_id.'"'); +		} +		return $rs; +	} + + +	/** +	 * Delete a consumer access token. +	 *  +	 * @param string token +	 * @param int user_id +	 * @param boolean user_is_admin +	 */ +	public function deleteConsumerAccessToken ( $token, $user_id, $user_is_admin = false ) +	{ +		if ($user_is_admin) +		{ +			$this->query(' +						DELETE FROM oauth_server_token +						WHERE ost_token 	 = \'%s\' +						  AND ost_token_type = \'access\' +						', $token); +		} +		else +		{ +			$this->query(' +						DELETE FROM oauth_server_token +						WHERE ost_token 	 = \'%s\' +						  AND ost_token_type = \'access\' +						  AND ost_usa_id_ref = %d +						', $token, $user_id); +		} +	} + + +	/** +	 * Set the ttl of a consumer access token.  This is done when the +	 * server receives a valid request with a xoauth_token_ttl parameter in it. +	 *  +	 * @param string token +	 * @param int ttl +	 */ +	public function setConsumerAccessTokenTtl ( $token, $token_ttl ) +	{ +		if ($token_ttl <= 0) +		{ +			// Immediate delete when the token is past its ttl +			$this->deleteConsumerAccessToken($token, 0, true); +		} +		else +		{ +			// Set maximum time to live for this token +			$this->query(' +						UPDATE oauth_server_token +						SET ost_token_ttl = DATE_ADD(NOW(), INTERVAL %d SECOND) +						WHERE ost_token 	 = \'%s\' +						  AND ost_token_type = \'access\' +						', $token_ttl, $token); +		} +	} + + +	/** +	 * Fetch a list of all consumer keys, secrets etc. +	 * Returns the public (user_id is null) and the keys owned by the user +	 *  +	 * @param int user_id +	 * @return array +	 */ +	public function listConsumers ( $user_id ) +	{ +		$rs = $this->query_all_assoc(' +				SELECT	osr_id					as id, +						osr_usa_id_ref			as user_id, +						osr_consumer_key 		as consumer_key, +						osr_consumer_secret		as consumer_secret, +						osr_enabled				as enabled, +						osr_status 				as status, +						osr_issue_date			as issue_date, +						osr_application_uri		as application_uri, +						osr_application_title	as application_title, +						osr_application_descr	as application_descr, +						osr_requester_name		as requester_name, +						osr_requester_email		as requester_email +				FROM oauth_server_registry +				WHERE (osr_usa_id_ref = %d OR osr_usa_id_ref IS NULL) +				ORDER BY osr_application_title +				', $user_id); +		return $rs; +	} + + +	/** +	 * Fetch a list of all consumer tokens accessing the account of the given user. +	 *  +	 * @param int user_id +	 * @return array +	 */ +	public function listConsumerTokens ( $user_id ) +	{ +		$rs = $this->query_all_assoc(' +				SELECT	osr_consumer_key 		as consumer_key, +						osr_consumer_secret		as consumer_secret, +						osr_enabled				as enabled, +						osr_status 				as status, +						osr_application_uri		as application_uri, +						osr_application_title	as application_title, +						osr_application_descr	as application_descr, +						ost_timestamp			as timestamp,	 +						ost_token				as token, +						ost_token_secret		as token_secret, +						ost_referrer_host		as token_referrer_host +				FROM oauth_server_registry +					JOIN oauth_server_token +					ON ost_osr_id_ref = osr_id +				WHERE ost_usa_id_ref = %d +				  AND ost_token_type = \'access\' +				  AND ost_token_ttl  >= NOW() +				ORDER BY osr_application_title +				', $user_id); +		return $rs; +	} + + +	/** +	 * Check an nonce/timestamp combination.  Clears any nonce combinations +	 * that are older than the one received. +	 *  +	 * @param string	consumer_key +	 * @param string 	token +	 * @param int		timestamp +	 * @param string 	nonce +	 * @exception OAuthException	thrown when the timestamp is not in sequence or nonce is not unique +	 */ +	public function checkServerNonce ( $consumer_key, $token, $timestamp, $nonce ) +	{ +		$r = $this->query_row(' +							SELECT MAX(osn_timestamp), MAX(osn_timestamp) > %d + %d +							FROM oauth_server_nonce +							WHERE osn_consumer_key = \'%s\' +							  AND osn_token        = \'%s\' +							', $timestamp, $this->max_timestamp_skew, $consumer_key, $token); + +		if (!empty($r) && $r[1]) +		{ +			throw new OAuthException('Timestamp is out of sequence. Request rejected. Got '.$timestamp.' last max is '.$r[0].' allowed skew is '.$this->max_timestamp_skew); +		} +		 +		// Insert the new combination +		$this->query(' +				INSERT IGNORE INTO oauth_server_nonce +				SET osn_consumer_key	= \'%s\', +					osn_token			= \'%s\', +					osn_timestamp		= %d, +					osn_nonce			= \'%s\' +				', $consumer_key, $token, $timestamp, $nonce); +		 +		if ($this->query_affected_rows() == 0) +		{ +			throw new OAuthException('Duplicate timestamp/nonce combination, possible replay attack.  Request rejected.'); +		} + +		// Clean up all timestamps older than the one we just received +		$this->query(' +				DELETE FROM oauth_server_nonce +				WHERE osn_consumer_key	= \'%s\' +				  AND osn_token			= \'%s\' +				  AND osn_timestamp     < %d - %d +				', $consumer_key, $token, $timestamp, $this->max_timestamp_skew); +	} + + +	/** +	 * Add an entry to the log table +	 *  +	 * @param array keys (osr_consumer_key, ost_token, ocr_consumer_key, oct_token) +	 * @param string received +	 * @param string sent +	 * @param string base_string +	 * @param string notes +	 * @param int (optional) user_id +	 */ +	public function addLog ( $keys, $received, $sent, $base_string, $notes, $user_id = null ) +	{ +		$args = array(); +		$ps   = array(); +		foreach ($keys as $key => $value) +		{ +			$args[] = $value; +			$ps[]   = "olg_$key = '%s'"; +		} + +		if (!empty($_SERVER['REMOTE_ADDR'])) +		{ +			$remote_ip = $_SERVER['REMOTE_ADDR']; +		}	 +		else if (!empty($_SERVER['REMOTE_IP'])) +		{ +			$remote_ip = $_SERVER['REMOTE_IP']; +		} +		else +		{ +			$remote_ip = '0.0.0.0'; +		} + +		// Build the SQL +		$ps[] = "olg_received  	= '%s'";						$args[] = $this->makeUTF8($received); +		$ps[] = "olg_sent   	= '%s'";						$args[] = $this->makeUTF8($sent); +		$ps[] = "olg_base_string= '%s'";						$args[] = $base_string; +		$ps[] = "olg_notes   	= '%s'";						$args[] = $this->makeUTF8($notes); +		$ps[] = "olg_usa_id_ref = NULLIF(%d,0)";				$args[] = $user_id; +		$ps[] = "olg_remote_ip  = IFNULL(INET_ATON('%s'),0)";	$args[] = $remote_ip; + +		$this->query('INSERT INTO oauth_log SET '.implode(',', $ps), $args); +	} +	 +	 +	/** +	 * Get a page of entries from the log.  Returns the last 100 records +	 * matching the options given. +	 *  +	 * @param array options +	 * @param int user_id	current user +	 * @return array log records +	 */ +	public function listLog ( $options, $user_id ) +	{ +		$where = array(); +		$args  = array(); +		if (empty($options)) +		{ +			$where[] = 'olg_usa_id_ref = %d'; +			$args[]  = $user_id; +		} +		else +		{ +			foreach ($options as $option => $value) +			{ +				if (strlen($value) > 0) +				{ +					switch ($option) +					{ +					case 'osr_consumer_key': +					case 'ocr_consumer_key': +					case 'ost_token': +					case 'oct_token': +						$where[] = 'olg_'.$option.' = \'%s\''; +						$args[]  = $value;	 +						break;				 +					} +				} +			} +			 +			$where[] = '(olg_usa_id_ref IS NULL OR olg_usa_id_ref = %d)'; +			$args[]  = $user_id; +		} + +		$rs = $this->query_all_assoc(' +					SELECT olg_id, +							olg_osr_consumer_key 	AS osr_consumer_key, +							olg_ost_token			AS ost_token, +							olg_ocr_consumer_key	AS ocr_consumer_key, +							olg_oct_token			AS oct_token, +							olg_usa_id_ref			AS user_id, +							olg_received			AS received, +							olg_sent				AS sent, +							olg_base_string			AS base_string, +							olg_notes				AS notes, +							olg_timestamp			AS timestamp, +							INET_NTOA(olg_remote_ip) AS remote_ip +					FROM oauth_log +					WHERE '.implode(' AND ', $where).' +					ORDER BY olg_id DESC +					LIMIT 0,100', $args); + +		return $rs; +	} + + + +	/** +	 * Initialise the database +	 */ +	public function install () +	{ +		require_once dirname(__FILE__) . '/mysql/install.php'; +	} +	 +	 +	/* ** Some simple helper functions for querying the mysql db ** */ + +	/** +	 * Perform a query, ignore the results +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 */ +	protected function query ( $sql ) +	{ +		$sql = $this->sql_printf(func_get_args()); +		if (!($res = mysql_query($sql, $this->conn))) +		{ +			$this->sql_errcheck($sql); +		} +		if (is_resource($res)) +		{ +			mysql_free_result($res); +		} +	} +	 + +	/** +	 * Perform a query, ignore the results +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_all_assoc ( $sql ) +	{ +		$sql = $this->sql_printf(func_get_args()); +		if (!($res = mysql_query($sql, $this->conn))) +		{ +			$this->sql_errcheck($sql); +		} +		$rs = array(); +		while ($row  = mysql_fetch_assoc($res)) +		{ +			$rs[] = $row; +		} +		mysql_free_result($res); +		return $rs; +	} +	 +	 +	/** +	 * Perform a query, return the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_row_assoc ( $sql ) +	{ +		$sql = $this->sql_printf(func_get_args()); +		if (!($res = mysql_query($sql, $this->conn))) +		{ +			$this->sql_errcheck($sql); +		} +		if ($row = mysql_fetch_assoc($res)) +		{ +			$rs = $row; +		} +		else +		{ +			$rs = false; +		} +		mysql_free_result($res); +		return $rs; +	} + +	 +	/** +	 * Perform a query, return the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return array +	 */ +	protected function query_row ( $sql ) +	{ +		$sql = $this->sql_printf(func_get_args()); +		if (!($res = mysql_query($sql, $this->conn))) +		{ +			$this->sql_errcheck($sql); +		} +		if ($row = mysql_fetch_array($res)) +		{ +			$rs = $row; +		} +		else +		{ +			$rs = false; +		} +		mysql_free_result($res); +		return $rs; +	} +	 +		 +	/** +	 * Perform a query, return the first column of the first row +	 *  +	 * @param string sql +	 * @param vararg arguments (for sprintf) +	 * @return mixed +	 */ +	protected function query_one ( $sql ) +	{ +		$sql = $this->sql_printf(func_get_args()); +		if (!($res = mysql_query($sql, $this->conn))) +		{ +			$this->sql_errcheck($sql); +		} +		$val = @mysql_result($res, 0, 0); +		mysql_free_result($res); +		return $val; +	} +	 +	 +	/** +	 * Return the number of rows affected in the last query +	 */ +	protected function query_affected_rows () +	{ +		return mysql_affected_rows($this->conn); +	} + + +	/** +	 * Return the id of the last inserted row +	 *  +	 * @return int +	 */ +	protected function query_insert_id () +	{ +		return mysql_insert_id($this->conn); +	} +	 +	 +	protected function sql_printf ( $args ) +	{ +		$sql  = array_shift($args); +		if (count($args) == 1 && is_array($args[0])) +		{ +			$args = $args[0]; +		} +		$args = array_map(array($this, 'sql_escape_string'), $args); +		return vsprintf($sql, $args); +	} +	 +	 +	protected function sql_escape_string ( $s ) +	{ +		if (is_string($s)) +		{ +			return mysql_real_escape_string($s, $this->conn); +		} +		else if (is_null($s)) +		{ +			return NULL; +		} +		else if (is_bool($s)) +		{ +			return intval($s); +		} +		else if (is_int($s) || is_float($s)) +		{ +			return $s; +		} +		else +		{ +			return mysql_real_escape_string(strval($s), $this->conn); +		} +	} +	 +	 +	protected function sql_errcheck ( $sql ) +	{ +		if (mysql_errno($this->conn)) +		{ +			$msg =  "SQL Error in OAuthStoreMySQL: ".mysql_error($this->conn)."\n\n" . $sql; +			throw new OAuthException($msg); +		} +	} +} + + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/store/mysql/install.php b/mod/oauth_api/vendors/oauth/library/store/mysql/install.php new file mode 100644 index 000000000..0015da5e3 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/store/mysql/install.php @@ -0,0 +1,32 @@ +<?php + +/** + * Installs all tables in the mysql.sql file, using the default mysql connection + */ + +/* Change and uncomment this when you need to: */ + +/* +mysql_connect('localhost', 'root'); +if (mysql_errno()) +{ +	die(' Error '.mysql_errno().': '.mysql_error()); +} +mysql_select_db('test'); +*/ + +$sql = file_get_contents(dirname(__FILE__) . '/mysql.sql'); +$ps  = explode('#--SPLIT--', $sql); + +foreach ($ps as $p) +{ +	$p = preg_replace('/^\s*#.*$/m', '', $p); +	 +	mysql_query($p); +	if (mysql_errno()) +	{ +		die(' Error '.mysql_errno().': '.mysql_error()); +	} +} + +?>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/library/store/mysql/mysql.sql b/mod/oauth_api/vendors/oauth/library/store/mysql/mysql.sql new file mode 100644 index 000000000..d652a1c99 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/library/store/mysql/mysql.sql @@ -0,0 +1,219 @@ +# Datamodel for OAuthStoreMySQL +# +# You need to add the foreign key constraints for the user ids your are using. +# I have commented the constraints out, just look for 'usa_id_ref' to enable them. +# +# The --SPLIT-- markers are used by the install.php script +#    +# @version $Id: mysql.sql 51 2008-10-15 15:15:47Z marcw@pobox.com $ +# @author Marc Worrell +# + +# Changes: +# +# 2008-10-15 (on r48) Added ttl to consumer and server tokens, added named server tokens +# +#			ALTER TABLE oauth_server_token  +#			ADD ost_token_ttl datetime not null default '9999-12-31', +#			ADD KEY (ost_token_ttl); +# +#			ALTER TABLE oauth_consumer_token  +#			ADD oct_name varchar(64) binary not null default '', +#			ADD oct_token_ttl datetime not null default '9999-12-31', +#			DROP KEY oct_usa_id_ref, +#			ADD UNIQUE KEY (oct_usa_id_ref, oct_ocr_id_ref, oct_token_type, oct_name), +#			ADD KEY (oct_token_ttl); +# +# 2008-09-09 (on r5) Added referrer host to server access token +# +#			ALTER TABLE oauth_server_token ADD ost_referrer_host VARCHAR(128) NOT NULL; +# + + +# +# Log table to hold all OAuth request when you enabled logging +# + +CREATE TABLE IF NOT EXISTS oauth_log ( +    olg_id                  int(11) not null auto_increment, +    olg_osr_consumer_key    varchar(64) binary, +    olg_ost_token           varchar(64) binary, +    olg_ocr_consumer_key    varchar(64) binary, +    olg_oct_token           varchar(64) binary, +    olg_usa_id_ref          int(11), +    olg_received            text not null, +    olg_sent                text not null, +    olg_base_string         text not null, +    olg_notes               text not null, +    olg_timestamp           timestamp not null default current_timestamp, +    olg_remote_ip           bigint not null, + +    primary key (olg_id), +    key (olg_osr_consumer_key, olg_id), +    key (olg_ost_token, olg_id), +    key (olg_ocr_consumer_key, olg_id), +    key (olg_oct_token, olg_id), +    key (olg_usa_id_ref, olg_id) +     +#   , foreign key (olg_usa_id_ref) references any_user_auth (usa_id_ref) +#       on update cascade +#       on delete cascade +) engine=InnoDB default charset=utf8; + +#--SPLIT-- + +# +# /////////////////// CONSUMER SIDE /////////////////// +# + +# This is a registry of all consumer codes we got from other servers +# The consumer_key/secret is obtained from the server +# We also register the server uri, so that we can find the consumer key and secret +# for a certain server.  From that server we can check if we have a token for a +# particular user. + +CREATE TABLE IF NOT EXISTS oauth_consumer_registry ( +    ocr_id                  int(11) not null auto_increment, +    ocr_usa_id_ref          int(11), +    ocr_consumer_key        varchar(64) binary not null, +    ocr_consumer_secret     varchar(64) binary not null, +    ocr_signature_methods   varchar(255) not null default 'HMAC-SHA1,PLAINTEXT', +    ocr_server_uri          varchar(255) not null, +    ocr_server_uri_host     varchar(128) not null, +    ocr_server_uri_path     varchar(128) binary not null, + +    ocr_request_token_uri   varchar(255) not null, +    ocr_authorize_uri       varchar(255) not null, +    ocr_access_token_uri    varchar(255) not null, +    ocr_timestamp           timestamp not null default current_timestamp, + +    primary key (ocr_id), +    unique key (ocr_consumer_key, ocr_usa_id_ref), +    key (ocr_server_uri), +    key (ocr_server_uri_host, ocr_server_uri_path), +    key (ocr_usa_id_ref) + +#   , foreign key (ocr_usa_id_ref) references any_user_auth(usa_id_ref) +#       on update cascade +#       on delete set null +) engine=InnoDB default charset=utf8; + +#--SPLIT-- + +# Table used to sign requests for sending to a server by the consumer +# The key is defined for a particular user.  Only one single named +# key is allowed per user/server combination + +CREATE TABLE IF NOT EXISTS oauth_consumer_token ( +    oct_id                  int(11) not null auto_increment, +    oct_ocr_id_ref          int(11) not null, +    oct_usa_id_ref          int(11) not null, +    oct_name                varchar(64) binary not null default '', +    oct_token               varchar(64) binary not null, +    oct_token_secret        varchar(64) binary not null, +    oct_token_type          enum('request','authorized','access'), +    oct_token_ttl           datetime not null default '9999-12-31', +    oct_timestamp           timestamp not null default current_timestamp, + +    primary key (oct_id), +    unique key (oct_ocr_id_ref, oct_token), +    unique key (oct_usa_id_ref, oct_ocr_id_ref, oct_token_type, oct_name), +	key (oct_token_ttl), + +    foreign key (oct_ocr_id_ref) references oauth_consumer_registry (ocr_id) +        on update cascade +        on delete cascade + +#   , foreign key (oct_usa_id_ref) references any_user_auth (usa_id_ref) +#       on update cascade +#       on delete cascade            +) engine=InnoDB default charset=utf8; + +#--SPLIT-- + + +# +# ////////////////// SERVER SIDE ///////////////// +# + +# Table holding consumer key/secret combos an user issued to consumers.  +# Used for verification of incoming requests. + +CREATE TABLE IF NOT EXISTS oauth_server_registry ( +    osr_id                      int(11) not null auto_increment, +    osr_usa_id_ref              int(11), +    osr_consumer_key            varchar(64) binary not null, +    osr_consumer_secret         varchar(64) binary not null, +    osr_enabled                 tinyint(1) not null default '1', +    osr_status                  varchar(16) not null, +    osr_requester_name          varchar(64) not null, +    osr_requester_email         varchar(64) not null, +    osr_callback_uri            varchar(255) not null, +    osr_application_uri         varchar(255) not null, +    osr_application_title       varchar(80) not null, +    osr_application_descr       text not null, +    osr_application_notes       text not null, +    osr_application_type        varchar(20) not null, +    osr_application_commercial  tinyint(1) not null default '0', +    osr_issue_date              datetime not null, +    osr_timestamp               timestamp not null default current_timestamp, + +    primary key (osr_id), +    unique key (osr_consumer_key), +    key (osr_usa_id_ref) + +#   , foreign key (osr_usa_id_ref) references any_user_auth(usa_id_ref) +#       on update cascade +#       on delete set null +) engine=InnoDB default charset=utf8; + +#--SPLIT-- + +# Nonce used by a certain consumer, every used nonce should be unique, this prevents +# replaying attacks.  We need to store all timestamp/nonce combinations for the +# maximum timestamp received. + +CREATE TABLE IF NOT EXISTS oauth_server_nonce ( +    osn_id                  int(11) not null auto_increment, +    osn_consumer_key        varchar(64) binary not null, +    osn_token               varchar(64) binary not null, +    osn_timestamp           bigint not null, +    osn_nonce               varchar(80) binary not null, + +    primary key (osn_id), +    unique key (osn_consumer_key, osn_token, osn_timestamp, osn_nonce) +) engine=InnoDB default charset=utf8; + +#--SPLIT-- + +# Table used to verify signed requests sent to a server by the consumer +# When the verification is succesful then the associated user id is returned. + +CREATE TABLE IF NOT EXISTS oauth_server_token ( +    ost_id                  int(11) not null auto_increment, +    ost_osr_id_ref          int(11) not null, +    ost_usa_id_ref          int(11) not null, +    ost_token               varchar(64) binary not null, +    ost_token_secret        varchar(64) binary not null, +    ost_token_type          enum('request','access'), +    ost_authorized          tinyint(1) not null default '0', +	ost_referrer_host		varchar(128) not null, +	ost_token_ttl           datetime not null default '9999-12-31', +    ost_timestamp           timestamp not null default current_timestamp, + +	primary key (ost_id), +    unique key (ost_token), +    key (ost_osr_id_ref), +	key (ost_token_ttl), + +	foreign key (ost_osr_id_ref) references oauth_server_registry (osr_id) +        on update cascade +        on delete cascade + +#   , foreign key (ost_usa_id_ref) references any_user_auth (usa_id_ref) +#       on update cascade +#       on delete cascade            +) engine=InnoDB default charset=utf8; + + + diff --git a/mod/oauth_api/vendors/oauth/test/discovery/xrds-fireeagle.xrds b/mod/oauth_api/vendors/oauth/test/discovery/xrds-fireeagle.xrds new file mode 100644 index 000000000..0f5eba222 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/test/discovery/xrds-fireeagle.xrds @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XRDS xmlns="xri://$xrds"> +   +  <!-- FireEagle User-Centric OAuth Configuration --> +  <XRD xml:id="oauth" xmlns:simple="http://xrds-simple.net/core/1.0" xmlns="xri://$XRD*($v*2.0)" version="2.0"> +     +    <Type>xri://$xrds*simple</Type> +    <Expires>2008-04-15T00:25:30-07:00</Expires> + +    <!-- Request Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/request</Type> +       +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> + +      <URI>https://fireeagle.yahooapis.com/oauth/request_token</URI> +    </Service> + +    <!-- User Authorization --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/authorize</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> + +      <URI>https://fireeagle.yahooapis.com/oauth/access_token</URI> +    </Service> + +    <!-- Access Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/access</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> + +      <URI>http://fireeagle.yahoo.net/oauth/authorize</URI> +    </Service> + +    <!-- Protected Resources --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/resource</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> +    </Service> + +    <!-- Consumer Identity --> +     +      <!-- Manual Consumer Identity Allocation --> +      <Service> +        <Type>http://oauth.net/discovery/1.0/consumer-identity/oob</Type> +        <URI>https://fireeagle.yahoo.net/developer/create</URI> +      </Service> +  </XRD> +   +  <!-- Global Resource Definition --> +   +  <XRD xmlns="xri://$XRD*($v*2.0)" version="2.0"> +    <Type>xri://$xrds*simple</Type> +     +    <!-- OAuth Endpoints Definition --> +    <Service> +      <Type>http://oauth.net/discovery/1.0</Type> +      <URI>#oauth</URI> +    </Service> +  </XRD> +   +</XRDS>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/test/discovery/xrds-getsatisfaction.xrds b/mod/oauth_api/vendors/oauth/test/discovery/xrds-getsatisfaction.xrds new file mode 100644 index 000000000..ab94b5bea --- /dev/null +++ b/mod/oauth_api/vendors/oauth/test/discovery/xrds-getsatisfaction.xrds @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XRDS xmlns="xri://$xrds"> +   +  <XRD xml:id="oauth" xmlns:simple="http://xrds-simple.net/core/1.0" xmlns="xri://$XRD*($v*2.0)" version="2.0"> +    <Type>xri://$xrds*simple</Type> +    <Expires>2008-04-30T23:59:59Z</Expires> + +    <!-- Request Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/request</Type> +       +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +       +      <URI>http://getsatisfaction.com/api/request_token</URI> +    </Service> + +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/authorize</Type> + +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> + +      <URI>http://getsatisfaction.com/api/authorize</URI> +    </Service> + +    <!-- Access Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/access</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> + +      <URI>http://getsatisfaction.com/api/access_token</URI> +    </Service> + +    <!-- Protected Resources --> +    <!--  +       +      To test successful access token grant, make a request against +       +        http://api.getsatisfaction.com/me + +      The API should respond with hCard of the user who authorized the token +      --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/resource</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type>       +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> + +    </Service> + +    <!-- Consumer Identity --> +     +    <Service> +      <Type>http://oauth.net/discovery/1.0/consumer-identity/oob</Type> +      <URI>http://getsatisfaction.com/me/extensions/new</URI> +    </Service> +  </XRD> +   +  <!-- Global Resource Definition --> +   +  <XRD xmlns="xri://$XRD*($v*2.0)" version="2.0"> +    <Type>xri://$xrds*simple</Type> +     +    <!-- OAuth Endpoints Definition --> +    <Service priority="10"> +      <Type>http://oauth.net/discovery/1.0</Type> +      <URI>#oauth</URI> +    </Service> +  </XRD> +   +</XRDS>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/test/discovery/xrds-magnolia.xrds b/mod/oauth_api/vendors/oauth/test/discovery/xrds-magnolia.xrds new file mode 100644 index 000000000..361b5c9a1 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/test/discovery/xrds-magnolia.xrds @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<XRDS xmlns="xri://$xrds"> +   +  <!-- Ma.gnolia OAuth Configuration --> +  <XRD xml:id="oauth" xmlns="xri://$XRD*($v*2.0)" version="2.0"> +     +    <Type>xri://$xrds*simple</Type> +    <Expires>2008-04-13T07:34:58Z</Expires> + +    <!-- Request Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/request</Type> +       +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/RSA-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> + +      <URI>https://ma.gnolia.com/oauth/get_request_token</URI> +    </Service> + +    <!-- User Authorization (HTTPS Prefered) --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/authorize</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> + +      <URI priority="10">https://ma.gnolia.com/oauth/authorize</URI> +      <URI priority="20">http://ma.gnolia.com/oauth/authorize</URI> +    </Service> + +    <!-- Access Token --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/access</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/RSA-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/PLAINTEXT</Type> + +      <URI>https://ma.gnolia.com/oauth/get_access_token</URI> +    </Service> + +    <!-- Protected Resources --> +    <Service> +      <Type>http://oauth.net/core/1.0/endpoint/resource</Type> + +      <Type>http://oauth.net/core/1.0/parameters/auth-header</Type> +      <Type>http://oauth.net/core/1.0/parameters/post-body</Type> +      <Type>http://oauth.net/core/1.0/parameters/uri-query</Type> +      <Type>http://oauth.net/core/1.0/signature/HMAC-SHA1</Type> +      <Type>http://oauth.net/core/1.0/signature/RSA-SHA1</Type> +    </Service> + +    <!-- Consumer Identity --> +     +      <!-- Manual Consumer Identity Allocation --> +      <Service> +        <Type>http://oauth.net/discovery/1.0/consumer-identity/oob</Type> +        <URI>http://ma.gnolia.com/applications/new</URI> +      </Service> +  </XRD> +   +  <!-- Global Resource Definition --> +   +  <XRD xmlns="xri://$XRD*($v*2.0)" version="2.0"> +    <Type>xri://$xrds*simple</Type> +     +    <!-- OAuth Endpoints Definition --> +    <Service priority="10"> +      <Type>http://oauth.net/discovery/1.0</Type> +      <URI>#oauth</URI> +    </Service> +  </XRD> +   +</XRDS>
\ No newline at end of file diff --git a/mod/oauth_api/vendors/oauth/test/oauth_test.php b/mod/oauth_api/vendors/oauth/test/oauth_test.php new file mode 100644 index 000000000..0c0504c70 --- /dev/null +++ b/mod/oauth_api/vendors/oauth/test/oauth_test.php @@ -0,0 +1,188 @@ +<?php + +/** + * Tests of OAuth implementation. + *  + * @version $Id$ + * @author Marc Worrell <marcw@pobox.com> + * @date  Nov 29, 2007 3:46:56 PM + * @see http://wiki.oauth.net/TestCases + *  + * The MIT License + *  + * Copyright (c) 2007-2008 Mediamatic Lab + *  + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +require_once dirname(__FILE__) . '/../library/OAuthRequest.php'; +require_once dirname(__FILE__) . '/../library/OAuthRequester.php'; +require_once dirname(__FILE__) . '/../library/OAuthRequestSigner.php'; +require_once dirname(__FILE__) . '/../library/OAuthRequestVerifier.php'; + +if (!function_exists('getallheaders')) +{ +	function getallheaders() +	{ +		return array(); +	} +} + + +oauth_test(); + +function oauth_test () +{ +	error_reporting(E_ALL); + +	header('Content-Type: text/plain; charset=utf-8'); +	 +	echo "Performing OAuth module tests.\n\n"; +	echo "See also: http://wiki.oauth.net/TestCases\n\n"; +	 +	assert_options(ASSERT_CALLBACK, 'oauth_assert_handler'); +	assert_options(ASSERT_WARNING,  0); +	 +	$req = new OAuthRequest('http://www.example.com', 'GET'); + +	echo "***** Parameter Encoding *****\n\n"; +	 +	assert('$req->urlencode(\'abcABC123\') == \'abcABC123\''); +	assert('$req->urlencode(\'-._~\') == \'-._~\''); +	assert('$req->urlencode(\'%\') == \'%25\''); +	assert('$req->urlencode(\'&=*\') == \'%26%3D%2A\''); +	assert('$req->urlencode(\'&=*\') == \'%26%3D%2A\''); +	assert('$req->urlencode("\n") == \'%0A\''); +	assert('$req->urlencode(" ") == \'%20\''); +	assert('$req->urlencode("\x7f") == \'%7F\''); + + +	echo "***** Normalize Request Parameters *****\n\n"; +	 +	$req = new OAuthRequest('http://example.com/?name', 'GET'); +	assert('$req->getNormalizedParams() == \'name=\''); + +	$req = new OAuthRequest('http://example.com/?a=b', 'GET'); +	assert('$req->getNormalizedParams() == \'a=b\''); +	 +	$req = new OAuthRequest('http://example.com/?a=b&c=d', 'GET'); +	assert('$req->getNormalizedParams() == \'a=b&c=d\''); +	 +	// At this moment we don't support two parameters with the same name +	// so I changed this test case to "a=" and "b=" and not "a=" and "a=" +	$req = new OAuthRequest('http://example.com/?b=x!y&a=x+y', 'GET'); +	assert('$req->getNormalizedParams() == \'a=x%20y&b=x%21y\''); +	 +	$req = new OAuthRequest('http://example.com/?x!y=a&x=a', 'GET'); +	assert('$req->getNormalizedParams() == \'x=a&x%21y=a\''); +	 + +	echo "***** Base String *****\n\n"; +	 +	$req  = new OAuthRequest('http://example.com/?n=v', 'GET'); +	assert('$req->signatureBaseString() == \'GET&http%3A%2F%2Fexample.com%2F&n%3Dv\''); +	 +	$req = new OAuthRequest( +							'https://photos.example.net/request_token',  +							'POST', +							'oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_timestamp=1191242090&oauth_nonce=hsu94j3884jdopsl&oauth_signature_method=PLAINTEXT&oauth_signature=ignored', +							array('X-OAuth-Test' => true)); +	assert('$req->signatureBaseString() == \'POST&https%3A%2F%2Fphotos.example.net%2Frequest_token&oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dhsu94j3884jdopsl%26oauth_signature_method%3DPLAINTEXT%26oauth_timestamp%3D1191242090%26oauth_version%3D1.0\''); + +	$req = new OAuthRequest( +							'http://photos.example.net/photos?file=vacation.jpg&size=original&oauth_version=1.0&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_token=nnch734d00sl2jdk&oauth_timestamp=1191242096&oauth_nonce=kllo9940pd9333jh&oauth_signature=ignored&oauth_signature_method=HMAC-SHA1',  +							'GET'); +	assert('$req->signatureBaseString() == \'GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal\''); + + +	echo "***** HMAC-SHA1 *****\nRequest signing\n"; + +	OAuthStore::instance('MySQL', array('conn'=>false)); +	$req = new OAuthRequestSigner('http://photos.example.net/photos?file=vacation.jpg&size=original', 'GET');	 + +	assert('$req->urldecode($req->calculateDataSignature(\'bs\', \'cs\', \'\',   \'HMAC-SHA1\')) == \'egQqG5AJep5sJ7anhXju1unge2I=\''); +	assert('$req->urldecode($req->calculateDataSignature(\'bs\', \'cs\', \'ts\', \'HMAC-SHA1\')) == \'VZVjXceV7JgPq/dOTnNmEfO0Fv8=\''); +	 +	$secrets = array( +				'consumer_key'		=> 'dpf43f3p2l4k3l03', +				'consumer_secret'	=> 'kd94hf93k423kf44', +				'token'				=> 'nnch734d00sl2jdk', +				'token_secret'		=> 'pfkkdhi9sl3r4s00', +				'signature_methods'	=> array('HMAC-SHA1'), +				'nonce'				=> 'kllo9940pd9333jh', +				'timestamp'			=> '1191242096' +				); +	$req->sign(0, $secrets); +	assert('$req->getParam(\'oauth_signature\', true) == \'tR3+Ty81lMeYAr/Fid0kMTYa/WM=\''); + +	echo "***** HMAC-SHA1 *****\nRequest verification\n"; + +	$req = new OAuthRequestVerifier( +				'http://photos.example.net/photos?file=vacation.jpg&size=original' +				.'&oauth_consumer_key=dpf43f3p2l4k3l03&oauth_token=nnch734d00sl2jdk' +				.'&oauth_signature_method=HMAC-SHA1&oauth_nonce=kllo9940pd9333jh' +				.'&oauth_timestamp=1191242096&oauth_version=1.0' +				.'&oauth_signature='.rawurlencode('tR3+Ty81lMeYAr/Fid0kMTYa/WM=') +				, 'GET'); +	 +	$req->verifySignature('kd94hf93k423kf44', 'pfkkdhi9sl3r4s00'); + +	echo "\n"; +	echo "***** Yahoo! test case ******\n\n"; + +	OAuthStore::instance('MySQL', array('conn'=>false)); +	$req = new OAuthRequestSigner('http://example.com:80/photo', 'GET'); +	 +	$req->setParam('title',   'taken with a 30% orange filter'); +	$req->setParam('file',    'mountain & water view'); +	$req->setParam('format',  'jpeg'); +	$req->setParam('include', array('date','aperture')); + +	$secrets = array( +				'consumer_key'		=> '1234=asdf=4567', +				'consumer_secret'	=> 'erks823*43=asd&123ls%23', +				'token'				=> 'asdf-4354=asew-5698', +				'token_secret'		=> 'dis9$#$Js009%==', +				'signature_methods'	=> array('HMAC-SHA1'), +				'nonce'				=> '3jd834jd9', +				'timestamp'			=> '12303202302' +				); +	$req->sign(0, $secrets); + +	// echo "Basestring:\n",$req->signatureBaseString(), "\n\n"; + +	//echo "queryString:\n",$req->getQueryString(), "\n\n"; +	assert('$req->getQueryString() == \'title=taken%20with%20a%2030%25%20orange%20filter&file=mountain%20%26%20water%20view&format=jpeg&include=date&include=aperture\'');	 + +	//echo "oauth_signature:\n",$req->getParam('oauth_signature', true),"\n\n"; +	assert('$req->getParam(\'oauth_signature\', true) == \'jMdUSR1vOr3SzNv3gZ5DDDuGirA=\''); +	 +	echo "\n\nFinished.\n"; +} + + +function oauth_assert_handler ( $file, $line, $code ) +{ +	echo "\nAssertion failed in $file:$line +   $code\n\n"; +} + +/* vi:set ts=4 sts=4 sw=4 binary noeol: */ + +?>
\ No newline at end of file | 
