diff options
Diffstat (limited to 'OAuth/src/Backend/ConsumerAcceptance.php')
-rw-r--r-- | OAuth/src/Backend/ConsumerAcceptance.php | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/OAuth/src/Backend/ConsumerAcceptance.php b/OAuth/src/Backend/ConsumerAcceptance.php new file mode 100644 index 00000000..da90914b --- /dev/null +++ b/OAuth/src/Backend/ConsumerAcceptance.php @@ -0,0 +1,274 @@ +<?php + +namespace MediaWiki\Extensions\OAuth\Backend; + +use Wikimedia\Rdbms\DBConnRef; + +/** + * (c) Aaron Schulz 2013, GPL + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + */ + +/** + * Representation of an OAuth consumer acceptance. + * Created when the user clicks through the OAuth authorization dialog, this allows + * the specified consumer to perform actions in the name of the user + * (subject to the grant and wiki restrictions stored in the acceptance object). + */ +class ConsumerAcceptance extends MWOAuthDAO { + /** @var int Unique ID */ + protected $id; + /** @var string Wiki ID the application can be used on (or "*" for all) */ + protected $wiki; + /** @var int Publisher user ID (on central wiki) */ + protected $userId; + /** @var int */ + protected $consumerId; + /** @var string Hex token */ + protected $accessToken; + /** @var string Secret HMAC key */ + protected $accessSecret; + /** @var array List of grants */ + protected $grants; + /** @var string TS_MW timestamp of acceptance */ + protected $accepted; + /** @var string */ + protected $oauthVersion; + + protected static function getSchema() { + return [ + 'table' => 'oauth_accepted_consumer', + 'fieldColumnMap' => [ + 'id' => 'oaac_id', + 'wiki' => 'oaac_wiki', + 'userId' => 'oaac_user_id', + 'consumerId' => 'oaac_consumer_id', + 'accessToken' => 'oaac_access_token', + 'accessSecret' => 'oaac_access_secret', + 'grants' => 'oaac_grants', + 'accepted' => 'oaac_accepted', + 'oauth_version' => 'oaac_oauth_version', + ], + 'idField' => 'id', + 'autoIncrField' => 'id', + ]; + } + + protected static function getFieldPermissionChecks() { + return [ + 'wiki' => 'userCanSee', + 'userId' => 'userCanSee', + 'consumerId' => 'userCanSee', + 'accessToken' => 'userCanSeePrivate', + 'accessSecret' => 'userCanSeeSecret', + 'grants' => 'userCanSee', + 'accepted' => 'userCanSee', + 'oauth_version' => 'userCanSee', + ]; + } + + /** + * @param DBConnRef $db + * @param string $token Access token + * @param int $flags MWOAuthConsumerAcceptance::READ_* bitfield + * @return ConsumerAcceptance|bool + */ + public static function newFromToken( DBConnRef $db, $token, $flags = 0 ) { + $row = $db->selectRow( static::getTable(), + array_values( static::getFieldColumnMap() ), + [ 'oaac_access_token' => (string)$token ], + __METHOD__, + ( $flags & self::READ_LOCKING ) ? [ 'FOR UPDATE' ] : [] + ); + + if ( $row ) { + $consumer = new self(); + $consumer->loadFromRow( $db, $row ); + return $consumer; + } else { + return false; + } + } + + /** + * @param DBConnRef $db + * @param string $userId of user who authorized (central wiki's id) + * @param Consumer $consumer + * @param string $wiki wiki associated with the acceptance + * @param int $flags MWOAuthConsumerAcceptance::READ_* bitfield + * @param string $oauthVersion + * @return ConsumerAcceptance|bool + */ + public static function newFromUserConsumerWiki( + DBConnRef $db, $userId, $consumer, + $wiki, $flags = 0, $oauthVersion = Consumer::OAUTH_VERSION_1 + ) { + $row = $db->selectRow( static::getTable(), + array_values( static::getFieldColumnMap() ), + [ + 'oaac_user_id' => (int)$userId, + 'oaac_consumer_id' => $consumer->getId(), + 'oaac_oauth_version' => $oauthVersion, + 'oaac_wiki' => (string)$wiki + ], + __METHOD__, + ( $flags & self::READ_LOCKING ) ? [ 'FOR UPDATE' ] : [] + ); + + if ( $row ) { + $consumer = new self(); + $consumer->loadFromRow( $db, $row ); + return $consumer; + } else { + return false; + } + } + + /** + * Database ID. + * @return int + */ + public function getId() { + return $this->get( 'id' ); + } + + /** + * Wiki on which the user has authorized the consumer to access their account. Wiki ID or '*' + * for all. + * @return string + */ + public function getWiki() { + return $this->get( 'wiki' ); + } + + /** + * Central user ID of the authorizing user. + * @return int + */ + public function getUserId() { + return $this->get( 'userId' ); + } + + /** + * Database ID of the consumer. + * @return int + */ + public function getConsumerId() { + return $this->get( 'consumerId' ); + } + + /** + * The access token for the OAuth protocol + * @return string + */ + public function getAccessToken() { + return $this->get( 'accessToken' ); + } + + /** + * Secret key used to derive the access secret for the OAuth protocol. + * The actual access secret will be calculated via MWOAuthUtils::hmacDBSecret() to mitigate + * DB leaks. + * @return string + */ + public function getAccessSecret() { + return $this->get( 'accessSecret' ); + } + + /** + * The list of grants which have been granted. + * @return string[] + */ + public function getGrants() { + return $this->get( 'grants' ); + } + + /** + * Date of the authorization, in TS_MW format. + * @return string + */ + public function getAccepted() { + return $this->get( 'accepted' ); + } + + /** + * @return int + */ + public function getOAuthVersion() { + return (int)$this->get( 'oauth_version' ); + } + + protected function normalizeValues() { + $this->userId = (int)$this->userId; + $this->consumerId = (int)$this->consumerId; + $this->accepted = wfTimestamp( TS_MW, $this->accepted ); + $this->grants = (array)$this->grants; // sanity + } + + protected function encodeRow( DBConnRef $db, $row ) { + if ( (int)$row['oaac_user_id'] === 0 ) { + throw new MWOAuthException( 'mwoauth-consumer-access-no-user' ); + } + // For compatibility with other wikis in the farm, un-remap some grants + foreach ( Consumer::$mapBackCompatGrants as $old => $new ) { + while ( ( $i = array_search( $new, $row['oaac_grants'], true ) ) !== false ) { + $row['oaac_grants'][$i] = $old; + } + } + + $row['oaac_grants'] = \FormatJson::encode( $row['oaac_grants'] ); + $row['oaac_accepted'] = $db->timestamp( $row['oaac_accepted'] ); + return $row; + } + + protected function decodeRow( DBConnRef $db, $row ) { + $row['oaac_grants'] = \FormatJson::decode( $row['oaac_grants'], true ); + $row['oaac_accepted'] = wfTimestamp( TS_MW, $row['oaac_accepted'] ); + + // For backwards compatibility, remap some grants + foreach ( Consumer::$mapBackCompatGrants as $old => $new ) { + while ( ( $i = array_search( $old, $row['oaac_grants'], true ) ) !== false ) { + $row['oaac_grants'][$i] = $new; + } + } + + return $row; + } + + protected function userCanSee( $name, \IContextSource $context ) { + $centralUserId = Utils::getCentralIdFromLocalUser( $context->getUser() ); + if ( $this->userId != $centralUserId + && !$context->getUser()->isAllowed( 'mwoauthviewprivate' ) + ) { + return $context->msg( 'mwoauth-field-private' ); + } else { + return true; + } + } + + protected function userCanSeePrivate( $name, \IContextSource $context ) { + if ( !$context->getUser()->isAllowed( 'mwoauthviewprivate' ) ) { + return $context->msg( 'mwoauth-field-private' ); + } else { + return $this->userCanSee( $name, $context ); + } + } + + protected function userCanSeeSecret( $name, \IContextSource $context ) { + return $context->msg( 'mwoauth-field-private' ); + } +} |