Aaron Schulz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/82783


Change subject: Made Special:MWOAuth use HTMLForm
......................................................................

Made Special:MWOAuth use HTMLForm

Change-Id: Ia69737fb661f5a9f3fbb862d1af7a3869f2a59e0
---
M control/MWOAuthConsumerAcceptanceSubmitControl.php
M frontend/language/MWOAuth.i18n.php
M frontend/specialpages/SpecialMWOAuth.php
3 files changed, 197 insertions(+), 172 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/OAuth 
refs/changes/83/82783/1

diff --git a/control/MWOAuthConsumerAcceptanceSubmitControl.php 
b/control/MWOAuthConsumerAcceptanceSubmitControl.php
index b23444f..ee468d3 100644
--- a/control/MWOAuthConsumerAcceptanceSubmitControl.php
+++ b/control/MWOAuthConsumerAcceptanceSubmitControl.php
@@ -41,14 +41,9 @@
        protected function getRequiredFields() {
                return array(
                        'accept'    => array(
-                               'consumerKey'  => '/^[0-9a-f]{32}$/',
-                               'requestToken' => '/^[0-9a-f]{32}$/',
-                               'wiki'         => function( $s ) {
-                                       return WikiMap::getWiki( $s ) || $s === 
'*'; },
-                               'grants'       => function( $s ) {
-                                       $grants = FormatJSON::decode( $s, true 
);
-                                       return is_array( $grants ) && 
MWOAuthUtils::grantsAreValid( $grants );
-                               }
+                               'consumerKey'   => '/^[0-9a-f]{32}$/',
+                               'requestToken'  => '/^[0-9a-f]{32}$/',
+                               'confirmUpdate' => '/^[01]$/',
                        ),
                        'update'   => array(
                                'acceptanceId' => '/^\d+$/',
@@ -90,35 +85,33 @@
                }
 
                switch ( $action ) {
-               /*
                case 'accept': // @TODO: unused (WIP)
                        $cmr = MWOAuthConsumer::newFromKey( $dbw, 
$this->vals['consumerKey'] );
                        if ( !$cmr ) {
                                return $this->failure( 'invalid_consumer_key', 
'mwoauth-invalid-consumer-key' );
                        } elseif ( $cmr->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
-                               && !$consumer->isPendingAndOwnedBy( $mwUser ) 
// let publisher test this
+                               && !$cmr->isPendingAndOwnedBy( $user ) // let 
publisher test this
                        ) {
                                return $this->failure( 'permission_denied', 
'badaccess-group0' );
                        }
 
-                       // @TODO: handle exceptions
-                       $oauthServer = MWOAuthUtils::newMWOAuthServer();
-                       $callback = $oauthServer->authorize(
-                               $this->vals['consumerKey'], 
$this->vals['requestToken'], $this->getUser() );
+                       try {
+                               $oauthServer = MWOAuthUtils::newMWOAuthServer();
+                               $callback = $oauthServer->authorize(
+                                       $this->vals['consumerKey'],
+                                       $this->vals['requestToken'],
+                                       $this->getUser(),
+                                       $this->vals['confirmUpdate']
+                               );
+                       } catch ( MWOAuthException $exception ) {
+                               return $this->failure( 'oauth_exception',
+                                       'mwoauth-oauth-exception', 
$exception->getMessage() );
+                       } catch ( OAuthException $exception ) {
+                               return $this->failure( 'oauth_exception',
+                                       'mwoauth-oauth-exception', 
$exception->getMessage() );
+                       }
 
-                       // WIP: PUT THIS IN authorize()
-                       $cmra = MWOAuthConsumerAcceptance::newFromArray( array(
-                               'wiki'         => $this->vals['wiki'],
-                               'userId'       => $centralUserId,
-                               'consumerId'   => $cmr->getId(),
-                               'accessToken'  => ...,
-                               'accessSecret' => ...,
-                               'grants'       => FormatJSON::decode( 
$this->vals['grants'], true ),
-                               'accepted'     => wfTimestampNow()
-                       ) );
-                       return $this->success( $cmra );
-                       $cmra->save();
-               */
+                       return $this->success( array( 'callbackUrl' => 
$callback ) );
                case 'update':
                        $cmra = MWOAuthConsumerAcceptance::newFromId( $dbw, 
$this->vals['acceptanceId'] );
                        if ( !$cmra ) {
diff --git a/frontend/language/MWOAuth.i18n.php 
b/frontend/language/MWOAuth.i18n.php
index 9e4d3f6..a821a5c 100644
--- a/frontend/language/MWOAuth.i18n.php
+++ b/frontend/language/MWOAuth.i18n.php
@@ -246,6 +246,7 @@
        'mwoauth-grant-viewdeleted' => 'View deleted information',
        'mwoauth-grant-viewmywatchlist' => 'View your watchlist',
 
+       'mwoauth-oauth-exception' => 'An error occurred in the OAuth protocal: 
$1.',
        'mwoauth-callback-not-oob' => 'oauth_callback must be set, and must be 
set to "oob" (case-sensitive)',
 
        'right-mwoauthproposeconsumer' => 'Propose new OAuth consumers',
@@ -382,6 +383,8 @@
        'mwoauth-invalid-consumer-key' => 'Used as failure message.',
        'mwoauth-invalid-access-token' => 'Used as failure message.',
        'mwoauth-consumer-conflict' => 'Used as failure message.',
+       'mwoauth-oauth-exception' => 'Used as failure message. Parameters:
+* $1 - Exception message text',
        'mwoauth-consumer-stage-proposed' => 
'{{Related|Mwoauth-consumer-stage}}',
        'mwoauth-consumer-stage-rejected' => '{{Related|Mwoauth-consumer-stage}}
 {{Identical|Rejected}}',
diff --git a/frontend/specialpages/SpecialMWOAuth.php 
b/frontend/specialpages/SpecialMWOAuth.php
index 5420a99..1e67f3d 100644
--- a/frontend/specialpages/SpecialMWOAuth.php
+++ b/frontend/specialpages/SpecialMWOAuth.php
@@ -1,5 +1,26 @@
 <?php
+/*
+ (c) Chris Steipp, 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
+*/
+
+/**
+ * Page that handles OAuth consumer authorization and token exchange
+ */
 class SpecialMWOAuth extends UnlistedSpecialPage {
        function __construct() {
                parent::__construct( 'MWOAuth' );
@@ -7,6 +28,8 @@
 
        public function execute( $subpage ) {
                $this->setHeaders();
+
+               $user = $this->getUser();
                $request = $this->getRequest();
                $format = $request->getVal( 'format', 'raw' );
                if ( !in_array( $subpage, array( 'initiate', 'authorize', 
'verified', 'token' ) ) ) {
@@ -14,113 +37,47 @@
                }
 
                try {
-                       $oauthServer = MWOAuthUtils::newMWOAuthServer();
                        switch ( $subpage ) {
                                case 'initiate':
-                                       $OAuthRequest = 
MWOAuthRequest::fromRequest( $request );
-                                       wfDebugLog( 'OAuth', __METHOD__ . ": 
Consumer '{$OAuthRequest->getConsumerKey()}' getting temporary credentials" );
+                                       $oauthServer = 
MWOAuthUtils::newMWOAuthServer();
+                                       $oauthRequest = 
MWOAuthRequest::fromRequest( $request );
+                                       wfDebugLog( 'OAuth', __METHOD__ . ": 
Consumer " .
+                                               
"'{$oauthRequest->getConsumerKey()}' getting temporary credentials" );
                                        // fetch_request_token does the 
version, freshness, and sig checks
-                                       $token = 
$oauthServer->fetch_request_token( $OAuthRequest );
+                                       $token = 
$oauthServer->fetch_request_token( $oauthRequest );
                                        $this->returnToken( $token, $format );
                                        break;
                                case 'authorize':
-                                       //TODO: most of the "controller" logic 
should be move somewhere else
-                                       $format = $request->getVal( 'format', 
'html' );
-                                       $mwUser = $this->getUser();
-                                       $requestToken = $request->getVal( 
'oauth_token', false ); //oauth_token
-                                       $consumerKey = $request->getVal( 
'oauth_consumer_key', false ); //oauth_key
-                                       wfDebugLog( 'OAuth', __METHOD__ . ": 
doing 'authorize' with '$requestToken' '$consumerKey' for 
'{$mwUser->getName()}'" );
-                                       if ( !$requestToken || !$consumerKey ) {
-                                               throw new MWOAuthException( 
'mwoauth-bad-request' );
-                                       }
+                                       // Hack: prefix needed for HTMLForm
+                                       $requestToken = $request->getVal( 
'wprequestToken',
+                                               $request->getVal( 'oauth_token' 
) );
+                                       $consumerKey = $request->getVal( 
'wpconsumerKey',
+                                               $request->getVal( 
'oauth_consumer_key' ) );
+                                       wfDebugLog( 'OAuth', __METHOD__ . ": 
doing 'authorize' with " .
+                                               "'$requestToken' '$consumerKey' 
for '{$user->getName()}'" );
                                        // TODO? Test that $requestToken exists 
in memcache
-
-                                       if ( $mwUser->isAnon() ) {
-                                               //redirect to login
+                                       if ( $user->isAnon() ) {
+                                               // Redirect to login page
                                                $query['returnto'] = 
$this->getTitle( 'authorize' )->getPrefixedText();
                                                $query['returntoquery'] = 
wfArrayToCgi( array(
-                                                       'oauth_token' => 
$requestToken,
+                                                       'oauth_token'        => 
$requestToken,
                                                        'oauth_consumer_key' => 
$consumerKey
                                                ) );
                                                $loginPage = 
SpecialPage::getTitleFor( 'UserLogin' );
                                                $url = $loginPage->getLocalURL( 
$query );
-                                               $this->doRedirect( $url );
-                                               return;
-                                       }
-
-                                       // Check to make sure this user is the 
same user
-                                       // on the central wiki
-                                       $centralId = 
MWOAuthUtils::getCentralIdFromLocalUser( $mwUser );
-                                       if ( !$centralId ) {
-                                               // For now, just abort and give 
them hints to fix in
-                                               // the error message. TODO: if 
we can fix the issue with
-                                               // a few redirects, do that 
here.
-                                               throw new MWOAuthException( 
'mwoauth-authorize-form-invalid-user' );
-                                       }
-
-                                       if ( $request->getVal( 'doAuthorize', 
false ) ) {
-                                               // Require POST
-                                               if ( !$request->wasPosted() ) {
-                                                       throw new 
MWOAuthException( 'mwoauth-not-posted' );
-                                               }
-
-                                               // Check csrf token
-                                               $CSRFToken = $request->getVal( 
'formToken', false );
-                                               if ( !$mwUser->matchEditToken( 
$CSRFToken, 'OAuth:Authorize' ) ) {
-                                                       throw new 
MWOAuthException( 'mwoauth-bad-csrf-token' );
-                                               }
-                                               // Create Grant
-                                               $callback = 
$oauthServer->authorize(
-                                                       $consumerKey,
-                                                       $requestToken,
-                                                       $mwUser,
-                                                       $request->getCheck( 
'grants-update' )
-                                               );
-                                               // Redirect to callback url
-                                               $this->doRedirect( $callback );
+                                               $this->getOutput()->redirect( 
$url );
                                        } else {
-                                               $dbr = 
MWOAuthUtils::getCentralDB( DB_SLAVE );
-                                               $consumer = 
MWOAuthDAOAccessControl::wrap(
-                                                       
MWOAuthConsumer::newFromKey( $dbr, $consumerKey ),
-                                                       $this->getContext()
-                                               );
-                                               if ( !$consumer ) {
-                                                       throw new 
MWOAuthException( 'mwoauth-bad-request' );
-                                               }
-                                               if ( $consumer->get( 'stage' ) 
!== MWOAuthConsumer::STAGE_APPROVED
-                                                       && 
!$consumer->getDAO()->isPendingAndOwnedBy( $mwUser )
-                                               ) {
-                                                       throw new 
MWOAuthException( 'mwoauth-invalid-authorization-not-approved' );
-                                               }
-                                               // 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' => 
MWOAuthUtils::getCentralUserNameFromId(
-                                                                       
$consumer->get( 'userId' ) ),
-                                                               'name' => 
$consumer->get( 'name'),
-                                                               'version' => 
$consumer->get( 'version'),
-                                                               'description' 
=> $consumer->get( 'description'),
-                                                               'wiki' => 
$consumer->get( 'wiki'),
-                                                       )
-                                               );
-                                               $this->showAuthorizeForm( 
$formParams );
+                                               // Show form and redirect on 
submission for authorization
+                                               $this->handleAuthorizationForm( 
$requestToken, $consumerKey );
                                        }
                                        break;
                                case 'token':
-                                       $OAuthRequest = 
MWOAuthRequest::fromRequest( $request );
-                                       wfDebugLog( 'OAuth', "/token: 
'{$OAuthRequest->get_parameter( 'oauth_consumer_key' )}' getting temporary 
credentials" );
-                                       $token = 
$oauthServer->fetch_access_token( $OAuthRequest );
+                                       $oauthServer = 
MWOAuthUtils::newMWOAuthServer();
+                                       $oauthRequest = 
MWOAuthRequest::fromRequest( $request );
+                                       $consumerKey = 
$oauthRequest->get_parameter( 'oauth_consumer_key' );
+                                       wfDebugLog( 'OAuth', "/token: 
'{$consumerKey}' getting temporary credentials" );
+                                       $token = 
$oauthServer->fetch_access_token( $oauthRequest );
                                        $this->returnToken( $token, $format );
-
                                        break;
                                case 'verified':
                                        $format = $request->getVal( 'format', 
'html' );
@@ -141,7 +98,6 @@
                                default:
                                        throw new OAuthException( 
'mwoauth-invalid-method' );
                        }
-
                } catch ( MWOAuthException $exception ) {
                        wfDebugLog( 'OAuth', __METHOD__ . ": Exception " . 
$exception->getMessage() );
                        $this->showError( $exception->getMessage(), $format );
@@ -151,66 +107,139 @@
                }
        }
 
-       private function doRedirect( $url ) {
-               $output = $this->getOutput();
-               $output->redirect( $url );
-       }
+       // @TODO: cancel button
+       protected function handleAuthorizationForm( $requestToken, $consumerKey 
) {
+               $this->getOutput()->addSubtitle( $this->msg( 'mwoauth-desc' 
)->escaped() );
 
-       private function showAuthorizeForm( $params ) {
-               $out = $this->getOutput();
+               $user = $this->getUser();
+               $lang = $this->getLanguage();
 
-               $out->addSubtitle( $this->msg( 'mwoauth-desc' )->escaped() );
-               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() ) );
+               $dbr = MWOAuthUtils::getCentralDB( DB_SLAVE ); // @TODO: lazy 
handle
+               $oauthServer = MWOAuthUtils::newMWOAuthServer();
 
-               $out->addHTML( Html::element( 'p', array(), $this->msg( 
'mwoauth-authorize-form' )->text() ) );
-               $description = '';
-               foreach ( $params['description'] as $descKey => $descVal ) {
-                       // Messages: mwoauth-authorize-form-user, 
mwoauth-authorize-form-name,
-                       // mwoauth-authorize-form-description, 
mwoauth-authorize-form-version,
-                       // mwoauth-authorize-form-wiki
-                       $description .= Html::element(
-                               'li',
-                               array(),
-                               $this->msg( 'mwoauth-authorize-form-' . 
$descKey, $descVal )->text()
-                       );
-               }
-               $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 );
-
-               $form .= Html::hidden( 'oauth_consumer_key', 
$params['consumerKey'] );
-               $form .= Html::hidden( 'oauth_token', $params['requestToken'] );
-               $form .= Html::hidden( 'formToken', 
$this->getUser()->getEditToken( 'OAuth:Authorize' ) );
-               $form .= Html::hidden( 'doAuthorize', '1' );
-
-               $form = Xml::tags( 'form',
-                       array(
-                               'action' => $this->getTitle( 'authorize' 
)->getFullURL(),
-                               'method' => 'post'
-                       ),
-                       $form
+               $cmr = MWOAuthDAOAccessControl::wrap(
+                       MWOAuthConsumer::newFromKey( $dbr, $consumerKey ),
+                       $this->getContext()
                );
+               if ( !$cmr ) {
+                       throw new MWOAuthException( 'mwoauth-bad-request' );
+               } elseif ( $cmr->get( 'stage' ) !== 
MWOAuthConsumer::STAGE_APPROVED
+                       && !$cmr->getDAO()->isPendingAndOwnedBy( $user )
+               ) {
+                       throw new MWOAuthException( 
'mwoauth-invalid-authorization-not-approved' );
+               }
 
-               $out->addHTML( $form );
+               // Check if this user has authorized grants for this consumer 
previously
+               $existing = $oauthServer->getCurrentAuthorization( $user, 
$cmr->getDAO() );
+
+               $control = new MWOAuthConsumerAcceptanceSubmitControl( 
$this->getContext(), array(), $dbr );
+               $form = new HTMLForm(
+                       $control->registerValidators( array(
+                               'name' => array(
+                                       'type' => 'info',
+                                       'label-message' => 
'mwoauth-consumer-name',
+                                       'default' => $cmr->get( 'name' ),
+                                       'size' => '45'
+                               ),
+                               'version' => array(
+                                       'type' => 'info',
+                                       'label-message' => 
'mwoauth-consumer-version',
+                                       'default' => $cmr->get( 'version' ),
+                               ),
+                               'description' => array(
+                                       'type' => 'info',
+                                       'label-message' => 
'mwoauth-consumer-description',
+                                       'default' => $cmr->get( 'description' ),
+                                       'rows' => 5
+                               ),
+                               'wiki' => array(
+                                       'type' => 'info',
+                                       'label-message' => 
'mwoauth-consumer-wiki',
+                                       'default' => $cmr->get( 'wiki' ),
+                               ),
+                               'grants'  => array(
+                                       'type' => 'checkmatrix',
+                                       'label-message' => 
'mwoauthmanagemygrants-applicablegrantsallowed',
+                                       'columns' => array(
+                                               $this->msg( 
'mwoauthmanagemygrants-grantaccept' )->escaped() => 'grant'
+                                       ),
+                                       'rows' => array_combine(
+                                               array_map( 'htmlspecialchars',
+                                                       
MWOAuthUtils::grantNames( $cmr->get( 'grants' ) ) ),
+                                               $cmr->get( 'grants' )
+                                       ),
+                                       'default' => array_map(
+                                               function( $g ) { return 
"grant-$g"; },
+                                               $cmr->get( 'grants' )
+                                       ),
+                                       'tooltips' => array_combine(
+                                               array_map( 
'MWOAuthUtils::grantName', MWOAuthUtils::getValidGrants() ),
+                                               array_map(
+                                                       function( $rights ) use 
( $lang ) {
+                                                               return 
$lang->semicolonList( array_map(
+                                                                       
'User::getRightDescription', $rights ) );
+                                                       },
+                                                       
MWOAuthUtils::getRightsByGrant()
+                                               )
+                                       ),
+                                       'disabled' => true
+                               ),
+                               'action' => array(
+                                       'type'    => 'hidden',
+                                       'default' => 'accept',
+                                       'validation-callback' => null // 
different format
+                               ),
+                               'confirmUpdate' => array(
+                                       'type'    => 'hidden',
+                                       'default' => $existing ? 1 : 0,
+                                       'validation-callback' => null // 
different format
+                               ),
+                               'consumerKey' => array(
+                                       'type'    => 'hidden',
+                                       'default' => $consumerKey,
+                                       'validation-callback' => null // 
different format
+                               ),
+                               'requestToken' => array(
+                                       'type'    => 'hidden',
+                                       'default' => $requestToken,
+                                       'validation-callback' => null // 
different format
+                               )
+                       ) ),
+                       $this->getContext()
+               );
+               $form->setSubmitCallback(
+                       function( array $data, IContextSource $context ) use ( 
$control ) {
+                               $data['grants'] = FormatJSON::encode( // adapt 
form to controller
+                                       preg_replace( '/^grant-/', '', 
$data['grants'] ) );
+
+                               $control->setInputParameters( $data );
+                               return $control->submit();
+                       }
+               );
+               if ( $existing ) {
+                       // User has already authorized this consumer
+                       $grants = $existing->get( 'grants');
+                       $grantList = is_null( $grants )
+                               ? $this->msg( 'mwoauth-grants-nogrants' 
)->text()
+                               : $lang->commaList( $grants );
+                       $form->addPreText( $this->msg( 'mwoauth-form-existing',
+                               $grantList,
+                               $existing->get( 'wiki'),
+                               $existing->get( 'accepted' ) )->parseAsBlock()
+                       );
+               } else {
+                       $form->addPreText( $this->msg( 
'mwoauth-form-description' )->text() );
+               }
+               $form->addPreText( $this->msg( 'mwoauth-form-legal' )->text() );
+
+               $form->setWrapperLegendMsg( 'mwoauth-desc' );
+               $form->setSubmitTextMsg( 'mwoauth-form-button-approve' );
+
+               $status = $form->show();
+               if ( $status instanceof Status && $status->isOk() ) {
+                       // Redirect to callback url
+                       $this->getOutput()->redirect( 
$status->value['result']['callbackUrl'] );
+               }
        }
 
        /**

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia69737fb661f5a9f3fbb862d1af7a3869f2a59e0
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/OAuth
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>

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

Reply via email to