MediaWiki  1.30.0
AuthenticationRequest.php
Go to the documentation of this file.
1 <?php
24 namespace MediaWiki\Auth;
25 
26 use Message;
27 
37 abstract class AuthenticationRequest {
38 
40  const OPTIONAL = 0;
41 
46  const REQUIRED = 1;
47 
51  const PRIMARY_REQUIRED = 2;
52 
57  public $action = null;
58 
62 
64  public $returnToUrl = null;
65 
68  public $username = null;
69 
85  public function getUniqueId() {
86  return get_called_class();
87  }
88 
123  abstract public function getFieldInfo();
124 
135  public function getMetadata() {
136  return [];
137  }
138 
151  public function loadFromSubmission( array $data ) {
152  $fields = array_filter( $this->getFieldInfo(), function ( $info ) {
153  return $info['type'] !== 'null';
154  } );
155  if ( !$fields ) {
156  return false;
157  }
158 
159  foreach ( $fields as $field => $info ) {
160  // Checkboxes and buttons are special. Depending on the method used
161  // to populate $data, they might be unset meaning false or they
162  // might be boolean. Further, image buttons might submit the
163  // coordinates of the click rather than the expected value.
164  if ( $info['type'] === 'checkbox' || $info['type'] === 'button' ) {
165  $this->$field = isset( $data[$field] ) && $data[$field] !== false
166  || isset( $data["{$field}_x"] ) && $data["{$field}_x"] !== false;
167  if ( !$this->$field && empty( $info['optional'] ) ) {
168  return false;
169  }
170  continue;
171  }
172 
173  // Multiselect are too, slightly
174  if ( !isset( $data[$field] ) && $info['type'] === 'multiselect' ) {
175  $data[$field] = [];
176  }
177 
178  if ( !isset( $data[$field] ) ) {
179  return false;
180  }
181  if ( $data[$field] === '' || $data[$field] === [] ) {
182  if ( empty( $info['optional'] ) ) {
183  return false;
184  }
185  } else {
186  switch ( $info['type'] ) {
187  case 'select':
188  if ( !isset( $info['options'][$data[$field]] ) ) {
189  return false;
190  }
191  break;
192 
193  case 'multiselect':
194  $data[$field] = (array)$data[$field];
195  $allowed = array_keys( $info['options'] );
196  if ( array_diff( $data[$field], $allowed ) !== [] ) {
197  return false;
198  }
199  break;
200  }
201  }
202 
203  $this->$field = $data[$field];
204  }
205 
206  return true;
207  }
208 
225  public function describeCredentials() {
226  return [
227  'provider' => new \RawMessage( '$1', [ get_called_class() ] ),
228  'account' => new \RawMessage( '$1', [ $this->getUniqueId() ] ),
229  ];
230  }
231 
238  public static function loadRequestsFromSubmission( array $reqs, array $data ) {
239  return array_values( array_filter( $reqs, function ( $req ) use ( $data ) {
240  return $req->loadFromSubmission( $data );
241  } ) );
242  }
243 
253  public static function getRequestByClass( array $reqs, $class, $allowSubclasses = false ) {
254  $requests = array_filter( $reqs, function ( $req ) use ( $class, $allowSubclasses ) {
255  if ( $allowSubclasses ) {
256  return is_a( $req, $class, false );
257  } else {
258  return get_class( $req ) === $class;
259  }
260  } );
261  return count( $requests ) === 1 ? reset( $requests ) : null;
262  }
263 
273  public static function getUsernameFromRequests( array $reqs ) {
274  $username = null;
275  $otherClass = null;
276  foreach ( $reqs as $req ) {
277  $info = $req->getFieldInfo();
278  if ( $info && array_key_exists( 'username', $info ) && $req->username !== null ) {
279  if ( $username === null ) {
280  $username = $req->username;
281  $otherClass = get_class( $req );
282  } elseif ( $username !== $req->username ) {
283  $requestClass = get_class( $req );
284  throw new \UnexpectedValueException( "Conflicting username fields: \"{$req->username}\" from "
285  . "$requestClass::\$username vs. \"$username\" from $otherClass::\$username" );
286  }
287  }
288  }
289  return $username;
290  }
291 
298  public static function mergeFieldInfo( array $reqs ) {
299  $merged = [];
300 
301  // fields that are required by some primary providers but not others are not actually required
302  $primaryRequests = array_filter( $reqs, function ( $req ) {
303  return $req->required === AuthenticationRequest::PRIMARY_REQUIRED;
304  } );
305  $sharedRequiredPrimaryFields = array_reduce( $primaryRequests, function ( $shared, $req ) {
306  $required = array_keys( array_filter( $req->getFieldInfo(), function ( $options ) {
307  return empty( $options['optional'] );
308  } ) );
309  if ( $shared === null ) {
310  return $required;
311  } else {
312  return array_intersect( $shared, $required );
313  }
314  }, null );
315 
316  foreach ( $reqs as $req ) {
317  $info = $req->getFieldInfo();
318  if ( !$info ) {
319  continue;
320  }
321 
322  foreach ( $info as $name => $options ) {
323  if (
324  // If the request isn't required, its fields aren't required either.
325  $req->required === self::OPTIONAL
326  // If there is a primary not requiring this field, no matter how many others do,
327  // authentication can proceed without it.
328  || $req->required === self::PRIMARY_REQUIRED
329  && !in_array( $name, $sharedRequiredPrimaryFields, true )
330  ) {
331  $options['optional'] = true;
332  } else {
333  $options['optional'] = !empty( $options['optional'] );
334  }
335 
336  $options['sensitive'] = !empty( $options['sensitive'] );
337 
338  if ( !array_key_exists( $name, $merged ) ) {
339  $merged[$name] = $options;
340  } elseif ( $merged[$name]['type'] !== $options['type'] ) {
341  throw new \UnexpectedValueException( "Field type conflict for \"$name\", " .
342  "\"{$merged[$name]['type']}\" vs \"{$options['type']}\""
343  );
344  } else {
345  if ( isset( $options['options'] ) ) {
346  if ( isset( $merged[$name]['options'] ) ) {
347  $merged[$name]['options'] += $options['options'];
348  } else {
349  // @codeCoverageIgnoreStart
350  $merged[$name]['options'] = $options['options'];
351  // @codeCoverageIgnoreEnd
352  }
353  }
354 
355  $merged[$name]['optional'] = $merged[$name]['optional'] && $options['optional'];
356  $merged[$name]['sensitive'] = $merged[$name]['sensitive'] || $options['sensitive'];
357 
358  // No way to merge 'value', 'image', 'help', or 'label', so just use
359  // the value from the first request.
360  }
361  }
362  }
363 
364  return $merged;
365  }
366 
372  public static function __set_state( $data ) {
373  $ret = new static();
374  foreach ( $data as $k => $v ) {
375  $ret->$k = $v;
376  }
377  return $ret;
378  }
379 }
MediaWiki\Auth\AuthenticationRequest\OPTIONAL
const OPTIONAL
Indicates that the request is not required for authentication to proceed.
Definition: AuthenticationRequest.php:40
MediaWiki\Auth\AuthenticationRequest\$returnToUrl
string null $returnToUrl
Return-to URL, in case of redirect.
Definition: AuthenticationRequest.php:64
MediaWiki\Auth\AuthenticationRequest\getMetadata
getMetadata()
Returns metadata about this request.
Definition: AuthenticationRequest.php:135
MediaWiki\Auth\AuthenticationRequest\mergeFieldInfo
static mergeFieldInfo(array $reqs)
Merge the output of multiple AuthenticationRequest::getFieldInfo() calls.
Definition: AuthenticationRequest.php:298
MediaWiki\Auth\AuthenticationRequest\loadRequestsFromSubmission
static loadRequestsFromSubmission(array $reqs, array $data)
Update a set of requests with form submit data, discarding ones that fail.
Definition: AuthenticationRequest.php:238
MediaWiki\Auth\AuthenticationRequest\describeCredentials
describeCredentials()
Describe the credentials represented by this request.
Definition: AuthenticationRequest.php:225
captcha-old.count
count
Definition: captcha-old.py:249
MediaWiki\Auth\AuthenticationRequest\$required
int $required
For login, continue, and link actions, one of self::OPTIONAL, self::REQUIRED, or self::PRIMARY_REQUIR...
Definition: AuthenticationRequest.php:61
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$req
this hook is for auditing only $req
Definition: hooks.txt:988
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
MediaWiki\Auth\AuthenticationRequest\getRequestByClass
static getRequestByClass(array $reqs, $class, $allowSubclasses=false)
Select a request by class name.
Definition: AuthenticationRequest.php:253
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
MediaWiki\Auth\AuthenticationRequest\$action
string null $action
The AuthManager::ACTION_* constant this request was created to be used for.
Definition: AuthenticationRequest.php:57
MediaWiki\Auth\AuthenticationRequest\$username
string null $username
Username.
Definition: AuthenticationRequest.php:68
MediaWiki\Auth\AuthenticationRequest\getUsernameFromRequests
static getUsernameFromRequests(array $reqs)
Get the username from the set of requests.
Definition: AuthenticationRequest.php:273
MediaWiki\Auth\AuthenticationRequest\PRIMARY_REQUIRED
const PRIMARY_REQUIRED
Indicates that the request is required by a primary authentication provider.
Definition: AuthenticationRequest.php:51
MediaWiki\Auth\AuthenticationRequest\getUniqueId
getUniqueId()
Supply a unique key for deduplication.
Definition: AuthenticationRequest.php:85
MediaWiki\Auth\AuthenticationRequest\getFieldInfo
getFieldInfo()
Fetch input field info.
MediaWiki\Auth\AuthenticationRequest\loadFromSubmission
loadFromSubmission(array $data)
Initialize form submitted form data.
Definition: AuthenticationRequest.php:151
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1965
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1965
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
$requests
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead. & $feedLinks hooks can tweak the array to change how login etc forms should look $requests
Definition: hooks.txt:304
MediaWiki\Auth
Definition: AbstractAuthenticationProvider.php:22
MediaWiki\Auth\AuthenticationRequest\__set_state
static __set_state( $data)
Implementing this mainly for use from the unit tests.
Definition: AuthenticationRequest.php:372
MediaWiki\Auth\AuthenticationRequest
This is a value object for authentication requests.
Definition: AuthenticationRequest.php:37
MediaWiki\Auth\AuthenticationRequest\REQUIRED
const REQUIRED
Indicates that the request is required for authentication to proceed.
Definition: AuthenticationRequest.php:46
array
the array() calling protocol came about after MediaWiki 1.4rc1.