Update to last upstream version of libomb: coding style updates, static call fix, improved handling of invalid XRD URIs.

This commit is contained in:
Brion Vibber 2010-06-29 14:39:57 -04:00
parent c038164c0f
commit 15b1d130d2
16 changed files with 2072 additions and 1792 deletions

View File

@ -1,14 +1,6 @@
<?php <?php
require_once 'xrds_mapper.php';
require_once 'constants.php';
/** /**
* Map XRDS actions to URLs using base URLs. * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -25,27 +17,56 @@ require_once 'constants.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper { require_once 'xrds_mapper.php';
require_once 'constants.php';
protected $urls; /**
* Map XRDS actions to URLs using base URLs
*
* This class realizes a simple mapping of action URIs to handler URLs. The
* target URLs are constructed using a base URL.
*/
class OMB_Base_URL_XRDS_Mapper implements OMB_XRDS_Mapper
{
protected $urls;
public function __construct($oauth_base, $omb_base) { /**
$this->urls = array( * Constructor
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken', *
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization', * Initialize the XRDS mapper with base URLs for OAuth and OMB endpoints.
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken', *
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice', * @param string $oauth_base The base URL for OAuth endpoints
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile'); * @param string $omb_base The base URL for OMB endpoints
} */
public function __construct($oauth_base, $omb_base)
{
$this->urls = array(
OAUTH_ENDPOINT_REQUEST => $oauth_base . 'requesttoken',
OAUTH_ENDPOINT_AUTHORIZE => $oauth_base . 'userauthorization',
OAUTH_ENDPOINT_ACCESS => $oauth_base . 'accesstoken',
OMB_ENDPOINT_POSTNOTICE => $omb_base . 'postnotice',
OMB_ENDPOINT_UPDATEPROFILE => $omb_base . 'updateprofile');
}
public function getURL($action) { /**
return $this->urls[$action]; * Fetch an URL for a specified action
} *
* Returns the action URL for an action specified by the endpoint URI.
*
* @param string $action The endpoint URI
*
* @return string The action URL
*/
public function getURL($action)
{
return $this->urls[$action];
}
} }
?> ?>

View File

@ -20,15 +20,16 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
/** /**
* The OMB constants. * The OMB constants.
**/ */
define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1'); define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
@ -40,7 +41,7 @@ define('OMB_ENDPOINT_POSTNOTICE', OMB_VERSION . '/postNotice');
/** /**
* The OAuth constants. * The OAuth constants.
**/ */
define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/'); define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');

View File

@ -1,4 +1,28 @@
<?php <?php
/**
* This file is part of libomb
*
* PHP version 5
*
* LICENSE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @version 0.1a-20090828
* @link http://adrianlang.de/libomb
*/
require_once 'OAuth.php'; require_once 'OAuth.php';
@ -27,174 +51,162 @@ require_once 'OAuth.php';
* Most of the parameters passed to these methods are unescaped and unverified * Most of the parameters passed to these methods are unescaped and unverified
* user input. Therefore they should be handled with extra care to avoid * user input. Therefore they should be handled with extra care to avoid
* security problems like SQL injections. * security problems like SQL injections.
* */
* PHP version 5 class OMB_Datastore extends OAuthDataStore
* {
* LICENSE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package OMB
* @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
**/
class OMB_Datastore extends OAuthDataStore { /*********
* OAUTH *
*********/
/********* /**
* OAUTH * * Revoke specified OAuth token
*********/ *
* Revokes the authorization token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key The key of the token to be revoked
*
* @access public
*/
public function revoke_token($token_key)
{
throw new Exception();
}
/** /**
* Revoke specified OAuth token * Authorize specified OAuth token
* *
* Revokes the authorization token specified by $token_key. * Authorizes the authorization token specified by $token_key.
* Throws exceptions in case of error. * Throws exceptions in case of error.
* *
* @param string $token_key The key of the token to be revoked * @param string $token_key The key of the token to be authorized
* *
* @access public * @access public
**/ */
public function revoke_token($token_key) { public function authorize_token($token_key)
throw new Exception(); {
} throw new Exception();
}
/** /*********
* Authorize specified OAuth token * OMB *
* *********/
* Authorizes the authorization token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key The key of the token to be authorized
*
* @access public
**/
public function authorize_token($token_key) {
throw new Exception();
}
/********* /**
* OMB * * Get profile by identifying URI
*********/ *
* Returns an OMB_Profile object representing the OMB profile identified by
* $identifier_uri.
* Returns null if there is no such OMB profile.
* Throws exceptions in case of other error.
*
* @param string $identifier_uri The OMB identifier URI specifying the
* requested profile
*
* @access public
*
* @return OMB_Profile The corresponding profile
*/
public function getProfile($identifier_uri)
{
throw new Exception();
}
/** /**
* Get profile by identifying URI * Save passed profile
* *
* Returns an OMB_Profile object representing the OMB profile identified by * Stores the OMB profile $profile. Overwrites an existing entry.
* $identifier_uri. * Throws exceptions in case of error.
* Returns null if there is no such OMB profile. *
* Throws exceptions in case of other error. * @param OMB_Profile $profile The OMB profile which should be saved
* *
* @param string $identifier_uri The OMB identifier URI specifying the * @access public
* requested profile */
* public function saveProfile($profile)
* @access public {
* throw new Exception();
* @return OMB_Profile The corresponding profile }
**/
public function getProfile($identifier_uri) {
throw new Exception();
}
/** /**
* Save passed profile * Save passed notice
* *
* Stores the OMB profile $profile. Overwrites an existing entry. * Stores the OMB notice $notice. The datastore may change the passed
* Throws exceptions in case of error. * notice. This might by necessary for URIs depending on a database key.
* * Note that it is the users duty to present a mechanism for his
* @param OMB_Profile $profile The OMB profile which should be saved * OMB_Datastore to appropriately change his OMB_Notice.
* * Throws exceptions in case of error.
* @access public *
**/ * @param OMB_Notice &$notice The OMB notice which should be saved
public function saveProfile($profile) { *
throw new Exception(); * @access public
} */
public function saveNotice(&$notice)
{
throw new Exception();
}
/** /**
* Save passed notice * Get subscriptions of a given profile
* *
* Stores the OMB notice $notice. The datastore may change the passed notice. * Returns an array containing subscription informations for the specified
* This might by neccessary for URIs depending on a database key. Note that * profile. Every array entry should in turn be an array with keys
* it is the users duty to present a mechanism for his OMB_Datastore to * 'uri´: The identifier URI of the subscriber
* appropriately change his OMB_Notice. TODO: Ugly. * 'token´: The subscribe token
* Throws exceptions in case of error. * 'secret´: The secret token
* * Throws exceptions in case of error.
* @param OMB_Notice $notice The OMB notice which should be saved *
* * @param string $subscribed_user_uri The OMB identifier URI specifying the
* @access public * subscribed profile
**/ *
public function saveNotice(&$notice) { * @access public
throw new Exception(); *
} * @return mixed An array containing the subscriptions or 0 if no
* subscription has been found.
*/
public function getSubscriptions($subscribed_user_uri)
{
throw new Exception();
}
/** /**
* Get subscriptions of a given profile * Delete a subscription
* *
* Returns an array containing subscription informations for the specified * Deletes the subscription from $subscriber_uri to $subscribed_user_uri.
* profile. Every array entry should in turn be an array with keys * Throws exceptions in case of error.
* 'uri´: The identifier URI of the subscriber *
* 'token´: The subscribe token * @param string $subscriber_uri The OMB identifier URI specifying the
* 'secret´: The secret token * subscribing profile
* Throws exceptions in case of error. *
* * @param string $subscribed_user_uri The OMB identifier URI specifying the
* @param string $subscribed_user_uri The OMB identifier URI specifying the * subscribed profile
* subscribed profile *
* * @access public
* @access public */
* public function deleteSubscription($subscriber_uri, $subscribed_user_uri)
* @return mixed An array containing the subscriptions or 0 if no {
* subscription has been found. throw new Exception();
**/ }
public function getSubscriptions($subscribed_user_uri) {
throw new Exception();
}
/** /**
* Delete a subscription * Save a subscription
* *
* Deletes the subscription from $subscriber_uri to $subscribed_user_uri. * Saves the subscription from $subscriber_uri to $subscribed_user_uri.
* Throws exceptions in case of error. * Throws exceptions in case of error.
* *
* @param string $subscriber_uri The OMB identifier URI specifying the * @param string $subscriber_uri The OMB identifier URI specifying
* subscribing profile * the subscribing profile
* *
* @param string $subscribed_user_uri The OMB identifier URI specifying the * @param string $subscribed_user_uri The OMB identifier URI specifying
* subscribed profile * the subscribed profile
* * @param OAuthToken $token The access token
* @access public *
**/ * @access public
public function deleteSubscription($subscriber_uri, $subscribed_user_uri) { */
throw new Exception(); public function saveSubscription($subscriber_uri, $subscribed_user_uri,
} $token)
{
/** throw new Exception();
* Save a subscription }
*
* Saves the subscription from $subscriber_uri to $subscribed_user_uri.
* Throws exceptions in case of error.
*
* @param string $subscriber_uri The OMB identifier URI specifying
* the subscribing profile
*
* @param string $subscribed_user_uri The OMB identifier URI specifying
* the subscribed profile
* @param OAuthToken $token The access token
*
* @access public
**/
public function saveSubscription($subscriber_uri, $subscribed_user_uri,
$token) {
throw new Exception();
}
} }
?> ?>

View File

@ -1,11 +1,6 @@
<?php <?php
require_once 'Validate.php';
/** /**
* Helper functions for libomb * This file is part of libomb
*
* This file contains helper functions for libomb.
* *
* PHP version 5 * PHP version 5
* *
@ -22,78 +17,88 @@ require_once 'Validate.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Helper { require_once 'Validate.php';
/** /**
* Non-scalar constants * Helper functions for libomb
* *
* The set of OMB and OAuth Services an OMB Server has to implement. * This class contains helper functions for libomb.
*/ */
class OMB_Helper
{
public static $OMB_SERVICES = /**
array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE); * Non-scalar constants
public static $OAUTH_SERVICES = *
array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE, OAUTH_ENDPOINT_ACCESS); * The set of OMB and OAuth Services an OMB Server has to implement.
*/
/** public static $OMB_SERVICES = array(OMB_ENDPOINT_UPDATEPROFILE,
* Validate URL OMB_ENDPOINT_POSTNOTICE);
* public static $OAUTH_SERVICES = array(OAUTH_ENDPOINT_REQUEST,
* Basic URL validation. Currently http, https, ftp and gopher are supported OAUTH_ENDPOINT_AUTHORIZE,
* schemes. OAUTH_ENDPOINT_ACCESS);
*
* @param string $url The URL which is to be validated.
*
* @return bool Whether URL is valid.
*
* @access public
*/
public static function validateURL($url) {
return Validate::uri($url, array('allowed_schemes' => array('http', 'https',
'gopher', 'ftp')));
}
/** /**
* Validate Media type * Validate URL
* *
* Basic Media type validation. Checks for valid maintype and correct format. * Basic URL validation. Currently http, https, ftp and gopher are supported
* * schemes.
* @param string $mediatype The Media type which is to be validated. *
* * @param string $url The URL which is to be validated.
* @return bool Whether media type is valid. *
* * @return bool Whether URL is valid.
* @access public *
*/ * @access public
public static function validateMediaType($mediatype) { */
if (0 === preg_match('/^(\w+)\/([\w\d-+.]+)$/', $mediatype, $subtypes)) { public static function validateURL($url)
return false; {
return Validate::uri($url, array('allowed_schemes' => array('http',
'https', 'gopher', 'ftp')));
} }
if (!in_array(strtolower($subtypes[1]), array('application', 'audio', 'image',
'message', 'model', 'multipart', 'text', 'video'))) {
return false;
}
return true;
}
/** /**
* Remove escaping from request parameters * Validate Media type
* *
* Neutralise the evil effects of magic_quotes_gpc in the current request. * Basic Media type validation. Checks for valid maintype and correct
* This is used before handing a request off to OAuthRequest::from_request. * format.
* Many thanks to Ciaran Gultnieks for this fix. *
* * @param string $mediatype The Media type which is to be validated.
* @access public *
*/ * @return bool Whether media type is valid.
public static function removeMagicQuotesFromRequest() { *
if(get_magic_quotes_gpc() == 1) { * @access public
$_POST = array_map('stripslashes', $_POST); */
$_GET = array_map('stripslashes', $_GET); public static function validateMediaType($mediatype)
{
return preg_match('/^(\w+)\/([\w\d-+.]+)$/', $mediatype, $subtypes) > 0
&&
in_array(strtolower($subtypes[1]), array('application', 'audio',
'image', 'message', 'model', 'multipart', 'text', 'video'));
}
/**
* Remove escaping from request parameters
*
* Neutralise the evil effects of magic_quotes_gpc in the current request.
* This is used before handing a request off to OAuthRequest::from_request.
* Many thanks to Ciaran Gultnieks for this fix.
*
* @access public
*/
public static function removeMagicQuotesFromRequest()
{
if (get_magic_quotes_gpc() === 1) {
$_POST = array_map('stripslashes', $_POST);
$_GET = array_map('stripslashes', $_GET);
}
} }
}
} }
?> ?>

View File

@ -1,8 +1,6 @@
<?php <?php
/** /**
* Exception stating that a passed parameter is invalid * This file is part of libomb
*
* This exception is raised when a parameter does not obey the OMB standard.
* *
* PHP version 5 * PHP version 5
* *
@ -19,14 +17,36 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_InvalidParameterException extends Exception { */
public function __construct($value, $type, $parameter) {
parent::__construct("Invalid value $value for parameter $parameter in $type"); /**
} * Exception stating that a passed parameter is invalid
*
* This exception is raised when a parameter does not obey the OMB standard.
*/
class OMB_InvalidParameterException extends Exception
{
/**
* Constructor
*
* Creates a new exception based on a parameter name, value, and object
* type.
*
* @param string $value The wrong value passed
* @param string $type The object type the parameter belongs to;
* Currently OMB uses profiles and notices
* @param string $parameter The name of the parameter the wrong value has
* been passed for
*/
public function __construct($value, $type, $parameter)
{
parent::__construct("Invalid value ${value} for parameter " .
"${parameter} in $type");
}
} }
?> ?>

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that a requested url does not resolve to a valid yadis * This file is part of libomb
*
* This exception is raised when OMB_Service is not able to discover a valid
* yadis location with XRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -20,12 +17,21 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_InvalidYadisException extends Exception { */
/**
* Exception stating that a requested url does not resolve to a valid yadis
*
* This exception is raised when OMB_Service is not able to discover a valid
* yadis location with XRDS.
*/
class OMB_InvalidYadisException extends Exception
{
} }
?> ?>

View File

@ -1,15 +1,6 @@
<?php <?php
require_once 'invalidparameterexception.php';
require_once 'Validate.php';
require_once 'helper.php';
/** /**
* OMB Notice representation * This file is part of libomb
*
* This class represents an OMB notice.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
* *
* PHP version 5 * PHP version 5
* *
@ -26,247 +17,278 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Notice { require_once 'invalidparameterexception.php';
protected $author; require_once 'Validate.php';
protected $uri; require_once 'helper.php';
protected $content;
protected $url;
protected $license_url; /* url is an own addition for clarification. */
protected $seealso_url; /* url is an own addition for clarification. */
protected $seealso_disposition;
protected $seealso_mediatype;
protected $seealso_license_url; /* url is an addition for clarification. */
/* The notice as OMB param array. Cached and rebuild on usage. /**
false while outdated. */ * OMB Notice representation
protected $param_array; *
* This class represents an OMB notice.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
*/
class OMB_Notice
{
protected $author;
protected $uri;
protected $content;
protected $url;
protected $license_url; /* url is an own addition for clarification. */
protected $seealso_url; /* url is an own addition for clarification. */
protected $seealso_disposition;
protected $seealso_mediatype;
protected $seealso_license_url; /* url is an addition for clarification. */
/** /* The notice as OMB param array. Cached and rebuild on usage.
* Constructor for OMB_Notice false while outdated. */
* protected $param_array;
* Initializes the OMB_Notice object with author, uri and content.
* These parameters are mandatory for postNotice.
*
* @param object $author An OMB_Profile object representing the author of the
* notice.
* @param string $uri The notice URI as defined by the OMB. A unique and
* unchanging identifier for a notice.
* @param string $content The content of the notice. 140 chars recommended,
* but there is no limit.
*
* @access public
*/
public function __construct($author, $uri, $content) {
$this->content = $content;
if (is_null($author)) {
throw new OMB_InvalidParameterException('', 'notice', 'omb_listenee');
}
$this->author = $author;
if (!Validate::uri($uri)) { /**
throw new OMB_InvalidParameterException($uri, 'notice', 'omb_notice'); * Constructor for OMB_Notice
} *
$this->uri = $uri; * Initializes the OMB_Notice object with author, uri and content.
* These parameters are mandatory for postNotice.
*
* @param object $author An OMB_Profile object representing the author of
* the notice.
* @param string $uri The notice URI as defined by the OMB. A unique and
* never changing identifier for a notice.
* @param string $content The content of the notice. 140 chars recommended,
* but there is no limit.
*
* @access public
*/
public function __construct($author, $uri, $content)
{
$this->content = $content;
if (is_null($author)) {
throw new OMB_InvalidParameterException('', 'notice', 'omb_listenee');
}
$this->author = $author;
$this->param_array = false; if (!Validate::uri($uri)) {
} throw new OMB_InvalidParameterException($uri, 'notice', 'omb_notice');
}
$this->uri = $uri;
/** $this->param_array = false;
* Returns the notice as array
*
* The method returns an array which contains the whole notice as array. The
* array is cached and only rebuilt on changes of the notice.
* Empty optional values are not passed.
*
* @access public
* @returns array The notice as parameter array
*/
public function asParameters() {
if ($this->param_array !== false) {
return $this->param_array;
} }
$this->param_array = array( /**
'omb_notice' => $this->uri, * Return the notice as array
'omb_notice_content' => $this->content); *
* Returns an array which contains the whole notice as array. The array is
* cached and only rebuilt on changes of the notice.
* Empty optional values are not passed.
*
* @access public
* @return array The notice as parameter array
*/
public function asParameters()
{
if ($this->param_array !== false) {
return $this->param_array;
}
if (!is_null($this->url)) $this->param_array = array(
$this->param_array['omb_notice_url'] = $this->url; 'omb_notice' => $this->uri,
'omb_notice_content' => $this->content);
if (!is_null($this->license_url)) if (!is_null($this->url))
$this->param_array['omb_notice_license'] = $this->license_url; $this->param_array['omb_notice_url'] = $this->url;
if (!is_null($this->seealso_url)) { if (!is_null($this->license_url))
$this->param_array['omb_seealso'] = $this->seealso_url; $this->param_array['omb_notice_license'] = $this->license_url;
/* This is actually a free interpretation of the OMB standard. We assume if (!is_null($this->seealso_url)) {
that additional seealso parameters are not of any use if seealso itself $this->param_array['omb_seealso'] = $this->seealso_url;
is not set. */
if (!is_null($this->seealso_disposition)) /* This is actually a free interpretation of the OMB standard. We
$this->param_array['omb_seealso_disposition'] = assume that additional seealso parameters are not of any use if
seealso itself is not set. */
if (!is_null($this->seealso_disposition))
$this->param_array['omb_seealso_disposition'] =
$this->seealso_disposition; $this->seealso_disposition;
if (!is_null($this->seealso_mediatype)) if (!is_null($this->seealso_mediatype))
$this->param_array['omb_seealso_mediatype'] = $this->seealso_mediatype; $this->param_array['omb_seealso_mediatype'] =
$this->seealso_mediatype;
if (!is_null($this->seealso_license_url)) if (!is_null($this->seealso_license_url))
$this->param_array['omb_seealso_license'] = $this->seealso_license_url; $this->param_array['omb_seealso_license'] =
} $this->seealso_license_url;
return $this->param_array; }
} return $this->param_array;
/**
* Builds an OMB_Notice object from array
*
* The method builds an OMB_Notice object from the passed parameters array.
* The array MUST provide a notice URI and content. The array fields HAVE TO
* be named according to the OMB standard, i. e. omb_notice_* and
* omb_seealso_*. Values are handled as not passed if the corresponding array
* fields are not set or the empty string.
*
* @param object $author An OMB_Profile object representing the author of
* the notice.
* @param string $parameters An array containing the notice parameters.
*
* @access public
*
* @returns OMB_Notice The built OMB_Notice.
*/
public static function fromParameters($author, $parameters) {
$notice = new OMB_Notice($author, $parameters['omb_notice'],
$parameters['omb_notice_content']);
if (isset($parameters['omb_notice_url'])) {
$notice->setURL($parameters['omb_notice_url']);
} }
if (isset($parameters['omb_notice_license'])) { /**
$notice->setLicenseURL($parameters['omb_notice_license']); * Build an OMB_Notice object from array
*
* Builds an OMB_Notice object from the passed parameters array. The array
* MUST provide a notice URI and content. The array fields HAVE TO be named
* according to the OMB standard, i. e. omb_notice_* and omb_seealso_*.
* Values are handled as not passed if the corresponding array fields are
* not set or the empty string.
*
* @param object $author An OMB_Profile object representing the author
* of the notice.
* @param string $parameters An array containing the notice parameters.
*
* @access public
*
* @returns OMB_Notice The built OMB_Notice.
*/
public static function fromParameters($author, $parameters)
{
$notice = new OMB_Notice($author, $parameters['omb_notice'],
$parameters['omb_notice_content']);
if (isset($parameters['omb_notice_url'])) {
$notice->setURL($parameters['omb_notice_url']);
}
if (isset($parameters['omb_notice_license'])) {
$notice->setLicenseURL($parameters['omb_notice_license']);
}
if (isset($parameters['omb_seealso'])) {
$notice->setSeealsoURL($parameters['omb_seealso']);
}
if (isset($parameters['omb_seealso_disposition'])) {
$notice->setSeealsoDisposition($parameters['omb_seealso_disposition']);
}
if (isset($parameters['omb_seealso_mediatype'])) {
$notice->setSeealsoMediatype($parameters['omb_seealso_mediatype']);
}
if (isset($parameters['omb_seealso_license'])) {
$notice->setSeealsoLicenseURL($parameters['omb_seealso_license']);
}
return $notice;
} }
if (isset($parameters['omb_seealso'])) { public function getAuthor()
$notice->setSeealsoURL($parameters['omb_seealso']); {
return $this->author;
} }
if (isset($parameters['omb_seealso_disposition'])) { public function getIdentifierURI()
$notice->setSeealsoDisposition($parameters['omb_seealso_disposition']); {
return $this->uri;
} }
if (isset($parameters['omb_seealso_mediatype'])) { public function getContent()
$notice->setSeealsoMediatype($parameters['omb_seealso_mediatype']); {
return $this->content;
} }
if (isset($parameters['omb_seealso_license'])) { public function getURL()
$notice->setSeealsoLicenseURL($parameters['omb_seealso_license']); {
return $this->url;
} }
return $notice;
}
public function getAuthor() { public function getLicenseURL()
return $this->author; {
} return $this->license_url;
public function getIdentifierURI() {
return $this->uri;
}
public function getContent() {
return $this->content;
}
public function getURL() {
return $this->url;
}
public function getLicenseURL() {
return $this->license_url;
}
public function getSeealsoURL() {
return $this->seealso_url;
}
public function getSeealsoDisposition() {
return $this->seealso_disposition;
}
public function getSeealsoMediatype() {
return $this->seealso_mediatype;
}
public function getSeealsoLicenseURL() {
return $this->seealso_license_url;
}
public function setURL($url) {
if ($url === '') {
$url = null;
} elseif (!OMB_Helper::validateURL($url)) {
throw new OMB_InvalidParameterException($url, 'notice', 'omb_notice_url');
} }
$this->url = $url;
$this->param_array = false;
}
public function setLicenseURL($license_url) { public function getSeealsoURL()
if ($license_url === '') { {
$license_url = null; return $this->seealso_url;
} elseif (!OMB_Helper::validateURL($license_url)) {
throw new OMB_InvalidParameterException($license_url, 'notice',
'omb_notice_license');
} }
$this->license_url = $license_url;
$this->param_array = false;
}
public function setSeealsoURL($seealso_url) { public function getSeealsoDisposition()
if ($seealso_url === '') { {
$seealso_url = null; return $this->seealso_disposition;
} elseif (!OMB_Helper::validateURL($seealso_url)) {
throw new OMB_InvalidParameterException($seealso_url, 'notice',
'omb_seealso');
} }
$this->seealso_url = $seealso_url;
$this->param_array = false;
}
public function setSeealsoDisposition($seealso_disposition) { public function getSeealsoMediatype()
if ($seealso_disposition === '') { {
$seealso_disposition = null; return $this->seealso_mediatype;
} elseif ($seealso_disposition !== 'link' && $seealso_disposition !== 'inline') {
throw new OMB_InvalidParameterException($seealso_disposition, 'notice',
'omb_seealso_disposition');
} }
$this->seealso_disposition = $seealso_disposition;
$this->param_array = false;
}
public function setSeealsoMediatype($seealso_mediatype) { public function getSeealsoLicenseURL()
if ($seealso_mediatype === '') { {
$seealso_mediatype = null; return $this->seealso_license_url;
} elseif (!OMB_Helper::validateMediaType($seealso_mediatype)) {
throw new OMB_InvalidParameterException($seealso_mediatype, 'notice',
'omb_seealso_mediatype');
} }
$this->seealso_mediatype = $seealso_mediatype;
$this->param_array = false;
}
public function setSeealsoLicenseURL($seealso_license_url) { public function setURL($url)
if ($seealso_license_url === '') { {
$seealso_license_url = null; $this->setVal('notice_url', $url, 'OMB_Helper::validateURL', 'url');
} elseif (!OMB_Helper::validateURL($seealso_license_url)) { }
throw new OMB_InvalidParameterException($seealso_license_url, 'notice',
'omb_seealso_license'); public function setLicenseURL($license_url)
{
$this->setVal('license', $license_url, 'OMB_Helper::validateURL',
'license_url');
}
public function setSeealsoURL($seealso_url)
{
$this->setVal('seealso', $seealso_url, 'OMB_Helper::validateURL',
'seealso_url');
}
public function setSeealsoDisposition($seealso_disposition)
{
$this->setVal('seealso_disposition', $seealso_disposition,
'OMB_Notice::validateDisposition');
}
protected static function validateDisposition($str)
{
return in_array($str, array('link', 'inline'));
}
public function setSeealsoMediatype($seealso_mediatype)
{
$this->setVal('seealso_mediatype', $seealso_mediatype,
'OMB_Helper::validateMediaType');
}
public function setSeealsoLicenseURL($seealso_license_url)
{
$this->setVal('seealso_license', $seealso_license_url,
'OMB_Helper::validateURL', 'seealso_license_url');
}
/**
* Set a value
*
* Updates a value specified by a parameter name and the new value.
*
* @param string $param The parameter name according to OMB
* @param string $value The new value
* @param callback $validator A validator function for the parameter
* @param string $field The name of the field in OMB_Notice
* @param bool $force Whether null values should be checked as well
*/
protected function setVal($param, $value, $validator, $field = null,
$force = false)
{
if (is_null($field)) {
$field = $param;
}
if ($value === '' && !$force) {
$value = null;
} elseif (!call_user_func($validator, $value)) {
throw new OMB_InvalidParameterException($value, 'notice', $param);
}
if ($this->$field !== $value) {
$this->$field = $value;
$this->param_array = false;
}
} }
$this->seealso_license_url = $seealso_license_url;
$this->param_array = false;
}
} }
?> ?>

View File

@ -1,14 +1,6 @@
<?php <?php
require_once 'Auth/Yadis/Yadis.php';
require_once 'unsupportedserviceexception.php';
require_once 'invalidyadisexception.php';
/** /**
* OMB XRDS representation * This file is part of libomb
*
* This class represents a Yadis XRDS file for OMB. It adds some useful methods to
* Auth_Yadis_XRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -25,172 +17,193 @@ require_once 'invalidyadisexception.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Yadis_XRDS extends Auth_Yadis_XRDS { require_once 'Auth/Yadis/Yadis.php';
require_once 'unsupportedserviceexception.php';
require_once 'invalidyadisexception.php';
protected $fetcher; /**
* OMB XRDS representation
*
* This class represents a Yadis XRDS file for OMB. It adds some useful methods to
* Auth_Yadis_XRDS.
*/
class OMB_Yadis_XRDS extends Auth_Yadis_XRDS
{
/** protected $fetcher;
* Create an instance from URL
* /**
* Constructs an OMB_Yadis_XRDS object from a given URL. A full Yadis * Create an instance from URL
* discovery is performed on the URL and the XRDS is parsed. *
* Throws an OMB_InvalidYadisException when no Yadis is discovered or the * Constructs an OMB_Yadis_XRDS object from a given URL. A full Yadis
* detected XRDS file is broken. * discovery is performed on the URL and the XRDS is parsed.
* * Throws an OMB_InvalidYadisException when no Yadis is discovered or the
* @param string $url The URL on which Yadis discovery * detected XRDS file is broken.
* should be performed on *
* @param Auth_Yadis_HTTPFetcher $fetcher A fetcher used to get HTTP * @param string $url The URL on which Yadis discovery
* resources * should be performed on
* * @param Auth_Yadis_HTTPFetcher $fetcher A fetcher used to get HTTP
* @access public * resources
* *
* @return OMB_Yadis_XRDS The initialized object representing the given * @access public
* resource *
**/ * @return OMB_Yadis_XRDS The initialized object representing the given
public static function fromYadisURL($url, $fetcher) { * resource
/* Perform a Yadis discovery. */ */
$yadis = Auth_Yadis_Yadis::discover($url, $fetcher); public static function fromYadisURL($url, $fetcher)
if ($yadis->failed) { {
throw new OMB_InvalidYadisException($url); /* Perform a Yadis discovery. */
$yadis = Auth_Yadis_Yadis::discover($url, $fetcher);
if ($yadis->failed) {
throw new OMB_InvalidYadisException($url);
}
/* Parse the XRDS file. */
$xrds = OMB_Yadis_XRDS::parseXRDS($yadis->response_text);
if ($xrds === null) {
throw new OMB_InvalidYadisException($url);
}
$xrds->fetcher = $fetcher;
return $xrds;
} }
/* Parse the XRDS file. */ /**
$xrds = OMB_Yadis_XRDS::parseXRDS($yadis->response_text); * Get a specific service
if ($xrds === null) { *
throw new OMB_InvalidYadisException($url); * Returns the Auth_Yadis_Service object corresponding to the given service
} * URI.
$xrds->fetcher = $fetcher; * Throws an OMB_UnsupportedServiceException if the service is not
return $xrds; * available.
} *
* @param string $service URI specifier of the requested service
/** *
* Get a specific service * @access public
* *
* Returns the Auth_Yadis_Service object corresponding to the given service * @return Auth_Yadis_Service The object representing the requested service
* URI. */
* Throws an OMB_UnsupportedServiceException if the service is not available. public function getService($service)
* {
* @param string $service URI specifier of the requested service $match = $this->services(array(create_function('$s',
* "return in_array('$service', \$s->getTypes());")));
* @access public if ($match === array()) {
* throw new OMB_UnsupportedServiceException($service);
* @return Auth_Yadis_Service The object representing the requested service }
**/ return $match[0];
public function getService($service) {
$match = $this->services(array( create_function('$s',
"return in_array('$service', \$s->getTypes());")));
if ($match === array()) {
throw new OMB_UnsupportedServiceException($service);
}
return $match[0];
}
/**
* Get a specific XRD
*
* Returns the OMB_Yadis_XRDS object corresponding to the given URI.
* Throws an OMB_UnsupportedServiceException if the XRD is not available.
* Note that getXRD tries to resolve external XRD parts as well.
*
* @param string $uri URI specifier of the requested XRD
*
* @access public
*
* @return OMB_Yadis_XRDS The object representing the requested XRD
**/
public function getXRD($uri) {
$nexthash = strpos($uri, '#');
if ($nexthash !== 0) {
if ($nexthash !== false) {
$cururi = substr($uri, 0, $nexthash);
$nexturi = substr($uri, $nexthash);
}
return
OMB_Yadis_XRDS::fromYadisURL($cururi, $this->fetcher)->getXRD($nexturi);
} }
$id = substr($uri, 1); /**
foreach ($this->allXrdNodes as $node) { * Get a specific XRD
$attrs = $this->parser->attributes($node); *
if (array_key_exists('xml:id', $attrs) && $attrs['xml:id'] == $id) { * Returns the OMB_Yadis_XRDS object corresponding to the given URI.
/* Trick the constructor into thinking this is the only node. */ * Throws an OMB_UnsupportedServiceException if the XRD is not available.
$bogus_nodes = array($node); * Note that getXRD tries to resolve external XRD parts as well.
return new OMB_Yadis_XRDS($this->parser, $bogus_nodes); *
} * @param string $uri URI specifier of the requested XRD
} *
throw new OMB_UnsupportedServiceException($uri); * @access public
} *
* @return OMB_Yadis_XRDS The object representing the requested XRD
*/
public function getXRD($uri)
{
$nexthash = strpos($uri, '#');
if ($nexthash === false) {
throw new OMB_InvalidYadisException("$uri does not specify a " .
'valid XML node.');
}
/** if ($nexthash > 0) {
* Parse an XML string containing a XRDS document $cururi = substr($uri, 0, $nexthash);
* $nexturi = substr($uri, $nexthash);
* Parse an XML string (XRDS document) and return either a return OMB_Yadis_XRDS::fromYadisURL($cururi, $this->fetcher)
* Auth_Yadis_XRDS object or null, depending on whether the ->getXRD($nexturi);
* XRDS XML is valid. }
* Copy and paste from parent to select correct constructor.
*
* @param string $xml_string An XRDS XML string.
*
* @access public
*
* @return mixed An instance of OMB_Yadis_XRDS or null,
* depending on the validity of $xml_string
**/
public function &parseXRDS($xml_string, $extra_ns_map = null) { $id = substr($uri, 1);
$_null = null; foreach ($this->allXrdNodes as $node) {
$attrs = $this->parser->attributes($node);
if (!$xml_string) { if (array_key_exists('xml:id', $attrs) && $attrs['xml:id'] == $id) {
return $_null; /* Trick the constructor into thinking this is the only node. */
$bogus_nodes = array($node);
return new OMB_Yadis_XRDS($this->parser, $bogus_nodes);
}
}
throw new OMB_UnsupportedServiceException($uri);
} }
$parser = Auth_Yadis_getXMLParser(); /**
* Parse an XML string containing a XRDS document
*
* Parses an XML string (XRDS document) and returns either an
* Auth_Yadis_XRDS object or null, depending on whether the XRDS XML is
* valid.
* This method is just copy and paste from the parent class to select the
* correct constructor.
*
* @param string $xml_string An XRDS XML string
* @param array $extra_ns_map Additional namespace declarations
*
* @access public
*
* @return mixed An instance of OMB_Yadis_XRDS or null,
* depending on the validity of $xml_string
*/
public function parseXRDS($xml_string, $extra_ns_map = null)
{
$_null = null;
$ns_map = Auth_Yadis_getNSMap(); if (!$xml_string) {
return $_null;
}
if ($extra_ns_map && is_array($extra_ns_map)) { $parser = Auth_Yadis_getXMLParser();
$ns_map = array_merge($ns_map, $extra_ns_map);
$ns_map = Auth_Yadis_getNSMap();
if ($extra_ns_map && is_array($extra_ns_map)) {
$ns_map = array_merge($ns_map, $extra_ns_map);
}
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
if (is_array($root)) {
$root = $root[0];
}
$attrs = $parser->attributes($root);
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
return $_null;
}
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
if (!$xrd_nodes) {
return $_null;
}
$xrds = new OMB_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
} }
if (!($parser && $parser->init($xml_string, $ns_map))) {
return $_null;
}
// Try to get root element.
$root = $parser->evalXPath('/xrds:XRDS[1]');
if (!$root) {
return $_null;
}
if (is_array($root)) {
$root = $root[0];
}
$attrs = $parser->attributes($root);
if (array_key_exists('xmlns:xrd', $attrs) &&
$attrs['xmlns:xrd'] != Auth_Yadis_XMLNS_XRDS) {
return $_null;
} else if (array_key_exists('xmlns', $attrs) &&
preg_match('/xri/', $attrs['xmlns']) &&
$attrs['xmlns'] != Auth_Yadis_XMLNS_XRD_2_0) {
return $_null;
}
// Get the last XRD node.
$xrd_nodes = $parser->evalXPath('/xrds:XRDS[1]/xrd:XRD');
if (!$xrd_nodes) {
return $_null;
}
$xrds = new OMB_Yadis_XRDS($parser, $xrd_nodes);
return $xrds;
}
} }

View File

@ -1,13 +1,6 @@
<?php <?php
require_once 'xrds_writer.php';
/** /**
* Write OMB-specific XRDS using XMLWriter. * This file is part of libomb
*
* This class writes the XRDS file announcing the OMB server. It uses
* OMB_XMLWriter, which is a subclass of XMLWriter. An instance of
* OMB_Plain_XRDS_Writer should be passed to OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -24,25 +17,45 @@ require_once 'xrds_writer.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer { require_once 'xrds_writer.php';
public function writeXRDS($user, $mapper) {
header('Content-Type: application/xrds+xml');
$xw = new XMLWriter();
$xw->openURI('php://output');
$xw->setIndent(true);
$xw->startDocument('1.0', 'UTF-8'); /**
$this->writeFullElement($xw, 'XRDS', array('xmlns' => 'xri://$xrds'), array( * Write OMB-specific XRDS using XMLWriter
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', *
'xml:id' => 'oauth', * This class writes the XRDS file announcing the OMB server. It uses XMLWriter.
'xmlns:simple' => 'http://xrds-simple.net/core/1.0', * An instance of OMB_Plain_XRDS_Writer should be passed to
'version' => '2.0'), array( * OMB_Service_Provider->writeXRDS.
*/
class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer
{
/**
* Write XRDS using XMLWriter
*
* Outputs a XRDS document specifying an OMB service.
*
* @param OMB_profile $user The target user for the OMB service
* @param OMB_XRDS_Mapper $mapper An OMB_XRDS_Mapper providing endpoint URLs
*/
public function writeXRDS($user, $mapper)
{
header('Content-Type: application/xrds+xml');
$xw = new XMLWriter();
$xw->openURI('php://output');
$xw->setIndent(true);
$xw->startDocument('1.0', 'UTF-8');
$this->_writeFullElement($xw, 'XRDS', array('xmlns' => 'xri://$xrds'), array(
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'oauth',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OAUTH_ENDPOINT_REQUEST), array('Type', null, OAUTH_ENDPOINT_REQUEST),
@ -73,10 +86,10 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('Type', null, OAUTH_HMAC_SHA1) array('Type', null, OAUTH_HMAC_SHA1)
)) ))
)), )),
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'xml:id' => 'omb', 'xml:id' => 'omb',
'xmlns:simple' => 'http://xrds-simple.net/core/1.0', 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
'version' => '2.0'), array( 'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OMB_ENDPOINT_POSTNOTICE), array('Type', null, OMB_ENDPOINT_POSTNOTICE),
@ -87,8 +100,8 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('URI', null, $mapper->getURL(OMB_ENDPOINT_UPDATEPROFILE)) array('URI', null, $mapper->getURL(OMB_ENDPOINT_UPDATEPROFILE))
)) ))
)), )),
array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', array('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
'version' => '2.0'), array( 'version' => '2.0'), array(
array('Type', null, 'xri://$xrds*simple'), array('Type', null, 'xri://$xrds*simple'),
array('Service', null, array( array('Service', null, array(
array('Type', null, OAUTH_DISCOVERY), array('Type', null, OAUTH_DISCOVERY),
@ -98,27 +111,40 @@ class OMB_Plain_XRDS_Writer implements OMB_XRDS_Writer {
array('Type', null, OMB_VERSION), array('Type', null, OMB_VERSION),
array('URI', null, '#omb') array('URI', null, '#omb')
)) ))
)) ))));
)); $xw->endDocument();
$xw->endDocument(); $xw->flush();
$xw->flush(); }
}
public static function writeFullElement($xw, $tag, $attributes, $content) { /**
$xw->startElement($tag); * Write a complex XML element
if (!is_null($attributes)) { *
foreach ($attributes as $name => $value) { * Outputs a XML element with attributes and content.
$xw->writeAttribute($name, $value); *
} * @param XMLWriter $xw The XMLWriter used to output the element
* @param string $tag The tag name
* @param array|null $attributes A map of XML attributes
* @param array|string $content The content of the element; either an
* array of child nodes each specified by a
* three entry-array ($tag, $attributes,
* $content) or a string
*/
private function _writeFullElement($xw, $tag, $attributes, $content)
{
$xw->startElement($tag);
if (!is_null($attributes)) {
foreach ($attributes as $name => $value) {
$xw->writeAttribute($name, $value);
}
}
if (is_array($content)) {
foreach ($content as $val) {
$this->_writeFullElement($xw, $val[0], $val[1], $val[2]);
}
} else {
$xw->text($content);
}
$xw->fullEndElement();
} }
if (is_array($content)) {
foreach ($content as $values) {
OMB_Plain_XRDS_Writer::writeFullElement($xw, $values[0], $values[1], $values[2]);
}
} else {
$xw->text($content);
}
$xw->fullEndElement();
}
} }
?> ?>

View File

@ -1,15 +1,6 @@
<?php <?php
require_once 'invalidparameterexception.php';
require_once 'Validate.php';
require_once 'helper.php';
/** /**
* OMB profile representation * This file is part of libomb
*
* This class represents an OMB profile.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
* *
* PHP version 5 * PHP version 5
* *
@ -26,292 +17,329 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Profile { require_once 'invalidparameterexception.php';
protected $identifier_uri; require_once 'Validate.php';
protected $profile_url; require_once 'helper.php';
protected $nickname;
protected $license_url;
protected $fullname;
protected $homepage;
protected $bio;
protected $location;
protected $avatar_url;
/* The profile as OMB param array. Cached and rebuild on usage. /**
false while outdated. */ * OMB profile representation
protected $param_array; *
* This class represents an OMB profile.
*
* Do not call the setters with null values. Instead, if you want to delete a
* field, pass an empty string. The getters will return null for empty fields.
*/
class OMB_Profile
{
protected $identifier_uri;
protected $profile_url;
protected $nickname;
protected $license_url;
protected $fullname;
protected $homepage;
protected $bio;
protected $location;
protected $avatar_url;
/** /* The profile as OMB param array. Cached and rebuild on usage.
* Constructor for OMB_Profile false while outdated. */
* protected $param_array;
* Initializes the OMB_Profile object with an identifier uri.
* /**
* @param string $identifier_uri The profile URI as defined by the OMB. A unique * Constructor for OMB_Profile
* and unchanging identifier for a profile. *
* * Initializes the OMB_Profile object with an identifier uri.
* @access public *
*/ * @param string $identifier_uri The profile URI as defined by the OMB;
public function __construct($identifier_uri) { * A unique and never changing identifier for
if (!Validate::uri($identifier_uri)) { * a profile
throw new OMB_InvalidParameterException($identifier_uri, 'profile', *
* @access public
*/
public function __construct($identifier_uri)
{
if (!Validate::uri($identifier_uri)) {
throw new OMB_InvalidParameterException($identifier_uri, 'profile',
'omb_listenee or omb_listener'); 'omb_listenee or omb_listener');
} }
$this->identifier_uri = $identifier_uri; $this->identifier_uri = $identifier_uri;
$this->param_array = false; $this->param_array = false;
}
/**
* Returns the profile as array
*
* The method returns an array which contains the whole profile as array. The
* array is cached and only rebuilt on changes of the profile.
*
* @param bool $force_all Specifies whether empty fields should be added to
* the array as well. This is neccessary to clear
* fields via updateProfile.
*
* @param string $prefix The common prefix to the key for all parameters.
*
* @access public
*
* @return array The profile as parameter array
*/
public function asParameters($prefix, $force_all = false) {
if ($this->param_array === false) {
$this->param_array = array('' => $this->identifier_uri);
if ($force_all || !is_null($this->profile_url)) {
$this->param_array['_profile'] = $this->profile_url;
}
if ($force_all || !is_null($this->homepage)) {
$this->param_array['_homepage'] = $this->homepage;
}
if ($force_all || !is_null($this->nickname)) {
$this->param_array['_nickname'] = $this->nickname;
}
if ($force_all || !is_null($this->license_url)) {
$this->param_array['_license'] = $this->license_url;
}
if ($force_all || !is_null($this->fullname)) {
$this->param_array['_fullname'] = $this->fullname;
}
if ($force_all || !is_null($this->bio)) {
$this->param_array['_bio'] = $this->bio;
}
if ($force_all || !is_null($this->location)) {
$this->param_array['_location'] = $this->location;
}
if ($force_all || !is_null($this->avatar_url)) {
$this->param_array['_avatar'] = $this->avatar_url;
}
}
$ret = array();
foreach ($this->param_array as $k => $v) {
$ret[$prefix . $k] = $v;
}
return $ret;
}
/**
* Builds an OMB_Profile object from array
*
* The method builds an OMB_Profile object from the passed parameters array. The
* array MUST provide a profile URI. The array fields HAVE TO be named according
* to the OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
* parameter.
*
* @param string $parameters An array containing the profile parameters.
* @param string $prefix The common prefix of the profile parameter keys.
*
* @access public
*
* @returns OMB_Profile The built OMB_Profile.
*/
public static function fromParameters($parameters, $prefix) {
if (!isset($parameters[$prefix])) {
throw new OMB_InvalidParameterException('', 'profile', $prefix);
} }
$profile = new OMB_Profile($parameters[$prefix]); /**
$profile->updateFromParameters($parameters, $prefix); * Return the profile as array
return $profile; *
} * Returns an array which contains the whole profile as array.
* The array is cached and only rebuilt on changes of the profile.
*
* @param string $prefix The common prefix to the key for all parameters
* @param bool $force_all Specifies whether empty fields should be added
* to the array as well; This is necessary to
* clear fields via updateProfile
*
* @access public
*
* @return array The profile as parameter array
*/
public function asParameters($prefix, $force_all = false)
{
if ($this->param_array === false) {
$this->param_array = array('' => $this->identifier_uri);
/** if ($force_all || !is_null($this->profile_url)) {
* Update from array $this->param_array['_profile'] = $this->profile_url;
* }
* Updates from the passed parameters array. The array does not have to
* provide a profile URI. The array fields HAVE TO be named according to the if ($force_all || !is_null($this->homepage)) {
* OMB standard. The prefix (omb_listener or omb_listenee) is passed as a $this->param_array['_homepage'] = $this->homepage;
* parameter. }
*
* @param string $parameters An array containing the profile parameters. if ($force_all || !is_null($this->nickname)) {
* @param string $prefix The common prefix of the profile parameter keys. $this->param_array['_nickname'] = $this->nickname;
* }
* @access public
*/ if ($force_all || !is_null($this->license_url)) {
public function updateFromParameters($parameters, $prefix) { $this->param_array['_license'] = $this->license_url;
if (isset($parameters[$prefix.'_profile'])) { }
$this->setProfileURL($parameters[$prefix.'_profile']);
if ($force_all || !is_null($this->fullname)) {
$this->param_array['_fullname'] = $this->fullname;
}
if ($force_all || !is_null($this->bio)) {
$this->param_array['_bio'] = $this->bio;
}
if ($force_all || !is_null($this->location)) {
$this->param_array['_location'] = $this->location;
}
if ($force_all || !is_null($this->avatar_url)) {
$this->param_array['_avatar'] = $this->avatar_url;
}
}
$ret = array();
foreach ($this->param_array as $k => $v) {
$ret[$prefix . $k] = $v;
}
return $ret;
} }
if (isset($parameters[$prefix.'_license'])) { /**
$this->setLicenseURL($parameters[$prefix.'_license']); * Build an OMB_Profile object from array
*
* Builds an OMB_Profile object from the passed parameters array. The
* array MUST provide a profile URI. The array fields HAVE TO be named
* according to the OMB standard. The prefix (omb_listener or omb_listenee)
* is passed as a parameter.
*
* @param string $parameters An array containing the profile parameters
* @param string $prefix The common prefix of the profile parameter keys
*
* @access public
*
* @returns OMB_Profile The built OMB_Profile
*/
public static function fromParameters($parameters, $prefix)
{
if (!isset($parameters[$prefix])) {
throw new OMB_InvalidParameterException('', 'profile', $prefix);
}
$profile = new OMB_Profile($parameters[$prefix]);
$profile->updateFromParameters($parameters, $prefix);
return $profile;
} }
if (isset($parameters[$prefix.'_nickname'])) { /**
$this->setNickname($parameters[$prefix.'_nickname']); * Update from array
*
* Updates from the passed parameters array. The array does not have to
* provide a profile URI. The array fields HAVE TO be named according to the
* OMB standard. The prefix (omb_listener or omb_listenee) is passed as a
* parameter.
*
* @param string $parameters An array containing the profile parameters
* @param string $prefix The common prefix of the profile parameter keys
*
* @access public
*/
public function updateFromParameters($parameters, $prefix)
{
if (isset($parameters[$prefix.'_profile'])) {
$this->setProfileURL($parameters[$prefix.'_profile']);
}
if (isset($parameters[$prefix.'_license'])) {
$this->setLicenseURL($parameters[$prefix.'_license']);
}
if (isset($parameters[$prefix.'_nickname'])) {
$this->setNickname($parameters[$prefix.'_nickname']);
}
if (isset($parameters[$prefix.'_fullname'])) {
$this->setFullname($parameters[$prefix.'_fullname']);
}
if (isset($parameters[$prefix.'_homepage'])) {
$this->setHomepage($parameters[$prefix.'_homepage']);
}
if (isset($parameters[$prefix.'_bio'])) {
$this->setBio($parameters[$prefix.'_bio']);
}
if (isset($parameters[$prefix.'_location'])) {
$this->setLocation($parameters[$prefix.'_location']);
}
if (isset($parameters[$prefix.'_avatar'])) {
$this->setAvatarURL($parameters[$prefix.'_avatar']);
}
} }
if (isset($parameters[$prefix.'_fullname'])) { public function getIdentifierURI()
$this->setFullname($parameters[$prefix.'_fullname']); {
return $this->identifier_uri;
} }
if (isset($parameters[$prefix.'_homepage'])) { public function getProfileURL()
$this->setHomepage($parameters[$prefix.'_homepage']); {
return $this->profile_url;
} }
if (isset($parameters[$prefix.'_bio'])) { public function getHomepage()
$this->setBio($parameters[$prefix.'_bio']); {
return $this->homepage;
} }
if (isset($parameters[$prefix.'_location'])) { public function getNickname()
$this->setLocation($parameters[$prefix.'_location']); {
return $this->nickname;
} }
if (isset($parameters[$prefix.'_avatar'])) { public function getLicenseURL()
$this->setAvatarURL($parameters[$prefix.'_avatar']); {
} return $this->license_url;
}
public function getIdentifierURI() {
return $this->identifier_uri;
}
public function getProfileURL() {
return $this->profile_url;
}
public function getHomepage() {
return $this->homepage;
}
public function getNickname() {
return $this->nickname;
}
public function getLicenseURL() {
return $this->license_url;
}
public function getFullname() {
return $this->fullname;
}
public function getBio() {
return $this->bio;
}
public function getLocation() {
return $this->location;
}
public function getAvatarURL() {
return $this->avatar_url;
}
public function setProfileURL($profile_url) {
if (!OMB_Helper::validateURL($profile_url)) {
throw new OMB_InvalidParameterException($profile_url, 'profile',
'omb_listenee_profile or omb_listener_profile');
}
$this->profile_url = $profile_url;
$this->param_array = false;
}
public function setNickname($nickname) {
if (!Validate::string($nickname,
array('min_length' => 1,
'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA))) {
throw new OMB_InvalidParameterException($nickname, 'profile', 'nickname');
} }
$this->nickname = $nickname; public function getFullname()
$this->param_array = false; {
} return $this->fullname;
public function setLicenseURL($license_url) {
if (!OMB_Helper::validateURL($license_url)) {
throw new OMB_InvalidParameterException($license_url, 'profile',
'omb_listenee_license or omb_listener_license');
} }
$this->license_url = $license_url;
$this->param_array = false;
}
public function setFullname($fullname) { public function getBio()
if ($fullname === '') { {
$fullname = null; return $this->bio;
} elseif (!Validate::string($fullname, array('max_length' => 255))) {
throw new OMB_InvalidParameterException($fullname, 'profile', 'fullname');
} }
$this->fullname = $fullname;
$this->param_array = false;
}
public function setHomepage($homepage) { public function getLocation()
if ($homepage === '') { {
$homepage = null; return $this->location;
} }
$this->homepage = $homepage;
$this->param_array = false;
}
public function setBio($bio) { public function getAvatarURL()
if ($bio === '') { {
$bio = null; return $this->avatar_url;
} elseif (!Validate::string($bio, array('max_length' => 140))) {
throw new OMB_InvalidParameterException($bio, 'profile', 'fullname');
} }
$this->bio = $bio;
$this->param_array = false;
}
public function setLocation($location) { public function setProfileURL($profile_url)
if ($location === '') { {
$location = null; $this->setVal('profile', $profile_url, 'OMB_Helper::validateURL',
} elseif (!Validate::string($location, array('max_length' => 255))) { 'profile_url');
throw new OMB_InvalidParameterException($location, 'profile', 'fullname');
} }
$this->location = $location;
$this->param_array = false;
}
public function setAvatarURL($avatar_url) { public function setNickname($nickname)
if ($avatar_url === '') { {
$avatar_url = null; $this->setVal('nickname', $nickname, 'OMB_Profile::validateNickname',
} elseif (!OMB_Helper::validateURL($avatar_url)) { 'nickname', true);
throw new OMB_InvalidParameterException($avatar_url, 'profile',
'omb_listenee_avatar or omb_listener_avatar');
} }
$this->avatar_url = $avatar_url;
$this->param_array = false;
}
public function setLicenseURL($license_url)
{
$this->setVal('license', $license_url, 'OMB_Helper::validateURL',
'license_url');
}
public function setFullname($fullname)
{
$this->setVal('fullname', $fullname, 'OMB_Profile::validate255');
}
public function setHomepage($homepage)
{
$this->setVal('homepage', $homepage, 'OMB_Helper::validateURL');
}
public function setBio($bio)
{
$this->setVal('bio', $bio, 'OMB_Profile::validate140');
}
public function setLocation($location)
{
$this->setVal('location', $location, 'OMB_Profile::validate255');
}
public function setAvatarURL($avatar_url)
{
$this->setVal('avatar', $avatar_url, 'OMB_Helper::validateURL',
'avatar_url');
}
protected static function validate255($str)
{
return Validate::string($str, array('max_length' => 255));
}
protected static function validate140($str)
{
return Validate::string($str, array('max_length' => 140));
}
protected static function validateNickname($str)
{
return Validate::string($str,
array('min_length' => 1,
'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA));
}
/**
* Set a value
*
* Updates a value specified by a parameter name and the new value.
*
* @param string $param The parameter name according to OMB
* @param string $value The new value
* @param callback $validator A validator function for the parameter
* @param string $field The name of the field in OMB_Profile
* @param bool $force Whether null values should be checked as well
*/
protected function setVal($param, $value, $validator, $field = null,
$force = false)
{
if (is_null($field)) {
$field = $param;
}
if ($value === '' && !$force) {
$value = null;
} elseif (!call_user_func($validator, $value)) {
throw new OMB_InvalidParameterException($value, 'profile', $param);
}
if ($this->$field !== $value) {
$this->$field = $value;
$this->param_array = false;
}
}
} }
?> ?>

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that the remote service had a failure * This file is part of libomb
*
* This exception is raised when a remote service failed to return a valid
* response to a request or send a valid request.
* *
* PHP version 5 * PHP version 5
* *
@ -20,23 +17,57 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_RemoteServiceException extends Exception { */
public static function fromYadis($request_uri, $result) {
if ($result->status == 200) {
$err = 'Got wrong response ' . $result->body;
} else {
$err = 'Got error code ' . $result->status . ' with response ' . $result->body;
}
return new OMB_RemoteServiceException($request_uri . ': ' . $err);
}
public static function forRequest($action_uri, $failure) { /**
return new OMB_RemoteServiceException("Handler for $action_uri: " . $failure); * Exception stating that the remote service had a failure
} *
* This exception is raised when a remote service failed to return a valid
* response to a request or send a valid request.
*/
class OMB_RemoteServiceException extends Exception
{
/**
* Create exception from Yadis response
*
* Creates an exception from a passed yadis result.
*
* @param string $request_uri The target URI for the failed
* request
* @param Auth_Yadis_HTTPResponse $result The result of the failed
* request
*
* @return OMB_RemoteServiceException A new exception
*/
public static function fromYadis($request_uri, $result)
{
if ($result->status == 200) {
$err = 'Got wrong response ' . $result->body;
} else {
$err = 'Got error code ' . $result->status . ' with response ' .
$result->body;
}
return OMB_RemoteServiceException::forRequest($request_uri, $err);
}
/**
* Create exception for a call to a resource
*
* Creates an exception for a given error message and target URI.
*
* @param string $action_uri The target URI for the failed request
* @param string $failure An error message
*
* @return OMB_RemoteServiceException A new exception
*/
public static function forRequest($action_uri, $failure)
{
return new OMB_RemoteServiceException("Handler for $action_uri: $failure");
}
} }
?> ?>

View File

@ -1,19 +1,6 @@
<?php <?php
require_once 'constants.php';
require_once 'Validate.php';
require_once 'Auth/Yadis/Yadis.php';
require_once 'OAuth.php';
require_once 'unsupportedserviceexception.php';
require_once 'remoteserviceexception.php';
require_once 'omb_yadis_xrds.php';
require_once 'helper.php';
/** /**
* OMB service representation * This file is part of libomb
*
* This class represents a complete remote OMB service. It provides discovery
* and execution of the services methods.
* *
* PHP version 5 * PHP version 5
* *
@ -30,401 +17,445 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Service_Consumer { require_once 'Validate.php';
protected $url; /* The service URL */ require_once 'Auth/Yadis/Yadis.php';
protected $services; /* An array of strings mapping service URI to require_once 'OAuth.php';
service URL */ require_once 'constants.php';
require_once 'helper.php';
require_once 'omb_yadis_xrds.php';
require_once 'profile.php';
require_once 'remoteserviceexception.php';
require_once 'unsupportedserviceexception.php';
protected $token; /* An OAuthToken */ /**
* OMB service representation
*
* This class represents a complete remote OMB service. It provides discovery
* and execution of the services methods.
*/
class OMB_Service_Consumer
{
protected $url; /* The service URL */
protected $services; /* An array of strings mapping service URI to
service URL */
protected $listener_uri; /* The URI identifying the listener, i. e. the protected $token; /* An OAuthToken */
remote user. */
protected $listenee_uri; /* The URI identifying the listenee, i. e. the protected $listener_uri; /* The URI identifying the listener, i. e. the
local user during an auth request. */ remote user. */
/** protected $listenee_uri; /* The URI identifying the listenee, i. e. the
* According to OAuth Core 1.0, an user authorization request is no full-blown local user during an auth request. */
* OAuth request. nonce, timestamp, consumer_key and signature are not needed
* in this step. See http://laconi.ca/trac/ticket/827 for more informations.
*
* Since Laconica up to version 0.7.2 performs a full OAuth request check, a
* correct request would fail.
**/
public $performLegacyAuthRequest = true;
/* Helper stuff we are going to need. */ /**
protected $fetcher; * According to OAuth Core 1.0, an user authorization request is no
protected $oauth_consumer; * full-blown OAuth request. nonce, timestamp, consumer_key and signature
protected $datastore; * are not needed in this step. See http://laconi.ca/trac/ticket/827 for
* more informations.
*
* Since Laconica up to version 0.7.2 performs a full OAuth request check, a
* correct request would fail.
*/
public $performLegacyAuthRequest = true;
/** /* Helper stuff we are going to need. */
* Constructor for OMB_Service_Consumer protected $fetcher;
* protected $oauth_consumer;
* Initializes an OMB_Service_Consumer object representing the OMB service protected $datastore;
* specified by $service_url. Performs a complete service discovery using
* Yadis.
* Throws OMB_UnsupportedServiceException if XRDS file does not specify a
* complete OMB service.
*
* @param string $service_url The URL of the service
* @param string $consumer_url An URL representing the consumer
* @param OMB_Datastore $datastore An instance of a class implementing
* OMB_Datastore
*
* @access public
**/
public function __construct ($service_url, $consumer_url, $datastore) {
$this->url = $service_url;
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$this->datastore = $datastore;
$this->oauth_consumer = new OAuthConsumer($consumer_url, '');
$xrds = OMB_Yadis_XRDS::fromYadisURL($service_url, $this->fetcher); /**
* Constructor for OMB_Service_Consumer
*
* Initializes an OMB_Service_Consumer object representing the OMB service
* specified by $service_url. Performs a complete service discovery using
* Yadis.
* Throws OMB_UnsupportedServiceException if XRDS file does not specify a
* complete OMB service.
*
* @param string $service_url The URL of the service
* @param string $consumer_url An URL representing the consumer
* @param OMB_Datastore $datastore An instance of a class implementing
* OMB_Datastore
*
* @access public
*/
public function __construct ($service_url, $consumer_url, $datastore)
{
$this->url = $service_url;
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$this->datastore = $datastore;
$this->oauth_consumer = new OAuthConsumer($consumer_url, '');
/* Detect our services. This performs a validation as well, since $xrds = OMB_Yadis_XRDS::fromYadisURL($service_url, $this->fetcher);
getService und getXRD throw exceptions on failure. */
$this->services = array();
foreach (array(OAUTH_DISCOVERY => OMB_Helper::$OAUTH_SERVICES, /* Detect our services. This performs a validation as well, since
OMB_VERSION => OMB_Helper::$OMB_SERVICES) getService und getXRD throw exceptions on failure. */
as $service_root => $targetservices) { $this->services = array();
$uris = $xrds->getService($service_root)->getURIs();
$xrd = $xrds->getXRD($uris[0]); foreach (array(OAUTH_DISCOVERY => OMB_Helper::$OAUTH_SERVICES,
foreach ($targetservices as $targetservice) { OMB_VERSION => OMB_Helper::$OMB_SERVICES)
$yadis_service = $xrd->getService($targetservice); as $service_root => $targetservices) {
if ($targetservice == OAUTH_ENDPOINT_REQUEST) { $uris = $xrds->getService($service_root)->getURIs();
$localid = $yadis_service->getElements('xrd:LocalID'); $xrd = $xrds->getXRD($uris[0]);
$this->listener_uri = $yadis_service->parser->content($localid[0]); foreach ($targetservices as $targetservice) {
$yadis_service = $xrd->getService($targetservice);
if ($targetservice == OAUTH_ENDPOINT_REQUEST) {
$localid =
$yadis_service->getElements('xrd:LocalID');
$this->listener_uri =
$yadis_service->parser->content($localid[0]);
}
$uris = $yadis_service->getURIs();
$this->services[$targetservice] = $uris[0];
}
} }
$uris = $yadis_service->getURIs();
$this->services[$targetservice] = $uris[0];
}
}
}
/**
* Get the handler URI for a service
*
* Returns the URI the remote web service has specified for the given
* service.
*
* @param string $service The URI identifying the service
*
* @access public
*
* @return string The service handler URI
**/
public function getServiceURI($service) {
return $this->services[$service];
}
/**
* Get the remote users URI
*
* Returns the URI of the remote user, i. e. the listener.
*
* @access public
*
* @return string The remote users URI
**/
public function getRemoteUserURI() {
return $this->listener_uri;
}
/**
* Get the listenees URI
*
* Returns the URI of the user being subscribed to, i. e. the local user.
*
* @access public
*
* @return string The local users URI
**/
public function getListeneeURI() {
return $this->listenee_uri;
}
/**
* Request a request token
*
* Performs a token request on the service. Returns an OAuthToken on success.
* Throws an exception if the request fails.
*
* @access public
*
* @return OAuthToken An unauthorized request token
**/
public function requestToken() {
/* Set the token to null just in case the user called setToken. */
$this->token = null;
$result = $this->performAction(OAUTH_ENDPOINT_REQUEST,
array('omb_listener' => $this->listener_uri));
if ($result->status != 200) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
parse_str($result->body, $return);
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
return $this->token;
}
/**
*
* Request authorization
*
* Returns an URL which equals to an authorization request. The end user
* should be redirected to this location to perform authorization.
* The $finish_url should be a local resource which invokes
* OMB_Consumer::finishAuthorization on request.
*
* @param OMB_Profile $profile An OMB_Profile object representing the
* soon-to-be subscribed (i. e. local) user
* @param string $finish_url Target location after successful
* authorization
*
* @access public
*
* @return string An URL representing an authorization request
**/
public function requestAuthorization($profile, $finish_url) {
if ($this->performLegacyAuthRequest) {
$params = $profile->asParameters('omb_listenee', false);
$params['omb_listener'] = $this->listener_uri;
$params['oauth_callback'] = $finish_url;
$url = $this->prepareAction(OAUTH_ENDPOINT_AUTHORIZE, $params, 'GET')->to_url();
} else {
$params = array(
'oauth_callback' => $finish_url,
'oauth_token' => $this->token->key,
'omb_version' => OMB_VERSION,
'omb_listener' => $this->listener_uri);
$params = array_merge($profile->asParameters('omb_listenee', false). $params);
/* Build result URL. */
$url = $this->services[OAUTH_ENDPOINT_AUTHORIZE];
$url .= (strrpos($url, '?') === false ? '?' : '&');
foreach ($params as $k => $v) {
$url .= OAuthUtil::urlencode_rfc3986($k) . '=' . OAuthUtil::urlencode_rfc3986($v) . '&';
}
} }
$this->listenee_uri = $profile->getIdentifierURI(); /**
* Get the handler URI for a service
return $url; *
} * Returns the URI the remote web service has specified for the given
* service.
/** *
* Finish authorization * @param string $service The URI identifying the service
* *
* Finish the subscription process by converting the received and authorized * @access public
* request token into an access token. After that, the subscribers profile *
* and the subscription are stored in the database. * @return string The service handler URI
* Expects an OAuthRequest in query parameters. */
* Throws exceptions on failure. public function getServiceURI($service)
* {
* @access public return $this->services[$service];
**/
public function finishAuthorization() {
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request();
if ($req->get_parameter('oauth_token') !=
$this->token->key) {
/* Thats not the token I wanted to get authorized. */
throw new OAuthException('The authorized token does not equal the ' .
'submitted token.');
} }
if ($req->get_parameter('omb_version') != OMB_VERSION) { /**
throw new OMB_RemoteServiceException('The remote service uses an ' . * Get the remote users URI
'unsupported OMB version'); *
* Returns the URI of the remote user, i. e. the listener.
*
* @access public
*
* @return string The remote users URI
*/
public function getRemoteUserURI()
{
return $this->listener_uri;
} }
/* Construct the profile to validate it. */ /**
* Get the listenees URI
/* Fix OMB bug. Listener URI is not passed. */ *
if ($_SERVER['REQUEST_METHOD'] == 'POST') { * Returns the URI of the user being subscribed to, i. e. the local user.
$params = $_POST; *
} else { * @access public
$params = $_GET; *
} * @return string The local users URI
$params['omb_listener'] = $this->listener_uri; */
public function getListeneeURI()
require_once 'profile.php'; {
$listener = OMB_Profile::fromParameters($params, 'omb_listener'); return $this->listenee_uri;
/* Ask the remote service to convert the authorized request token into an
access token. */
$result = $this->performAction(OAUTH_ENDPOINT_ACCESS, array());
if ($result->status != 200) {
throw new OAuthException('Could not get access token');
} }
parse_str($result->body, $return); /**
if (!isset($return['oauth_token']) || !isset($return['oauth_token_secret'])) { * Request a request token
throw new OAuthException('Could not get access token'); *
* Performs a token request on the service. Returns an OAuthToken on success.
* Throws an exception if the request fails.
*
* @access public
*
* @return OAuthToken An unauthorized request token
*/
public function requestToken()
{
/* Set the token to null just in case the user called setToken. */
$this->token = null;
$result = $this->performAction(OAUTH_ENDPOINT_REQUEST,
array('omb_listener' => $this->listener_uri));
if ($result->status != 200) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
parse_str($result->body, $return);
if (!isset($return['oauth_token']) ||
!isset($return['oauth_token_secret'])) {
throw OMB_RemoteServiceException::fromYadis(OAUTH_ENDPOINT_REQUEST,
$result);
}
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
return $this->token;
} }
$this->setToken($return['oauth_token'], $return['oauth_token_secret']);
/* Subscription is finished and valid. Now store the new subscriber and the /**
subscription in the database. */ * Request authorization
*
* Returns an URL which equals to an authorization request. The end user
* should be redirected to this location to perform authorization.
* The $finish_url should be a local resource which invokes
* OMB_Consumer::finishAuthorization on request.
*
* @param OMB_Profile $profile An OMB_Profile object representing the
* soon-to-be subscribed (i. e. local) user
* @param string $finish_url Target location after successful
* authorization
*
* @access public
*
* @return string An URL representing an authorization request
*/
public function requestAuthorization($profile, $finish_url)
{
if ($this->performLegacyAuthRequest) {
$params = $profile->asParameters('omb_listenee',
false);
$params['omb_listener'] = $this->listener_uri;
$params['oauth_callback'] = $finish_url;
$this->datastore->saveProfile($listener); $url = $this->prepareAction(OAUTH_ENDPOINT_AUTHORIZE, $params,
$this->datastore->saveSubscription($this->listener_uri, 'GET')->to_url();
$this->listenee_uri, } else {
$this->token); $params = array('oauth_callback' => $finish_url,
} 'oauth_token' => $this->token->key,
'omb_version' => OMB_VERSION,
'omb_listener' => $this->listener_uri);
/** $params = array_merge($profile->asParameters('omb_listenee', false),
* Return the URI identifying the listener $params);
*
* Returns the URI for the OMB user who tries to subscribe or already has
* subscribed our user. This method is a workaround for a serious OMB flaw:
* The Listener URI is not passed in the finishauthorization call.
*
* @access public
*
* @return string the listeners URI
**/
public function getListenerURI() {
return $this->listener_uri;
}
/** /* Build result URL. */
* Inform the service about a profile update $url = $this->services[OAUTH_ENDPOINT_AUTHORIZE] .
* (strrpos($url, '?') === false ? '?' : '&');
* Sends an updated profile to the service. foreach ($params as $k => $v) {
* $url .= OAuthUtil::urlencode_rfc3986($k) . '=' .
* @param OMB_Profile $profile The profile that has changed OAuthUtil::urlencode_rfc3986($v) . '&';
* }
* @access public }
**/
public function updateProfile($profile) {
$params = $profile->asParameters('omb_listenee', true);
$this->performOMBAction(OMB_ENDPOINT_UPDATEPROFILE, $params, $profile->getIdentifierURI());
}
/** $this->listenee_uri = $profile->getIdentifierURI();
* Inform the service about a new notice
*
* Sends a notice to the service.
*
* @param OMB_Notice $notice The notice
*
* @access public
**/
public function postNotice($notice) {
$params = $notice->asParameters();
$params['omb_listenee'] = $notice->getAuthor()->getIdentifierURI();
$this->performOMBAction(OMB_ENDPOINT_POSTNOTICE, $params, $params['omb_listenee']);
}
/** return $url;
* Set the token member variable }
*
* Initializes the token based on given token and secret token. /**
* * Finish authorization
* @param string $token The token *
* @param string $secret The secret token * Finish the subscription process by converting the received and authorized
* * request token into an access token. After that, the subscribers profile
* @access public * and the subscription are stored in the database.
**/ * Expects an OAuthRequest in query parameters.
public function setToken($token, $secret) { * Throws exceptions on failure.
$this->token = new OAuthToken($token, $secret); *
} * @access public
*/
/** public function finishAuthorization()
* Prepare an OAuthRequest object {
* OMB_Helper::removeMagicQuotesFromRequest();
* Creates an OAuthRequest object mapping the request specified by the $req = OAuthRequest::from_request();
* parameters. if ($req->get_parameter('oauth_token') != $this->token->key) {
* /* Thats not the token I wanted to get authorized. */
* @param string $action_uri The URI specifying the target service throw new OAuthException('The authorized token does not equal ' .
* @param array $params Additional parameters for the service call 'the submitted token.');
* @param string $method The HTTP method used to call the service }
* ('POST' or 'GET', usually)
* if ($req->get_parameter('omb_version') != OMB_VERSION) {
* @access protected throw new OMB_RemoteServiceException('The remote service uses an ' .
* 'unsupported OMB version');
* @return OAuthRequest the prepared request }
**/
protected function prepareAction($action_uri, $params, $method) { /* Construct the profile to validate it. */
$url = $this->services[$action_uri];
/* Fix OMB bug. Listener URI is not passed. */
$url_params = array(); if ($_SERVER['REQUEST_METHOD'] == 'POST') {
parse_str(parse_url($url, PHP_URL_QUERY), $url_params); $params = $_POST;
} else {
/* Add OMB version. */ $params = $_GET;
$url_params['omb_version'] = OMB_VERSION; }
$params['omb_listener'] = $this->listener_uri;
/* Add user-defined parameters. */
$url_params = array_merge($url_params, $params); $listener = OMB_Profile::fromParameters($params, 'omb_listener');
$req = OAuthRequest::from_consumer_and_token($this->oauth_consumer, /* Ask the remote service to convert the authorized request token into
$this->token, $method, $url, $url_params); an access token. */
/* Sign the request. */ $result = $this->performAction(OAUTH_ENDPOINT_ACCESS, array());
$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), if ($result->status != 200) {
$this->oauth_consumer, $this->token); throw new OAuthException('Could not get access token');
}
return $req;
} parse_str($result->body, $return);
if (!isset($return['oauth_token']) ||
/** !isset($return['oauth_token_secret'])) {
* Perform a service call throw new OAuthException('Could not get access token');
* }
* Creates an OAuthRequest object and execute the mapped call as POST request. $this->setToken($return['oauth_token'], $return['oauth_token_secret']);
*
* @param string $action_uri The URI specifying the target service /* Subscription is finished and valid. Now store the new subscriber and
* @param array $params Additional parameters for the service call the subscription in the database. */
*
* @access protected $this->datastore->saveProfile($listener);
* $this->datastore->saveSubscription($this->listener_uri,
* @return Auth_Yadis_HTTPResponse The POST request response $this->listenee_uri,
**/ $this->token);
protected function performAction($action_uri, $params) { }
$req = $this->prepareAction($action_uri, $params, 'POST');
/**
/* Return result page. */ * Return the URI identifying the listener
return $this->fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), array()); *
} * Returns the URI for the OMB user who tries to subscribe or already has
* subscribed our user. This method is a workaround for a serious OMB flaw:
/** * The Listener URI is not passed in the finishauthorization call.
* Perform an OMB action *
* * @access public
* Executes an OMB action to date, its one of updateProfile or postNotice. *
* * @return string the listeners URI
* @param string $action_uri The URI specifying the target service */
* @param array $params Additional parameters for the service call public function getListenerURI()
* @param string $listenee_uri The URI identifying the local user for whom {
* the action is performed return $this->listener_uri;
* }
* @access protected
**/ /**
protected function performOMBAction($action_uri, $params, $listenee_uri) { * Inform the service about a profile update
$result = $this->performAction($action_uri, $params); *
if ($result->status == 403) { * Sends an updated profile to the service.
/* The remote user unsubscribed us. */ *
$this->datastore->deleteSubscription($this->listener_uri, $listenee_uri); * @param OMB_Profile $profile The profile that has changed
} else if ($result->status != 200 || *
strpos($result->body, 'omb_version=' . OMB_VERSION) === false) { * @access public
/* The server signaled an error or sent an incorrect response. */ */
throw OMB_RemoteServiceException::fromYadis($action_uri, $result); public function updateProfile($profile)
{
$params = $profile->asParameters('omb_listenee', true);
$this->performOMBAction(OMB_ENDPOINT_UPDATEPROFILE, $params,
$profile->getIdentifierURI());
}
/**
* Inform the service about a new notice
*
* Sends a notice to the service.
*
* @param OMB_Notice $notice The notice
*
* @access public
*/
public function postNotice($notice)
{
$params = $notice->asParameters();
$params['omb_listenee'] = $notice->getAuthor()->getIdentifierURI();
$this->performOMBAction(OMB_ENDPOINT_POSTNOTICE, $params,
$params['omb_listenee']);
}
/**
* Set the token member variable
*
* Initializes the token based on given token and secret token.
*
* @param string $token The token
* @param string $secret The secret token
*
* @access public
*/
public function setToken($token, $secret)
{
$this->token = new OAuthToken($token, $secret);
}
/**
* Prepare an OAuthRequest object
*
* Creates an OAuthRequest object mapping the request specified by the
* parameters.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
* @param string $method The HTTP method used to call the service
* ('POST' or 'GET', usually)
*
* @access protected
*
* @return OAuthRequest the prepared request
*/
protected function prepareAction($action_uri, $params, $method)
{
$url = $this->services[$action_uri];
$url_params = array();
parse_str(parse_url($url, PHP_URL_QUERY), $url_params);
/* Add OMB version. */
$url_params['omb_version'] = OMB_VERSION;
/* Add user-defined parameters. */
$url_params = array_merge($url_params, $params);
$req = OAuthRequest::from_consumer_and_token($this->oauth_consumer,
$this->token, $method,
$url, $url_params);
/* Sign the request. */
$req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(),
$this->oauth_consumer, $this->token);
return $req;
}
/**
* Perform a service call
*
* Creates an OAuthRequest object and execute the mapped call as POST
* request.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
*
* @access protected
*
* @return Auth_Yadis_HTTPResponse The POST request response
*/
protected function performAction($action_uri, $params)
{
$req = $this->prepareAction($action_uri, $params, 'POST');
/* Return result page. */
return $this->fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(), array());
}
/**
* Perform an OMB action
*
* Executes an OMB action as of OMB 0.1, its one of updateProfile and
* postNotice.
*
* @param string $action_uri The URI specifying the target service
* @param array $params Additional parameters for the service call
* @param string $listenee_uri The URI identifying the local user for whom
* the action is performed
*
* @access protected
*/
protected function performOMBAction($action_uri, $params, $listenee_uri)
{
$result = $this->performAction($action_uri, $params);
if ($result->status == 403) {
/* The remote user unsubscribed us. */
$this->datastore->deleteSubscription($this->listener_uri,
$listenee_uri);
} else if ($result->status != 200 ||
strpos($result->body, 'omb_version=' . OMB_VERSION) === false) {
/* The server signaled an error or sent an incorrect response. */
throw OMB_RemoteServiceException::fromYadis($action_uri, $result);
}
} }
}
} }
?>

View File

@ -1,13 +1,6 @@
<?php <?php
require_once 'constants.php';
require_once 'remoteserviceexception.php';
require_once 'helper.php';
/** /**
* OMB service realization * This file is part of libomb
*
* This class realizes a complete, simple OMB service.
* *
* PHP version 5 * PHP version 5
* *
@ -24,406 +17,445 @@ require_once 'helper.php';
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
class OMB_Service_Provider { require_once 'constants.php';
protected $user; /* An OMB_Profile representing the user */ require_once 'helper.php';
protected $datastore; /* AN OMB_Datastore */ require_once 'notice.php';
require_once 'remoteserviceexception.php';
protected $remote_user; /* An OMB_Profile representing the remote user during /**
the authorization process */ * OMB service realization
*
* This class realizes a complete, simple OMB service.
*/
class OMB_Service_Provider
{
protected $user; /* An OMB_Profile representing the user */
protected $datastore; /* AN OMB_Datastore */
protected $oauth_server; /* An OAuthServer; should only be accessed via protected $remote_user; /* An OMB_Profile representing the remote user
getOAuthServer. */ during the authorization process */
/** protected $oauth_server; /* An OAuthServer; should only be accessed via
* Initialize an OMB_Service_Provider object getOAuthServer. */
*
* Constructs an OMB_Service_Provider instance that provides OMB services
* referring to a particular user.
*
* @param OMB_Profile $user An OMB_Profile; mandatory for XRDS
* output, user auth handling and OMB
* action performing
* @param OMB_Datastore $datastore An OMB_Datastore; mandatory for
* everything but XRDS output
* @param OAuthServer $oauth_server An OAuthServer; used for token writing
* and OMB action handling; will use
* default value if not set
*
* @access public
**/
public function __construct ($user = null, $datastore = null, $oauth_server = null) {
$this->user = $user;
$this->datastore = $datastore;
$this->oauth_server = $oauth_server;
}
public function getRemoteUser() { /**
return $this->remote_user; * Initialize an OMB_Service_Provider object
} *
* Constructs an OMB_Service_Provider instance that provides OMB services
/** * referring to a particular user.
* Write a XRDS document *
* * @param OMB_Profile $user An OMB_Profile; mandatory for XRDS
* Writes a XRDS document specifying the OMB service. Optionally uses a * output, user auth handling and OMB
* given object of a class implementing OMB_XRDS_Writer for output. Else * action performing
* OMB_Plain_XRDS_Writer is used. * @param OMB_Datastore $datastore An OMB_Datastore; mandatory for
* * everything but XRDS output
* @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs * @param OAuthServer $oauth_server An OAuthServer; used for token writing
* @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to * and OMB action handling; will use
* write the XRDS document * default value if not set
* *
* @access public * @access public
* */
* @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer public function __construct ($user = null, $datastore = null,
* returns nothing. $oauth_server = null)
**/ {
public function writeXRDS($xrds_mapper, $xrds_writer = null) { $this->user = $user;
if ($xrds_writer == null) { $this->datastore = $datastore;
require_once 'plain_xrds_writer.php'; $this->oauth_server = $oauth_server;
$xrds_writer = new OMB_Plain_XRDS_Writer();
}
return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
}
/**
* Echo a request token
*
* Outputs an unauthorized request token for the query found in $_GET or
* $_POST.
*
* @access public
**/
public function writeRequestToken() {
OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_request_token(OAuthRequest::from_request());
}
/**
* Handle an user authorization request.
*
* Parses an authorization request. This includes OAuth and OMB verification.
* Throws exceptions on failures. Returns an OMB_Profile object representing
* the remote user.
*
* The OMB_Profile passed to the constructor of OMB_Service_Provider should
* not represent the user specified in the authorization request, but the one
* currently logged in to the service. This condition being satisfied,
* handleUserAuth will check whether the listener specified in the request is
* identical to the logged in user.
*
* @access public
*
* @return OMB_Profile The profile of the soon-to-be subscribed, i. e. remote
* user
**/
public function handleUserAuth() {
OMB_Helper::removeMagicQuotesFromRequest();
/* Verify the request token. */
$this->token = $this->datastore->lookup_token(null, "request", $_GET['oauth_token']);
if (is_null($this->token)) {
throw new OAuthException('The given request token has not been issued ' .
'by this service.');
} }
/* Verify the OMB part. */ /**
* Return the remote user during user authorization
if ($_GET['omb_version'] !== OMB_VERSION) { *
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * Returns an OMB_Profile representing the remote user during the user
'Wrong OMB version ' . $_GET['omb_version']); * authorization request.
*
* @return OMB_Profile The remote user
*/
public function getRemoteUser()
{
return $this->remote_user;
} }
if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) { /**
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * Write a XRDS document
'Wrong OMB listener ' . $_GET['omb_listener']); *
} * Writes a XRDS document specifying the OMB service. Optionally uses a
* given object of a class implementing OMB_XRDS_Writer for output. Else
foreach (array('omb_listenee', 'omb_listenee_profile', * OMB_Plain_XRDS_Writer is used.
'omb_listenee_nickname', 'omb_listenee_license') as $param) { *
if (!isset($_GET[$param]) || is_null($_GET[$param])) { * @param OMB_XRDS_Mapper $xrds_mapper An object mapping actions to URLs
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, * @param OMB_XRDS_Writer $xrds_writer Optional; The OMB_XRDS_Writer used to
"Required parameter '$param' not found"); * write the XRDS document
} *
} * @access public
*
/* Store given callback for later use. */ * @return mixed Depends on the used OMB_XRDS_Writer; OMB_Plain_XRDS_Writer
if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') { * returns nothing.
$this->callback = $_GET['oauth_callback']; */
if (!OMB_Helper::validateURL($this->callback)) { public function writeXRDS($xrds_mapper, $xrds_writer = null)
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE, {
'Invalid callback URL specified'); if ($xrds_writer == null) {
} require_once 'plain_xrds_writer.php';
} $xrds_writer = new OMB_Plain_XRDS_Writer();
$this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
return $this->remote_user;
}
/**
* Continue the OAuth dance after user authorization
*
* Performs the appropriate actions after user answered the authorization
* request.
*
* @param bool $accepted Whether the user granted authorization
*
* @access public
*
* @return array A two-component array with the values:
* - callback The callback URL or null if none given
* - token The authorized request token or null if not
* authorized.
**/
public function continueUserAuth($accepted) {
$callback = $this->callback;
if (!$accepted) {
$this->datastore->revoke_token($this->token->key);
$this->token = null;
/* TODO: The handling is probably wrong in terms of OAuth 1.0 but the way
laconica works. Moreover I dont know the right way either. */
} else {
$this->datastore->authorize_token($this->token->key);
$this->datastore->saveProfile($this->remote_user);
$this->datastore->saveSubscription($this->user->getIdentifierURI(),
$this->remote_user->getIdentifierURI(), $this->token);
if (!is_null($this->callback)) {
/* Callback wants to get some informations as well. */
$params = $this->user->asParameters('omb_listener', false);
$params['oauth_token'] = $this->token->key;
$params['omb_version'] = OMB_VERSION;
$callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
foreach ($params as $k => $v) {
$callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
OAuthUtil::urlencode_rfc3986($v) . '&';
} }
} return $xrds_writer->writeXRDS($this->user, $xrds_mapper);
} }
return array($callback, $this->token);
}
/** /**
* Echo an access token * Echo a request token
* *
* Outputs an access token for the query found in $_POST. OMB 0.1 specifies * Outputs an unauthorized request token for the query found in $_GET or
* that the access token request has to be a POST even if OAuth allows GET as * $_POST.
* well. *
* * @access public
* @access public */
**/ public function writeRequestToken()
public function writeAccessToken() { {
OMB_Helper::removeMagicQuotesFromRequest(); OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_access_token( echo $this->getOAuthServer()->fetch_request_token(
OAuthRequest::from_request());
}
/**
* Handle an user authorization request.
*
* Parses an authorization request. This includes OAuth and OMB
* verification.
* Throws exceptions on failures. Returns an OMB_Profile object representing
* the remote user.
*
* The OMB_Profile passed to the constructor of OMB_Service_Provider should
* not represent the user specified in the authorization request, but the
* one currently logged in to the service. This condition being satisfied,
* handleUserAuth will check whether the listener specified in the request
* is identical to the logged in user.
*
* @access public
*
* @return OMB_Profile The profile of the soon-to-be subscribed, i. e.
* remote user
*/
public function handleUserAuth()
{
OMB_Helper::removeMagicQuotesFromRequest();
/* Verify the request token. */
$this->token = $this->datastore->lookup_token(null, "request",
$_GET['oauth_token']);
if (is_null($this->token)) {
throw new OAuthException('The given request token has not been ' .
'issued by this service.');
}
/* Verify the OMB part. */
if ($_GET['omb_version'] !== OMB_VERSION) {
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
'Wrong OMB version ' .
$_GET['omb_version']);
}
if ($_GET['omb_listener'] !== $this->user->getIdentifierURI()) {
throw OMB_RemoteServiceException::forRequest(OAUTH_ENDPOINT_AUTHORIZE,
'Wrong OMB listener ' .
$_GET['omb_listener']);
}
foreach (array('omb_listenee', 'omb_listenee_profile',
'omb_listenee_nickname', 'omb_listenee_license') as $param) {
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
throw OMB_RemoteServiceException::forRequest(
OAUTH_ENDPOINT_AUTHORIZE,
"Required parameter '$param' not found");
}
}
/* Store given callback for later use. */
if (isset($_GET['oauth_callback']) && $_GET['oauth_callback'] !== '') {
$this->callback = $_GET['oauth_callback'];
if (!OMB_Helper::validateURL($this->callback)) {
throw OMB_RemoteServiceException::forRequest(
OAUTH_ENDPOINT_AUTHORIZE,
'Invalid callback URL specified');
}
}
$this->remote_user = OMB_Profile::fromParameters($_GET, 'omb_listenee');
return $this->remote_user;
}
/**
* Continue the OAuth dance after user authorization
*
* Performs the appropriate actions after user answered the authorization
* request.
*
* @param bool $accepted Whether the user granted authorization
*
* @access public
*
* @return array A two-component array with the values:
* - callback The callback URL or null if none given
* - token The authorized request token or null if not
* authorized.
*/
public function continueUserAuth($accepted)
{
$callback = $this->callback;
if (!$accepted) {
$this->datastore->revoke_token($this->token->key);
$this->token = null;
} else {
$this->datastore->authorize_token($this->token->key);
$this->datastore->saveProfile($this->remote_user);
$this->datastore->saveSubscription($this->user->getIdentifierURI(),
$this->remote_user->getIdentifierURI(),
$this->token);
if (!is_null($this->callback)) {
/* Callback wants to get some informations as well. */
$params = $this->user->asParameters('omb_listener', false);
$params['oauth_token'] = $this->token->key;
$params['omb_version'] = OMB_VERSION;
$callback .= (parse_url($this->callback, PHP_URL_QUERY) ? '&' : '?');
foreach ($params as $k => $v) {
$callback .= OAuthUtil::urlencode_rfc3986($k) . '=' .
OAuthUtil::urlencode_rfc3986($v) . '&';
}
}
}
return array($callback, $this->token);
}
/**
* Echo an access token
*
* Outputs an access token for the query found in $_POST. OMB 0.1 specifies
* that the access token request has to be a POST even if OAuth allows GET
* as well.
*
* @access public
*/
public function writeAccessToken()
{
OMB_Helper::removeMagicQuotesFromRequest();
echo $this->getOAuthServer()->fetch_access_token(
OAuthRequest::from_request('POST')); OAuthRequest::from_request('POST'));
}
/**
* Handle an updateprofile request
*
* Handles an updateprofile request posted to this service. Updates the
* profile through the OMB_Datastore.
*
* @access public
*
* @return OMB_Profile The updated profile
**/
public function handleUpdateProfile() {
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
$profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
$this->datastore->saveProfile($profile);
$this->finishOMBRequest();
return $profile;
}
/**
* Handle a postnotice request
*
* Handles a postnotice request posted to this service. Saves the notice
* through the OMB_Datastore.
*
* @access public
*
* @return OMB_Notice The received notice
**/
public function handlePostNotice() {
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
require_once 'notice.php';
$notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
$this->datastore->saveNotice($notice);
$this->finishOMBRequest();
return $notice;
}
/**
* Handle an OMB request
*
* Performs common OMB request handling.
*
* @param string $uri The URI defining the OMB endpoint being served
*
* @access protected
*
* @return array(OAuthRequest, OMB_Profile)
**/
protected function handleOMBRequest($uri) {
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request('POST');
$listenee = $req->get_parameter('omb_listenee');
try {
list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
} catch (OAuthException $e) {
header('HTTP/1.1 403 Forbidden');
// @debug hack
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee . ': ' . $e->getMessage());
// @end debug
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee);
} }
$version = $req->get_parameter('omb_version'); /**
if ($version !== OMB_VERSION) { * Handle an updateprofile request
header('HTTP/1.1 400 Bad Request'); *
throw OMB_RemoteServiceException::forRequest($uri, * Handles an updateprofile request posted to this service. Updates the
'Wrong OMB version ' . $version); * profile through the OMB_Datastore.
*
* @access public
*
* @return OMB_Profile The updated profile
*/
public function handleUpdateProfile()
{
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_UPDATEPROFILE);
$profile->updateFromParameters($req->get_parameters(), 'omb_listenee');
$this->datastore->saveProfile($profile);
$this->finishOMBRequest();
return $profile;
} }
$profile = $this->datastore->getProfile($listenee); /**
if (is_null($profile)) { * Handle a postnotice request
header('HTTP/1.1 400 Bad Request'); *
throw OMB_RemoteServiceException::forRequest($uri, * Handles a postnotice request posted to this service. Saves the notice
'Unknown remote profile ' . $listenee); * through the OMB_Datastore.
*
* @access public
*
* @return OMB_Notice The received notice
*/
public function handlePostNotice()
{
list($req, $profile) = $this->handleOMBRequest(OMB_ENDPOINT_POSTNOTICE);
$notice = OMB_Notice::fromParameters($profile, $req->get_parameters());
$this->datastore->saveNotice($notice);
$this->finishOMBRequest();
return $notice;
} }
$subscribers = $this->datastore->getSubscriptions($listenee); /**
if (count($subscribers) === 0) { * Handle an OMB request
header('HTTP/1.1 403 Forbidden'); *
throw OMB_RemoteServiceException::forRequest($uri, * Performs common OMB request handling.
'No subscriber for ' . $listenee); *
* @param string $uri The URI defining the OMB endpoint being served
*
* @access protected
*
* @return array(OAuthRequest, OMB_Profile)
*/
protected function handleOMBRequest($uri)
{
OMB_Helper::removeMagicQuotesFromRequest();
$req = OAuthRequest::from_request('POST');
$listenee = $req->get_parameter('omb_listenee');
try {
list($consumer, $token) = $this->getOAuthServer()->verify_request($req);
} catch (OAuthException $e) {
header('HTTP/1.1 403 Forbidden');
throw OMB_RemoteServiceException::forRequest($uri,
'Revoked accesstoken for ' . $listenee);
}
$version = $req->get_parameter('omb_version');
if ($version !== OMB_VERSION) {
header('HTTP/1.1 400 Bad Request');
throw OMB_RemoteServiceException::forRequest($uri,
'Wrong OMB version ' . $version);
}
$profile = $this->datastore->getProfile($listenee);
if (is_null($profile)) {
header('HTTP/1.1 400 Bad Request');
throw OMB_RemoteServiceException::forRequest($uri,
'Unknown remote profile ' . $listenee);
}
$subscribers = $this->datastore->getSubscriptions($listenee);
if (count($subscribers) === 0) {
header('HTTP/1.1 403 Forbidden');
throw OMB_RemoteServiceException::forRequest($uri,
'No subscriber for ' . $listenee);
}
return array($req, $profile);
} }
return array($req, $profile); /**
} * Finishes an OMB request handling
*
* Performs common OMB request handling finishing.
*
* @access protected
*/
protected function finishOMBRequest()
{
header('HTTP/1.1 200 OK');
header('Content-type: text/plain');
/* There should be no clutter but the version. */
echo "omb_version=" . OMB_VERSION;
}
/** /**
* Finishes an OMB request handling * Return an OAuthServer
* *
* Performs common OMB request handling finishing. * Checks whether the OAuthServer is null. If so, initializes it with a
* * default value. Returns the OAuth server.
* @access protected *
**/ * @access protected
protected function finishOMBRequest() { */
header('HTTP/1.1 200 OK'); protected function getOAuthServer()
header('Content-type: text/plain'); {
/* There should be no clutter but the version. */ if (is_null($this->oauth_server)) {
echo "omb_version=" . OMB_VERSION; $this->oauth_server = new OAuthServer($this->datastore);
} $this->oauth_server->add_signature_method(
/**
* Return an OAuthServer
*
* Checks whether the OAuthServer is null. If so, initializes it with a
* default value. Returns the OAuth server.
*
* @access protected
**/
protected function getOAuthServer() {
if (is_null($this->oauth_server)) {
$this->oauth_server = new OAuthServer($this->datastore);
$this->oauth_server->add_signature_method(
new OAuthSignatureMethod_HMAC_SHA1()); new OAuthSignatureMethod_HMAC_SHA1());
} }
return $this->oauth_server; return $this->oauth_server;
}
/**
* Publish a notice
*
* Posts an OMB notice. This includes storing the notice and posting it to
* subscribed users.
*
* @param OMB_Notice $notice The new notice
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting to
* them has raised; Empty array if no exception occured
**/
public function postNotice($notice) {
$uri = $this->user->getIdentifierURI();
/* $notice is passed by reference and may change. */
$this->datastore->saveNotice($notice);
$subscribers = $this->datastore->getSubscriptions($uri);
/* No one to post to. */
if (is_null($subscribers)) {
return array();
} }
require_once 'service_consumer.php'; /**
* Publish a notice
*
* Posts an OMB notice. This includes storing the notice and posting it to
* subscribed users.
*
* @param OMB_Notice $notice The new notice
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting
* to them has raised; Empty array if no exception occured
*/
public function postNotice($notice)
{
$uri = $this->user->getIdentifierURI();
$err = array(); /* $notice is passed by reference and may change. */
foreach($subscribers as $subscriber) { $this->datastore->saveNotice($notice);
try { $subscribers = $this->datastore->getSubscriptions($uri);
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->postNotice($notice);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
}
/** /* No one to post to. */
* Publish a profile update if (is_null($subscribers)) {
* return array();
* Posts the current profile as an OMB profile update. This includes updating }
* the stored profile and posting it to subscribed users.
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting to
* them has raised; Empty array if no exception occured
**/
public function updateProfile() {
$uri = $this->user->getIdentifierURI();
$this->datastore->saveProfile($this->user); require_once 'service_consumer.php';
$subscribers = $this->datastore->getSubscriptions($uri);
/* No one to post to. */ $err = array();
if (is_null($subscribers)) { foreach ($subscribers as $subscriber) {
return array(); try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri,
$this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->postNotice($notice);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
} }
require_once 'service_consumer.php'; /**
* Publish a profile update
*
* Posts the current profile as an OMB profile update. This includes
* updating the stored profile and posting it to subscribed users.
*
* @access public
*
* @return array An array mapping subscriber URIs to the exception posting
* to them has raised; Empty array if no exception occured
*/
public function updateProfile()
{
$uri = $this->user->getIdentifierURI();
$err = array(); $this->datastore->saveProfile($this->user);
foreach($subscribers as $subscriber) { $subscribers = $this->datastore->getSubscriptions($uri);
try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri, $this->datastore); /* No one to post to. */
$service->setToken($subscriber['token'], $subscriber['secret']); if (is_null($subscribers)) {
$service->updateProfile($this->user); return array();
} catch (Exception $e) { }
$err[$subscriber['uri']] = $e;
continue; require_once 'service_consumer.php';
}
$err = array();
foreach ($subscribers as $subscriber) {
try {
$service = new OMB_Service_Consumer($subscriber['uri'], $uri,
$this->datastore);
$service->setToken($subscriber['token'], $subscriber['secret']);
$service->updateProfile($this->user);
} catch (Exception $e) {
$err[$subscriber['uri']] = $e;
continue;
}
}
return $err;
} }
return $err;
}
} }

View File

@ -1,9 +1,6 @@
<?php <?php
/** /**
* Exception stating that a requested service is not available * This file is part of libomb
*
* This exception is raised when OMB_Service is asked to call a service the remote
* server does not provide.
* *
* PHP version 5 * PHP version 5
* *
@ -20,12 +17,20 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
class OMB_UnsupportedServiceException extends Exception { */
/**
* Exception stating that a requested service is not available
*
* This exception is raised when OMB_Service is asked to call a service the
* remote server does not provide.
*/
class OMB_UnsupportedServiceException extends Exception
{
} }
?> ?>

View File

@ -1,10 +1,6 @@
<?php <?php
/** /**
* Map XRDS actions to URLs * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -21,13 +17,31 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
interface OMB_XRDS_Mapper { /**
public function getURL($action); * Map XRDS actions to URLs
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
*/
interface OMB_XRDS_Mapper
{
/**
* Fetch an URL for a specified action
*
* Returns the action URL for an action specified by the endpoint URI.
*
* @param string $action The endpoint URI
*
* @return string The action URL
*/
public function getURL($action);
} }
?> ?>

View File

@ -1,10 +1,6 @@
<?php <?php
/** /**
* Write OMB-specific XRDS * This file is part of libomb
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
* *
* PHP version 5 * PHP version 5
* *
@ -21,13 +17,30 @@
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* @package OMB * @package OMB
* @author Adrian Lang <mail@adrianlang.de> * @author Adrian Lang <mail@adrianlang.de>
* @copyright 2009 Adrian Lang * @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0
* @license http://www.gnu.org/licenses/agpl.html GNU AGPL 3.0 * @version 0.1a-20090828
**/ * @link http://adrianlang.de/libomb
*/
interface OMB_XRDS_Writer { /**
public function writeXRDS($user, $mapper); * Write OMB-specific XRDS
*
* This interface specifies classes which write the XRDS file announcing
* the OMB server. An instance of an implementing class should be passed to
* OMB_Service_Provider->writeXRDS.
*/
interface OMB_XRDS_Writer
{
/**
* Write XRDS
*
* Outputs a XRDS document specifying an OMB service.
*
* @param OMB_profile $user The target user for the OMB service
* @param OMB_XRDS_Mapper $mapper An OMB_XRDS_Mapper providing endpoint URLs
*/
public function writeXRDS($user, $mapper);
} }
?> ?>