MediaWiki  master
SpecialChangeCredentials.php
Go to the documentation of this file.
1 <?php
2 
8 
15  protected static $allowedActions = [ AuthManager::ACTION_CHANGE ];
16 
17  protected static $messagePrefix = 'changecredentials';
18 
20  protected static $loadUserData = true;
21 
25  public function __construct( AuthManager $authManager ) {
26  parent::__construct( 'ChangeCredentials', 'editmyprivateinfo' );
27  $this->setAuthManager( $authManager );
28  }
29 
30  protected function getGroupName() {
31  return 'users';
32  }
33 
34  public function isListed() {
35  $this->loadAuth( '' );
36  return (bool)$this->authRequests;
37  }
38 
39  public function doesWrites() {
40  return true;
41  }
42 
43  protected function getDefaultAction( $subPage ) {
44  return AuthManager::ACTION_CHANGE;
45  }
46 
47  protected function getPreservedParams( $withToken = false ) {
48  $request = $this->getRequest();
49  $params = parent::getPreservedParams( $withToken );
50  $params += [
51  'returnto' => $request->getVal( 'returnto' ),
52  'returntoquery' => $request->getVal( 'returntoquery' ),
53  ];
54  return $params;
55  }
56 
57  public function execute( $subPage ) {
58  $this->setHeaders();
59  $this->outputHeader();
60 
61  $this->loadAuth( $subPage );
62 
63  if ( !$subPage ) {
64  $this->showSubpageList();
65  return;
66  }
67 
68  if ( !$this->authRequests ) {
69  // messages used: changecredentials-invalidsubpage, removecredentials-invalidsubpage
70  $this->showSubpageList( $this->msg( static::$messagePrefix . '-invalidsubpage', $subPage ) );
71  return;
72  }
73 
74  $this->getOutput()->addBacklinkSubtitle( $this->getPageTitle() );
75 
76  $status = $this->trySubmit();
77 
78  if ( $status === false || !$status->isOK() ) {
79  $this->displayForm( $status );
80  return;
81  }
82 
83  $response = $status->getValue();
84 
85  switch ( $response->status ) {
86  case AuthenticationResponse::PASS:
87  $this->success();
88  break;
89  case AuthenticationResponse::FAIL:
90  $this->displayForm( Status::newFatal( $response->message ) );
91  break;
92  default:
93  throw new LogicException( 'invalid AuthenticationResponse' );
94  }
95  }
96 
97  protected function loadAuth( $subPage, $authAction = null, $reset = false ) {
98  parent::loadAuth( $subPage, $authAction );
99  if ( $subPage ) {
100  $foundReqs = [];
101  foreach ( $this->authRequests as $req ) {
102  if ( $req->getUniqueId() === $subPage ) {
103  $foundReqs[] = $req;
104  }
105  }
106  if ( count( $foundReqs ) > 1 ) {
107  throw new LogicException( 'Multiple AuthenticationRequest objects with same ID!' );
108  }
109  $this->authRequests = $foundReqs;
110  }
111  }
112 
114  public function onAuthChangeFormFields(
115  array $requests, array $fieldInfo, array &$formDescriptor, $action
116  ) {
117  parent::onAuthChangeFormFields( $requests, $fieldInfo, $formDescriptor, $action );
118 
119  // Add some UI flair for password changes, the most common use case for this page.
120  if ( AuthenticationRequest::getRequestByClass( $this->authRequests,
121  PasswordAuthenticationRequest::class )
122  ) {
123  $formDescriptor = self::mergeDefaultFormDescriptor( $fieldInfo, $formDescriptor, [
124  'password' => [
125  'autocomplete' => 'new-password',
126  'placeholder-message' => 'createacct-yourpassword-ph',
127  'help-message' => 'createacct-useuniquepass',
128  ],
129  'retype' => [
130  'autocomplete' => 'new-password',
131  'placeholder-message' => 'createacct-yourpasswordagain-ph',
132  ],
133  // T263927 - the Chromium password form guide recommends always having a username field
134  'username' => [
135  'type' => 'text',
136  'baseField' => 'password',
137  'autocomplete' => 'username',
138  'nodata' => true,
139  'readonly' => true,
140  'cssclass' => 'mw-htmlform-hidden-field',
141  'label-message' => 'userlogin-yourname',
142  'placeholder-message' => 'userlogin-yourname-ph',
143  ],
144  ] );
145  }
146  }
147 
148  protected function getAuthFormDescriptor( $requests, $action ) {
149  if ( !static::$loadUserData ) {
150  return [];
151  } else {
152  $descriptor = parent::getAuthFormDescriptor( $requests, $action );
153 
154  $any = false;
155  foreach ( $descriptor as &$field ) {
156  if ( $field['type'] === 'password' && $field['name'] !== 'retype' ) {
157  $any = true;
158  if ( isset( $field['cssclass'] ) ) {
159  $field['cssclass'] .= ' mw-changecredentials-validate-password';
160  } else {
161  $field['cssclass'] = 'mw-changecredentials-validate-password';
162  }
163  }
164  }
165 
166  if ( $any ) {
167  $this->getOutput()->addModules( 'mediawiki.misc-authed-ooui' );
168  }
169 
170  return $descriptor;
171  }
172  }
173 
174  protected function getAuthForm( array $requests, $action ) {
175  $form = parent::getAuthForm( $requests, $action );
176  $req = reset( $requests );
177  $info = $req->describeCredentials();
178 
179  $form->addPreText(
180  Html::openElement( 'dl' )
181  . Html::element( 'dt', [], $this->msg( 'credentialsform-provider' )->text() )
182  . Html::element( 'dd', [], $info['provider']->text() )
183  . Html::element( 'dt', [], $this->msg( 'credentialsform-account' )->text() )
184  . Html::element( 'dd', [], $info['account']->text() )
185  . Html::closeElement( 'dl' )
186  );
187 
188  // messages used: changecredentials-submit removecredentials-submit
189  $form->setSubmitTextMsg( static::$messagePrefix . '-submit' );
190  $form->showCancel()->setCancelTarget( $this->getReturnUrl() ?: Title::newMainPage() );
191 
192  return $form;
193  }
194 
195  protected function needsSubmitButton( array $requests ) {
196  // Change/remove forms show are built from a single AuthenticationRequest and do not allow
197  // for redirect flow; they always need a submit button.
198  return true;
199  }
200 
201  public function handleFormSubmit( $data ) {
202  // remove requests do not accept user input
203  $requests = $this->authRequests;
204  if ( static::$loadUserData ) {
205  $requests = AuthenticationRequest::loadRequestsFromSubmission( $this->authRequests, $data );
206  }
207 
208  $response = $this->performAuthenticationStep( $this->authAction, $requests );
209 
210  // we can't handle FAIL or similar as failure here since it might require changing the form
211  return Status::newGood( $response );
212  }
213 
217  protected function showSubpageList( $error = null ) {
218  $out = $this->getOutput();
219 
220  if ( $error ) {
221  $out->addHTML( $error->parse() );
222  }
223 
224  $groupedRequests = [];
225  foreach ( $this->authRequests as $req ) {
226  $info = $req->describeCredentials();
227  $groupedRequests[$info['provider']->text()][] = $req;
228  }
229 
230  $linkRenderer = $this->getLinkRenderer();
231  $out->addHTML( Html::openElement( 'dl' ) );
232  foreach ( $groupedRequests as $group => $members ) {
233  $out->addHTML( Html::element( 'dt', [], $group ) );
234  foreach ( $members as $req ) {
236  $info = $req->describeCredentials();
237  $out->addHTML( Html::rawElement( 'dd', [],
238  $linkRenderer->makeLink(
239  $this->getPageTitle( $req->getUniqueId() ),
240  $info['account']->text()
241  )
242  ) );
243  }
244  }
245  $out->addHTML( Html::closeElement( 'dl' ) );
246  }
247 
248  protected function success() {
249  $session = $this->getRequest()->getSession();
250  $user = $this->getUser();
251  $out = $this->getOutput();
252  $returnUrl = $this->getReturnUrl();
253 
254  // change user token and update the session
255  SessionManager::singleton()->invalidateSessionsForUser( $user );
256  $session->setUser( $user );
257  $session->resetId();
258 
259  if ( $returnUrl ) {
260  $out->redirect( $returnUrl );
261  } else {
262  // messages used: changecredentials-success removecredentials-success
263  $out->wrapWikiMsg( "<div class=\"successbox\">\n$1\n</div>", static::$messagePrefix
264  . '-success' );
265  $out->returnToMain();
266  }
267  }
268 
272  protected function getReturnUrl() {
273  $request = $this->getRequest();
274  $returnTo = $request->getText( 'returnto' );
275  $returnToQuery = $request->getText( 'returntoquery', '' );
276 
277  if ( !$returnTo ) {
278  return null;
279  }
280 
281  $title = Title::newFromText( $returnTo );
282  return $title->getFullUrlForRedirect( $returnToQuery );
283  }
284 
285  protected function getRequestBlacklist() {
286  return $this->getConfig()->get( 'ChangeCredentialsBlacklist' );
287  }
288 }
SpecialChangeCredentials\getAuthFormDescriptor
getAuthFormDescriptor( $requests, $action)
Generates a HTMLForm descriptor array from a set of authentication requests.
Definition: SpecialChangeCredentials.php:148
SpecialPage\$linkRenderer
LinkRenderer null $linkRenderer
Definition: SpecialPage.php:80
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:744
AuthManagerSpecialPage\displayForm
displayForm( $status)
Display the form.
Definition: AuthManagerSpecialPage.php:570
SpecialPage\msg
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:912
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:395
StatusValue\newFatal
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:70
SpecialChangeCredentials\__construct
__construct(AuthManager $authManager)
Definition: SpecialChangeCredentials.php:25
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:790
MediaWiki\Auth\AuthenticationRequest\describeCredentials
describeCredentials()
Describe the credentials represented by this request.
Definition: AuthenticationRequest.php:235
SpecialChangeCredentials\getAuthForm
getAuthForm(array $requests, $action)
Definition: SpecialChangeCredentials.php:174
SpecialChangeCredentials\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialChangeCredentials.php:30
SpecialChangeCredentials\getRequestBlacklist
getRequestBlacklist()
Allows blacklisting certain request types.
Definition: SpecialChangeCredentials.php:285
SpecialChangeCredentials\$allowedActions
static $allowedActions
Definition: SpecialChangeCredentials.php:15
Title\newMainPage
static newMainPage(MessageLocalizer $localizer=null)
Create a new Title for the Main Page.
Definition: Title.php:725
SpecialChangeCredentials\isListed
isListed()
Whether this special page is listed in Special:SpecialPages.
Definition: SpecialChangeCredentials.php:34
SpecialChangeCredentials\onAuthChangeFormFields
onAuthChangeFormFields(array $requests, array $fieldInfo, array &$formDescriptor, $action)
Change the form descriptor that determines how a field will look in the authentication form....
Definition: SpecialChangeCredentials.php:114
AuthManagerSpecialPage
A special page subclass for authentication-related special pages.
Definition: AuthManagerSpecialPage.php:18
SpecialPage\$authManager
AuthManager null $authManager
Definition: SpecialPage.php:88
AuthManagerSpecialPage\$authRequests
AuthenticationRequest[] $authRequests
Definition: AuthManagerSpecialPage.php:36
SpecialChangeCredentials\handleFormSubmit
handleFormSubmit( $data)
Submit handler callback for HTMLForm.
Definition: SpecialChangeCredentials.php:201
SpecialChangeCredentials\$messagePrefix
static $messagePrefix
Definition: SpecialChangeCredentials.php:17
AuthManagerSpecialPage\trySubmit
trySubmit()
Attempts to do an authentication step with the submitted data.
Definition: AuthManagerSpecialPage.php:416
Html\closeElement
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:316
MediaWiki\Auth\PasswordAuthenticationRequest
This is a value object for authentication requests with a username and password.
Definition: PasswordAuthenticationRequest.php:30
AuthManagerSpecialPage\$subPage
string $subPage
Subpage of the special page.
Definition: AuthManagerSpecialPage.php:39
AuthManagerSpecialPage\performAuthenticationStep
performAuthenticationStep( $action, array $requests)
Definition: AuthManagerSpecialPage.php:361
SpecialChangeCredentials\getDefaultAction
getDefaultAction( $subPage)
Get the default action for this special page, if none is given via URL/POST data.
Definition: SpecialChangeCredentials.php:43
SpecialPage\getConfig
getConfig()
Shortcut to get main config object.
Definition: SpecialPage.php:878
AuthManagerSpecialPage\$authAction
string $authAction
one of the AuthManager::ACTION_* constants.
Definition: AuthManagerSpecialPage.php:33
SpecialChangeCredentials\getPreservedParams
getPreservedParams( $withToken=false)
Returns URL query parameters which can be used to reload the page (or leave and return) while preserv...
Definition: SpecialChangeCredentials.php:47
SpecialChangeCredentials\doesWrites
doesWrites()
Indicates whether this special page may perform database writes.
Definition: SpecialChangeCredentials.php:39
SpecialChangeCredentials\needsSubmitButton
needsSubmitButton(array $requests)
Returns true if the form built from the given AuthenticationRequests needs a submit button.
Definition: SpecialChangeCredentials.php:195
MediaWiki\Auth\AuthenticationResponse
This is a value object to hold authentication response data.
Definition: AuthenticationResponse.php:37
SpecialPage\setAuthManager
setAuthManager(AuthManager $authManager)
Set the injected AuthManager from the special page constructor.
Definition: SpecialPage.php:510
$title
$title
Definition: testCompression.php:38
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:618
SpecialPage\getUser
getUser()
Shortcut to get the User executing this instance.
Definition: SpecialPage.php:800
SpecialChangeCredentials\$loadUserData
static $loadUserData
Change action needs user data; remove action does not.
Definition: SpecialChangeCredentials.php:20
SpecialChangeCredentials\success
success()
Definition: SpecialChangeCredentials.php:248
SpecialChangeCredentials\loadAuth
loadAuth( $subPage, $authAction=null, $reset=false)
Load or initialize $authAction, $authRequests and $subPage.
Definition: SpecialChangeCredentials.php:97
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
MediaWiki\Session\SessionManager
This serves as the entry point to the MediaWiki session handling system.
Definition: SessionManager.php:83
AuthManagerSpecialPage\mergeDefaultFormDescriptor
static mergeDefaultFormDescriptor(array $fieldInfo, array $formDescriptor, array $defaultFormDescriptor)
Apply defaults to a form descriptor, without creating non-existend fields.
Definition: AuthManagerSpecialPage.php:805
SpecialChangeCredentials
Special change to change credentials (such as the password).
Definition: SpecialChangeCredentials.php:14
SpecialChangeCredentials\getReturnUrl
getReturnUrl()
Definition: SpecialChangeCredentials.php:272
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:102
SpecialPage\getLinkRenderer
getLinkRenderer()
Definition: SpecialPage.php:1028
SpecialChangeCredentials\execute
execute( $subPage)
Default execute method Checks user permissions.
Definition: SpecialChangeCredentials.php:57
Html\openElement
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:252
Html\rawElement
static rawElement( $element, $attribs=[], $contents='')
Returns an HTML element in a string.
Definition: Html.php:210
AuthManagerSpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: AuthManagerSpecialPage.php:72
SpecialChangeCredentials\showSubpageList
showSubpageList( $error=null)
Definition: SpecialChangeCredentials.php:217
Html\element
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:232
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:709
MediaWiki\Auth\AuthenticationRequest
This is a value object for authentication requests.
Definition: AuthenticationRequest.php:38