MediaWiki  master
ApiLogin.php
Go to the documentation of this file.
1 <?php
28 
34 class ApiLogin extends ApiBase {
35 
36  public function __construct( ApiMain $main, $action ) {
37  parent::__construct( $main, $action, 'lg' );
38  }
39 
40  protected function getExtendedDescription() {
41  if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
42  return 'apihelp-login-extended-description';
43  } else {
44  return 'apihelp-login-extended-description-nobotpasswords';
45  }
46  }
47 
53  private function formatMessage( $message ) {
54  $message = Message::newFromSpecifier( $message );
55  $errorFormatter = $this->getErrorFormatter();
56  if ( $errorFormatter instanceof ApiErrorFormatter_BackCompat ) {
58  $message->useDatabase( false )->inLanguage( 'en' )->text()
59  );
60  } else {
61  return $errorFormatter->formatMessage( $message );
62  }
63  }
64 
74  public function execute() {
75  // If we're in a mode that breaks the same-origin policy, no tokens can
76  // be obtained
77  if ( $this->lacksSameOriginSecurity() ) {
78  $this->getResult()->addValue( null, 'login', [
79  'result' => 'Aborted',
80  'reason' => $this->formatMessage( 'api-login-fail-sameorigin' ),
81  ] );
82 
83  return;
84  }
85 
86  $this->requirePostedParameters( [ 'password', 'token' ] );
87 
88  $params = $this->extractRequestParams();
89 
90  $result = [];
91 
92  // Make sure session is persisted
94  $session->persist();
95 
96  // Make sure it's possible to log in
97  if ( !$session->canSetUser() ) {
98  $this->getResult()->addValue( null, 'login', [
99  'result' => 'Aborted',
100  'reason' => $this->formatMessage( [
101  'api-login-fail-badsessionprovider',
102  $session->getProvider()->describe( $this->getErrorFormatter()->getLanguage() ),
103  ] )
104  ] );
105 
106  return;
107  }
108 
109  $authRes = false;
110  $loginType = 'N/A';
111 
112  // Check login token
113  $token = $session->getToken( '', 'login' );
114  if ( !$params['token'] ) {
115  $authRes = 'NeedToken';
116  } elseif ( $token->wasNew() ) {
117  $authRes = 'Failed';
118  $message = ApiMessage::create( 'authpage-cannot-login-continue', 'sessionlost' );
119  } elseif ( !$token->match( $params['token'] ) ) {
120  $authRes = 'WrongToken';
121  }
122 
123  // Try bot passwords
124  if (
125  $authRes === false && $this->getConfig()->get( 'EnableBotPasswords' ) &&
126  ( $botLoginData = BotPassword::canonicalizeLoginData( $params['name'], $params['password'] ) )
127  ) {
128  $status = BotPassword::login(
129  $botLoginData[0], $botLoginData[1], $this->getRequest()
130  );
131  if ( $status->isOK() ) {
132  $session = $status->getValue();
133  $authRes = 'Success';
134  $loginType = 'BotPassword';
135  } elseif (
136  $status->hasMessage( 'login-throttled' ) ||
137  $status->hasMessage( 'botpasswords-needs-reset' ) ||
138  $status->hasMessage( 'botpasswords-locked' )
139  ) {
140  $authRes = 'Failed';
141  $message = $status->getMessage();
142  LoggerFactory::getInstance( 'authentication' )->info(
143  'BotPassword login failed: ' . $status->getWikiText( false, false, 'en' )
144  );
145  }
146  // For other errors, let's see if it's a valid non-bot login
147  }
148 
149  if ( $authRes === false ) {
150  // Simplified AuthManager login, for backwards compatibility
151  $manager = AuthManager::singleton();
152  $reqs = AuthenticationRequest::loadRequestsFromSubmission(
153  $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN, $this->getUser() ),
154  [
155  'username' => $params['name'],
156  'password' => $params['password'],
157  'domain' => $params['domain'],
158  'rememberMe' => true,
159  ]
160  );
161  $res = AuthManager::singleton()->beginAuthentication( $reqs, 'null:' );
162  switch ( $res->status ) {
163  case AuthenticationResponse::PASS:
164  if ( $this->getConfig()->get( 'EnableBotPasswords' ) ) {
165  $this->addDeprecation( 'apiwarn-deprecation-login-botpw', 'main-account-login' );
166  } else {
167  $this->addDeprecation( 'apiwarn-deprecation-login-nobotpw', 'main-account-login' );
168  }
169  $authRes = 'Success';
170  $loginType = 'AuthManager';
171  break;
172 
173  case AuthenticationResponse::FAIL:
174  // Hope it's not a PreAuthenticationProvider that failed...
175  $authRes = 'Failed';
176  $message = $res->message;
178  ->info( __METHOD__ . ': Authentication failed: '
179  . $message->inLanguage( 'en' )->plain() );
180  break;
181 
182  default:
184  ->info( __METHOD__ . ': Authentication failed due to unsupported response type: '
185  . $res->status, $this->getAuthenticationResponseLogData( $res ) );
186  $authRes = 'Aborted';
187  break;
188  }
189  }
190 
191  $result['result'] = $authRes;
192  switch ( $authRes ) {
193  case 'Success':
194  $user = $session->getUser();
195 
197 
198  // Deprecated hook
199  $injected_html = '';
200  $this->getHookRunner()->onUserLoginComplete( $user, $injected_html, true );
201 
202  $result['lguserid'] = (int)$user->getId();
203  $result['lgusername'] = $user->getName();
204  break;
205 
206  case 'NeedToken':
207  $result['token'] = $token->toString();
208  $this->addDeprecation( 'apiwarn-deprecation-login-token', 'action=login&!lgtoken' );
209  break;
210 
211  case 'WrongToken':
212  break;
213 
214  case 'Failed':
215  $result['reason'] = $this->formatMessage( $message );
216  break;
217 
218  case 'Aborted':
219  $result['reason'] = $this->formatMessage(
220  $this->getConfig()->get( 'EnableBotPasswords' )
221  ? 'api-login-fail-aborted'
222  : 'api-login-fail-aborted-nobotpw'
223  );
224  break;
225 
226  // @codeCoverageIgnoreStart
227  // Unreachable
228  default:
229  ApiBase::dieDebug( __METHOD__, "Unhandled case value: {$authRes}" );
230  // @codeCoverageIgnoreEnd
231  }
232 
233  $this->getResult()->addValue( null, 'login', $result );
234 
235  LoggerFactory::getInstance( 'authevents' )->info( 'Login attempt', [
236  'event' => 'login',
237  'successful' => $authRes === 'Success',
238  'loginType' => $loginType,
239  'status' => $authRes,
240  ] );
241  }
242 
243  public function isDeprecated() {
244  return !$this->getConfig()->get( 'EnableBotPasswords' );
245  }
246 
247  public function mustBePosted() {
248  return true;
249  }
250 
251  public function isReadMode() {
252  return false;
253  }
254 
255  public function getAllowedParams() {
256  return [
257  'name' => null,
258  'password' => [
259  ApiBase::PARAM_TYPE => 'password',
260  ],
261  'domain' => null,
262  'token' => [
263  ApiBase::PARAM_TYPE => 'string',
264  ApiBase::PARAM_REQUIRED => false, // for BC
265  ApiBase::PARAM_SENSITIVE => true,
266  ApiBase::PARAM_HELP_MSG => [ 'api-help-param-token', 'login' ],
267  ],
268  ];
269  }
270 
271  protected function getExamplesMessages() {
272  return [
273  'action=login&lgname=user&lgpassword=password&lgtoken=123ABC'
274  => 'apihelp-login-example-login',
275  ];
276  }
277 
278  public function getHelpUrls() {
279  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Login';
280  }
281 
288  $ret = [
289  'status' => $response->status,
290  ];
291  if ( $response->message ) {
292  $ret['responseMessage'] = $response->message->inLanguage( 'en' )->plain();
293  }
294  $reqs = [
295  'neededRequests' => $response->neededRequests,
296  'createRequest' => $response->createRequest,
297  'linkRequest' => $response->linkRequest,
298  ];
299  foreach ( $reqs as $k => $v ) {
300  if ( $v ) {
301  $v = is_array( $v ) ? $v : [ $v ];
302  $reqClasses = array_unique( array_map( 'get_class', $v ) );
303  sort( $reqClasses );
304  $ret[$k] = implode( ', ', $reqClasses );
305  }
306  }
307  return $ret;
308  }
309 }
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:44
ContextSource\getConfig
getConfig()
Definition: ContextSource.php:63
ApiLogin\isReadMode
isReadMode()
Indicates whether this module requires read rights.
Definition: ApiLogin.php:251
Message\newFromSpecifier
static newFromSpecifier( $value)
Transform a MessageSpecifier or a primitive value used interchangeably with specifiers (a message key...
Definition: Message.php:434
ApiLogin\execute
execute()
Executes the log-in attempt using the parameters passed.
Definition: ApiLogin.php:74
ApiErrorFormatter_BackCompat
Format errors and warnings in the old style, for backwards compatibility.
Definition: ApiErrorFormatter_BackCompat.php:30
ApiBase\PARAM_REQUIRED
const PARAM_REQUIRED
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:74
$response
$response
Definition: opensearch_desc.php:44
BotPassword\canonicalizeLoginData
static canonicalizeLoginData( $username, $password)
There are two ways to login with a bot password: "username@appId", "password" and "username",...
Definition: BotPassword.php:420
MediaWiki\Logger\LoggerFactory\getInstance
static getInstance( $channel)
Get a named logger instance from the currently configured logger factory.
Definition: LoggerFactory.php:92
ApiBase\PARAM_HELP_MSG
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:104
ApiLogin\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiLogin.php:247
ApiQueryInfo\resetTokenCache
static resetTokenCache()
Definition: ApiQueryInfo.php:126
ApiLogin\isDeprecated
isDeprecated()
Indicates whether this module is deprecated.
Definition: ApiLogin.php:243
ApiBase\PARAM_TYPE
const PARAM_TYPE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:68
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:546
ApiLogin\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiLogin.php:271
ContextSource\getRequest
getRequest()
Definition: ContextSource.php:71
$res
$res
Definition: testCompression.php:57
ApiBase\lacksSameOriginSecurity
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition: ApiBase.php:474
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:50
ApiBase\PARAM_SENSITIVE
const PARAM_SENSITIVE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition: ApiBase.php:79
ApiLogin\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiLogin.php:278
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
ApiErrorFormatter\stripMarkup
static stripMarkup( $text)
Turn wikitext into something resembling plaintext.
Definition: ApiErrorFormatter.php:291
MediaWiki\Auth\AuthenticationResponse
This is a value object to hold authentication response data.
Definition: AuthenticationResponse.php:37
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:695
ApiMessage\create
static create( $msg, $code=null, array $data=null)
Create an IApiMessage for the message.
Definition: ApiMessage.php:40
ApiLogin\getAuthenticationResponseLogData
getAuthenticationResponseLogData(AuthenticationResponse $response)
Turns an AuthenticationResponse into a hash suitable for passing to Logger.
Definition: ApiLogin.php:287
MediaWiki\Session\SessionManager\getGlobalSession
static getGlobalSession()
Get the "global" session.
Definition: SessionManager.php:114
ApiLogin\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiLogin.php:255
ApiBase\addDeprecation
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition: ApiBase.php:1348
ApiLogin\getExtendedDescription
getExtendedDescription()
Return the extended help text message.
Definition: ApiLogin.php:40
BotPassword\login
static login( $username, $password, WebRequest $request)
Try to log the user in.
Definition: BotPassword.php:446
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:88
ApiLogin\formatMessage
formatMessage( $message)
Format a message for the response.
Definition: ApiLogin.php:53
ApiLogin
Unit to authenticate log-in attempts to the current wiki.
Definition: ApiLogin.php:34
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:641
ApiLogin\__construct
__construct(ApiMain $main, $action)
Definition: ApiLogin.php:36
ApiBase\dieDebug
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition: ApiBase.php:1607
ApiBase\getErrorFormatter
getErrorFormatter()
Get the error formatter.
Definition: ApiBase.php:560
ApiBase\requirePostedParameters
requirePostedParameters( $params, $prefix='prefix')
Die if any of the specified parameters were found in the query part of the URL rather than the post b...
Definition: ApiBase.php:919
MediaWiki\Auth\AuthenticationRequest
This is a value object for authentication requests.
Definition: AuthenticationRequest.php:37