Page MenuHomePhabricator

0001-Require-reauthentication-for-proposing-or-managing-c.patch

Authored By
Anomie
Nov 16 2018, 6:29 PM
Size
9 KB
Referenced Files
None
Subscribers
None

0001-Require-reauthentication-for-proposing-or-managing-c.patch

From c84ae939eddcad92af563e02c9609d9de09db05e Mon Sep 17 00:00:00 2001
From: Brad Jorsch <bjorsch@wikimedia.org>
Date: Tue, 30 Oct 2018 13:56:02 -0400
Subject: [PATCH] Require reauthentication for proposing or managing consumers
By default, creating an owner-only consumer requires reauthentication
within the past 2 hours, while proposing or managing other consumers
requires reauthentication every 48 hours.
Bug: T197156
Bug: T208008
Change-Id: Iba1777196ae9da3423487084070be84175580aa7
---
backend/MWOAuth.hooks.php | 8 ++++
backend/MWOAuthConsumer.php | 8 ++--
backend/MWOAuthConsumerAcceptance.php | 6 +--
control/MWOAuthSubmitControl.php | 2 +-
.../SpecialMWOAuthConsumerRegistration.php | 37 +++++++++++++++++++
.../SpecialMWOAuthManageConsumers.php | 25 +++++++++++++
6 files changed, 78 insertions(+), 8 deletions(-)
diff --git a/backend/MWOAuth.hooks.php b/backend/MWOAuth.hooks.php
index f06a26a..63c0541 100644
--- a/backend/MWOAuth.hooks.php
+++ b/backend/MWOAuth.hooks.php
@@ -11,6 +11,14 @@ use MediaWiki\Storage\NameTableAccessException;
class MWOAuthHooks {
public static function onExtensionFunctions() {
+ global $wgReauthenticateTime;
+
+ // TODO: Maybe make it possible to put this in extension.json
+ $wgReauthenticateTime += [
+ 'OAuthManage' => 172800,
+ 'OAuthProposeOwnerOnly' => 7200,
+ ];
+
\MediaWiki\Extensions\OAuth\MWOAuthUISetup::conditionalSetup();
}
diff --git a/backend/MWOAuthConsumer.php b/backend/MWOAuthConsumer.php
index 9ef778d..9e47656 100644
--- a/backend/MWOAuthConsumer.php
+++ b/backend/MWOAuthConsumer.php
@@ -337,7 +337,7 @@ class MWOAuthConsumer extends MWOAuthDAO {
}
}
- protected function userCanSee( $name, \RequestContext $context ) {
+ protected function userCanSee( $name, \IContextSource $context ) {
if ( $this->get( 'deleted' )
&& !$context->getUser()->isAllowed( 'mwoauthviewsuppressed' ) ) {
return $context->msg( 'mwoauth-field-hidden' );
@@ -346,7 +346,7 @@ class MWOAuthConsumer extends MWOAuthDAO {
}
}
- protected function userCanSeePrivate( $name, \RequestContext $context ) {
+ protected function userCanSeePrivate( $name, \IContextSource $context ) {
if ( !$context->getUser()->isAllowed( 'mwoauthviewprivate' ) ) {
return $context->msg( 'mwoauth-field-private' );
} else {
@@ -354,7 +354,7 @@ class MWOAuthConsumer extends MWOAuthDAO {
}
}
- protected function userCanSeeEmail( $name, \RequestContext $context ) {
+ protected function userCanSeeEmail( $name, \IContextSource $context ) {
if ( !$context->getUser()->isAllowed( 'mwoauthmanageconsumer' ) ) {
return $context->msg( 'mwoauth-field-private' );
} else {
@@ -362,7 +362,7 @@ class MWOAuthConsumer extends MWOAuthDAO {
}
}
- protected function userCanSeeSecret( $name, \RequestContext $context ) {
+ protected function userCanSeeSecret( $name, \IContextSource $context ) {
return $context->msg( 'mwoauth-field-private' );
}
}
diff --git a/backend/MWOAuthConsumerAcceptance.php b/backend/MWOAuthConsumerAcceptance.php
index d0ec980..bc0c66b 100644
--- a/backend/MWOAuthConsumerAcceptance.php
+++ b/backend/MWOAuthConsumerAcceptance.php
@@ -162,7 +162,7 @@ class MWOAuthConsumerAcceptance extends MWOAuthDAO {
return $row;
}
- protected function userCanSee( $name, \RequestContext $context ) {
+ protected function userCanSee( $name, \IContextSource $context ) {
$centralUserId = MWOAuthUtils::getCentralIdFromLocalUser( $context->getUser() );
if ( $this->userId != $centralUserId
&& !$context->getUser()->isAllowed( 'mwoauthviewprivate' )
@@ -173,7 +173,7 @@ class MWOAuthConsumerAcceptance extends MWOAuthDAO {
}
}
- protected function userCanSeePrivate( $name, \RequestContext $context ) {
+ protected function userCanSeePrivate( $name, \IContextSource $context ) {
if ( !$context->getUser()->isAllowed( 'mwoauthviewprivate' ) ) {
return $context->msg( 'mwoauth-field-private' );
} else {
@@ -181,7 +181,7 @@ class MWOAuthConsumerAcceptance extends MWOAuthDAO {
}
}
- protected function userCanSeeSecret( $name, \RequestContext $context ) {
+ protected function userCanSeeSecret( $name, \IContextSource $context ) {
return $context->msg( 'mwoauth-field-private' );
}
}
diff --git a/control/MWOAuthSubmitControl.php b/control/MWOAuthSubmitControl.php
index 20fc59b..2ef120f 100644
--- a/control/MWOAuthSubmitControl.php
+++ b/control/MWOAuthSubmitControl.php
@@ -25,7 +25,7 @@ namespace MediaWiki\Extensions\OAuth;
* Handle the logic of submitting a client request
*/
abstract class MWOAuthSubmitControl extends \ContextSource {
- /** @var \RequestContext */
+ /** @var \IContextSource */
protected $context;
/** @var Array (field name => value) */
protected $vals;
diff --git a/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php b/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
index 4aba1df..73ea7f1 100644
--- a/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
+++ b/frontend/specialpages/SpecialMWOAuthConsumerRegistration.php
@@ -28,10 +28,28 @@ use User;
* Page that has registration request form and consumer update form
*/
class SpecialMWOAuthConsumerRegistration extends \SpecialPage {
+
+ /**
+ * @var array|null POST data preserved across re-authentication
+ */
+ protected $reauthPostData = null;
+
public function __construct() {
parent::__construct( 'OAuthConsumerRegistration' );
}
+ protected function setReauthPostData( array $data ) {
+ $this->reauthPostData = $data;
+
+ $context = $this->getContext();
+ $context = new \DerivativeContext( $context );
+ $oldRequest = $this->getRequest();
+ $context->setRequest( new \DerivativeRequest(
+ $oldRequest, $data + $oldRequest->getQueryValues(), true
+ ) );
+ $this->setContext( $context );
+ }
+
public function doesWrites() {
return true;
}
@@ -49,6 +67,10 @@ class SpecialMWOAuthConsumerRegistration extends \SpecialPage {
$this->checkPermissions();
+ if ( !$this->checkLoginSecurityLevel( 'OAuthManage' ) ) {
+ return;
+ }
+
$request = $this->getRequest();
$user = $this->getUser();
$lang = $this->getLanguage();
@@ -224,6 +246,15 @@ class SpecialMWOAuthConsumerRegistration extends \SpecialPage {
);
$form->setSubmitCallback(
function ( array $data, \IContextSource $context ) use ( $control ) {
+ if ( $this->reauthPostData !== null ) {
+ // Don't process the submission on the fake post in
+ // case of some crazy kind of CSRF.
+ return false;
+ }
+ if ( $data['ownerOnly'] && !$this->checkLoginSecurityLevel( 'OAuthProposeOwnerOnly' ) ) {
+ return false;
+ }
+
$data['grants'] = \FormatJson::encode( // adapt form to controller
preg_replace( '/^grant-/', '', $data['grants'] ) );
// 'callbackUrl' must be present,
@@ -333,6 +364,12 @@ class SpecialMWOAuthConsumerRegistration extends \SpecialPage {
);
$form->setSubmitCallback(
function ( array $data, \IContextSource $context ) use ( $control ) {
+ if ( $this->reauthPostData !== null ) {
+ // Don't process the submission on the fake post in
+ // case of some crazy kind of CSRF.
+ return false;
+ }
+
$control->setInputParameters( $data );
return $control->submit();
}
diff --git a/frontend/specialpages/SpecialMWOAuthManageConsumers.php b/frontend/specialpages/SpecialMWOAuthManageConsumers.php
index bc45500..e21d57c 100644
--- a/frontend/specialpages/SpecialMWOAuthManageConsumers.php
+++ b/frontend/specialpages/SpecialMWOAuthManageConsumers.php
@@ -34,6 +34,9 @@ class SpecialMWOAuthManageConsumers extends \SpecialPage {
/** @var string A stage key from MWOAuthConsumer::$stageNames */
protected $stageKey;
+ /** @var array|null POST data preserved across re-authentication */
+ protected $reauthPostData = null;
+
/**
* Stages which are shown in a queue (they are in an actionable state and can form a backlog)
* @var array
@@ -52,6 +55,18 @@ class SpecialMWOAuthManageConsumers extends \SpecialPage {
parent::__construct( 'OAuthManageConsumers', 'mwoauthmanageconsumer' );
}
+ protected function setReauthPostData( array $data ) {
+ $this->reauthPostData = $data;
+
+ $context = $this->getContext();
+ $context = new \DerivativeContext( $context );
+ $oldRequest = $this->getRequest();
+ $context->setRequest( new \DerivativeRequest(
+ $oldRequest, $data + $oldRequest->getQueryValues(), true
+ ) );
+ $this->setContext( $context );
+ }
+
public function doesWrites() {
return true;
}
@@ -75,6 +90,10 @@ class SpecialMWOAuthManageConsumers extends \SpecialPage {
throw new \ErrorPageError( 'mwoauth-error', 'mwoauth-db-readonly' );
}
+ if ( !$this->checkLoginSecurityLevel( 'OAuthManage' ) ) {
+ return;
+ }
+
// Format is Special:OAuthManageConsumers[/<stage>|/<consumer key>]
// B/C format is Special:OAuthManageConsumers/<stage>/<consumer key>
$stageKey = $consumerKey = null;
@@ -321,6 +340,12 @@ class SpecialMWOAuthManageConsumers extends \SpecialPage {
);
$form->setSubmitCallback(
function ( array $data, \IContextSource $context ) use ( $control ) {
+ if ( $this->reauthPostData ) {
+ // Don't process the submission on the fake post in
+ // case of some crazy kind of CSRF.
+ return false;
+ }
+
$data['suppress'] = 0;
if ( $data['action'] === 'dsuppress' ) {
$data = [ 'action' => 'disable', 'suppress' => 1 ] + $data;
--
2.19.1

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
6703695
Default Alt Text
0001-Require-reauthentication-for-proposing-or-managing-c.patch (9 KB)

Event Timeline