Aaron Schulz has submitted this change and it was merged.

Change subject: Adding re-authorize flow
......................................................................


Adding re-authorize flow

Re-authorization form is ugly, and probably needs some UX help, but
the basic functionality is there.

Change-Id: Ia40cea2ad2346c514e6bf661d4ba6efc07caebe9
---
M backend/MWOAuthConsumerAcceptance.php
M backend/MWOAuthServer.php
M frontend/language/MWOAuth.i18n.php
M frontend/specialpages/SpecialMWOAuth.php
4 files changed, 140 insertions(+), 25 deletions(-)

Approvals:
  Aaron Schulz: Verified; Looks good to me, approved



diff --git a/backend/MWOAuthConsumerAcceptance.php 
b/backend/MWOAuthConsumerAcceptance.php
index f0d231b..2cd107b 100644
--- a/backend/MWOAuthConsumerAcceptance.php
+++ b/backend/MWOAuthConsumerAcceptance.php
@@ -86,6 +86,34 @@
                }
        }
 
+       /**
+        * @param DBConnRef $db
+        * @param String $userId of user who authorized (central wiki's id)
+        * @param MWOAuthConsumer $consumer
+        * @param String $wiki wiki associated with the acceptance
+        * @param integer $flags MWOAuthConsumerAcceptance::READ_* bitfield
+        * @return MWOAuthConsumerAcceptance|bool
+        */
+       public static function newFromUserConsumerWiki( DBConnRef $db, $userId, 
$consumer, $wiki, $flags = 0 ) {
+               $row = $db->selectRow( static::getTable(),
+                       array_values( static::getFieldColumnMap() ),
+                       array( 'oaac_user_id' => $userId,
+                               'oaac_consumer_id' => $consumer->get( 'id' ),
+                               'oaac_wiki' => $wiki
+                       ),
+                       __METHOD__,
+                       ( $flags & self::READ_LOCKING ) ? array( 'FOR UPDATE' ) 
: array()
+               );
+
+               if ( $row ) {
+                       $consumer = new self();
+                       $consumer->loadFromRow( $db, $row );
+                       return $consumer;
+               } else {
+                       return false;
+               }
+       }
+
        protected function normalizeValues() {
                $this->userId = (int)$this->userId;
                $this->consumerId = (int)$this->consumerId;
diff --git a/backend/MWOAuthServer.php b/backend/MWOAuthServer.php
index 9b7fd7e..28d9996 100644
--- a/backend/MWOAuthServer.php
+++ b/backend/MWOAuthServer.php
@@ -82,11 +82,12 @@
         * generate the callback URL where we will redirect our user back to 
the consumer.
         * @param String $consumerKey
         * @param String $requestTokenKey
-        * @param User $mwUser user authorizing the request
+        * @param User $mwUser user authorizing the request (local user)
+        * @param bool $update update the grants/wiki to those requested by 
consumer
         * @return String the callback URL to redirect the user
         * @throws MWOAuthException
         */
-       public function authorize( $consumerKey, $requestTokenKey, User $mwUser 
) {
+       public function authorize( $consumerKey, $requestTokenKey, User 
$mwUser, $update ) {
                // Check that user and consumer are in good standing
                if ( $mwUser->isBlocked() ) {
                        throw new MWOAuthException( 
'mwoauthserver-insufficient-rights' );
@@ -101,18 +102,17 @@
                }
 
                // Generate and Update the tokens:
-               // * Generate Access token, and add a pointer to it in the 
request token
                // * Generate a new Verification code, and add it to the 
request token
-               // * Resave Request token with
-               $accessToken = MWOAuthDataStore::newToken();
+               // * Either add or update the authorization
+               // ** Generate a new access token if this is a new authorization
+               // * Resave request token with the access token
+
                $verifyCode = MWCryptRand::generateHex( 32, true);
                $requestToken = $this->data_store->lookup_token( $consumer, 
'request', $requestTokenKey );
                if ( !$requestToken || !( $requestToken instanceof MWOAuthToken 
) ) {
                        throw new MWOAuthException( 
'mwoauthserver-invalid-request-token' );
                }
                $requestToken->addVerifyCode( $verifyCode );
-               $requestToken->addAccessKey( $accessToken->key );
-               $this->data_store->updateRequestToken( $requestToken, $consumer 
);
 
                // CentralAuth may abort here if there is no global account for 
this user
                $userId = MWOAuthUtils::getCentralIdFromLocalUser( $mwUser );
@@ -120,23 +120,81 @@
                        throw new MWOAuthException( 
'mwoauthserver-invalid-user' );
                }
 
-               // Add the Authorization to the database
+               // Authorization Token
                $dbw = MWOAuthUtils::getCentralDB( DB_MASTER );
-               $cmra = MWOAuthConsumerAcceptance::newFromArray( array(
-                       'id'           => null,
-                       'wiki'         => $consumer->get( 'wiki' ),
-                       'userId'       => $userId,
-                       'consumerId'   => $consumer->get( 'id' ),
-                       'accessToken'  => $accessToken->key,
-                       'accessSecret' => $accessToken->secret,
-                       'grants'       => $consumer->get( 'grants' ),
-                       'accepted'     => wfTimestampNow()
-               ) );
-               $cmra->save( $dbw );
 
-               wfDebugLog( 'OAuth', "Verification code 
{$requestToken->getVerifyCode()} for " .
-                       "$requestTokenKey (client: $consumerKey)" );
+               // Check if this authorization exists
+               $cmra = $this->getCurrentAuthorization( $mwUser, $consumer );
 
+               if ( $update ) {
+                       // This should be an update to an existing authorization
+                       if ( !$cmra ) {
+                               // update requested, but no existing key
+                               throw new MWOAuthException( 
'mwoauthserver-invalid-request' );
+                       }
+                       $cmra->setFields( array(
+                               'wiki'   => $consumer->get( 'wiki' ),
+                               'grants' => $consumer->get( 'grants' )
+                       ) );
+                       $cmra->save( $dbw );
+                       $accessToken = new MWOAuthToken( $cmra->get( 
'accessToken' ), '' );
+               } elseif ( !$cmra ) {
+                       // Add the Authorization to the database
+                       $accessToken = MWOAuthDataStore::newToken();
+                       $cmra = MWOAuthConsumerAcceptance::newFromArray( array(
+                               'wiki'         => $consumer->get( 'wiki' ),
+                               'userId'       => $userId,
+                               'consumerId'   => $consumer->get( 'id' ),
+                               'accessToken'  => $accessToken->key,
+                               'accessSecret' => $accessToken->secret,
+                               'grants'       => $consumer->get( 'grants' ),
+                               'accepted'     => wfTimestampNow()
+                       ) );
+                       $cmra->save( $dbw );
+               } else {
+                       // Authorization exists, no updates requested, so no 
changes to the db
+                       $accessToken = new MWOAuthToken( $cmra->get( 
'accessToken' ), '' );
+               }
+
+               $requestToken->addAccessKey( $accessToken->key );
+               $this->data_store->updateRequestToken( $requestToken, $consumer 
);
+               wfDebugLog( 'OAuth', "Verification code 
{$requestToken->getVerifyCode()} for $requestTokenKey (client: $consumerKey)" );
                return $consumer->generateCallbackUrl( 
$requestToken->getVerifyCode(), $requestTokenKey );
        }
+
+       /**
+        * Attempts to get an authorization by this user, for this consumer. 
First attempts
+        * to fine an acceptance for the current wiki, when for '*' wikis. In 
theory, a user
+        * could authorize different grants on a particular wiki vs. all wikis, 
for a given
+        * consumer.
+        * @param User $mwUser (local wiki user) User who may or may not have 
authorizations
+        * @param MWOAuthConsumer $consumer
+        * @param integer $flags MWOAuthConsumerAcceptance::READ_* bitfield
+        * @return MWOAuthConsumerAcceptance
+        */
+       public function getCurrentAuthorization( User $mwUser, $consumer ) {
+               $dbr = MWOAuthUtils::getCentralDB( DB_SLAVE );
+
+               $centralUserId = MWOAuthUtils::getCentralIdFromLocalUser( 
$mwUser );
+               if ( !$centralUserId ) {
+                       throw new MWOAuthException( 
'mwoauthserver-invalid-user' );
+               }
+
+               $cmra = MWOAuthConsumerAcceptance::newFromUserConsumerWiki(
+                       $dbr,
+                       $centralUserId,
+                       $consumer,
+                       wfWikiID()
+               );
+               if ( !$cmra ) {
+                       $cmra = 
MWOAuthConsumerAcceptance::newFromUserConsumerWiki(
+                               $dbr,
+                               $centralUserId,
+                               $consumer,
+                               '*'
+                       );
+               }
+               return $cmra;
+       }
+
 }
diff --git a/frontend/language/MWOAuth.i18n.php 
b/frontend/language/MWOAuth.i18n.php
index 6d770d6..c22e798 100644
--- a/frontend/language/MWOAuth.i18n.php
+++ b/frontend/language/MWOAuth.i18n.php
@@ -184,9 +184,14 @@
        'mwoauthserver-invalid-user-hookabort' => 'This user cannot use OAuth.',
 
        'mwoauth-form-description' => 'The following application is requesting 
to use MediaWiki on your behalf. The application will be able to perform any 
actions that are allowed with the list if requested rights below. Only allow 
applications that you trust to use these permissions as you would.',
+       'mwoauth-form-existing' => "'''This application is requesting 
authorization to MediaWiki on your behalf, but you have already granted 
access:'''
+*  Grants: $1
+*  Wiki: $2
+*  Authorized on: $3",
        'mwoauth-form-legal' => '',
        'mwoauth-form-button-approve' => 'Yes, allow',
        'mwoauth-form-confirmation' => 'Allow this application to act on your 
behalf?',
+       'mwoauth-form-confirmation-update' => 'Update this authorization to the 
requested privileges. Leaving this unchecked will keep your existing 
authorizations',
        'mwoauth-authorize-form' => 'Application details:',
        'mwoauth-authorize-form-user' => 'Application author: $1',
        'mwoauth-authorize-form-name' => 'Application name: $1',
diff --git a/frontend/specialpages/SpecialMWOAuth.php 
b/frontend/specialpages/SpecialMWOAuth.php
index 651df66..f4e6ea0 100644
--- a/frontend/specialpages/SpecialMWOAuth.php
+++ b/frontend/specialpages/SpecialMWOAuth.php
@@ -24,6 +24,7 @@
                                        $this->returnToken( $token, $format );
                                        break;
                                case 'authorize':
+                                       //TODO: most of the "controller" logic 
should be move somewhere else
                                        $mwUser = $this->getUser();
                                        $requestToken = $request->getVal( 
'oauth_token', false ); //oauth_token
                                        $consumerKey = $request->getVal( 
'oauth_consumer_key', false ); //oauth_key
@@ -60,22 +61,31 @@
                                                $callback = 
$oauthServer->authorize(
                                                        $consumerKey,
                                                        $requestToken,
-                                                       $mwUser
+                                                       $mwUser,
+                                                       $request->getCheck( 
'grants-update' )
                                                );
                                                // Redirect to callback url
                                                $this->doRedirect( $callback );
                                        } else {
+                                               $dbr = 
MWOAuthUtils::getCentralDB( DB_SLAVE );
                                                $consumer = 
MWOAuthDAOAccessControl::wrap(
-                                                               
MWOAuthConsumer::newFromKey( MWOAuthUtils::getCentralDB( DB_SLAVE ), 
$consumerKey ),
+                                                               
MWOAuthConsumer::newFromKey( $dbr, $consumerKey ),
                                                                
$this->getContext()
                                                );
                                                if ( !$consumer ) {
                                                        throw new 
MWOAuthException( 'mwoauth-bad-request' );
                                                }
+                                               // Check if this user has 
authorized grants for this consumer previously
+                                               $existing = 
$oauthServer->getCurrentAuthorization(
+                                                       $mwUser,
+                                                       $consumer->getDAO()
+                                               );
+
                                                $formParams = array(
                                                        'consumerKey' => 
$consumerKey,
                                                        'requestToken' => 
$requestToken,
                                                        'grants' => 
$consumer->get( 'grants' ),
+                                                       'existing' => $existing,
                                                        'description' => array (
                                                                'user' => 
User::newFromId( $consumer->get( 'userId') )->getName(),
                                                                'name' => 
$consumer->get( 'name'),
@@ -117,7 +127,18 @@
                $user = $this->getUser();
 
                $out->addSubtitle( $this->msg( 'mwoauth-desc' )->escaped() );
-               $out->addHTML( Html::element( 'p', array(), $this->msg( 
'mwoauth-form-description' )->text() ) );
+               if ( !$params['existing'] ) {
+                       $out->addHTML( Html::element( 'p', array(), $this->msg( 
'mwoauth-form-description' )->text() ) );
+               } else {
+                       // User has already authorized this consumer
+                       $lang = $this->getLanguage();
+                       $grants = $params['existing']->get( 'grants');
+                       $grantList = is_null( $grants ) ? $this->msg( 
'mwoauth-grants-nogrants' )->text() : $lang->commaList( $grants );
+                       $out->addWikiMsg( 'mwoauth-form-existing',
+                               $grantList,
+                               $params['existing']->get( 'wiki'),
+                               $params['existing']->get( 'accepted' ) );
+               }
                $out->addHTML( Html::element( 'p', array(), $this->msg( 
'mwoauth-form-legal' )->text() ) );
 
                $out->addHTML( Html::element( 'p', array(), $this->msg( 
'mwoauth-authorize-form' )->text() ) );
@@ -138,7 +159,10 @@
                $out->addHTML( Html::rawElement( 'ul', array(), $description ) 
);
 
                $out->addHTML( $this->getGrantsHtml( $params['grants'] ) );
-
+               if ( $params['existing'] ) {
+                       // Checkbox to allow the user to update their 
permission to match the Consumer's request
+                       $fields['mwoauth-form-confirmation-update'] = 
Xml::check( 'grants-update', false );
+               }
                $fields['mwoauth-form-confirmation'] = Xml::submitButton( 
$this->msg( 'mwoauth-form-button-approve' )->text() );
                $form = Xml::buildForm( $fields );
                $form = Xml::fieldset( null, $form );

-- 
To view, visit https://gerrit.wikimedia.org/r/74543
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ia40cea2ad2346c514e6bf661d4ba6efc07caebe9
Gerrit-PatchSet: 8
Gerrit-Project: mediawiki/extensions/OAuth
Gerrit-Branch: master
Gerrit-Owner: CSteipp <[email protected]>
Gerrit-Reviewer: Aaron Schulz <[email protected]>
Gerrit-Reviewer: CSteipp <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to