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