Issues (4122)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

auth/AuthPluginPrimaryAuthenticationProvider.php (28 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Primary authentication provider wrapper for AuthPlugin
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License along
16
 * with this program; if not, write to the Free Software Foundation, Inc.,
17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
 * http://www.gnu.org/copyleft/gpl.html
19
 *
20
 * @file
21
 * @ingroup Auth
22
 */
23
24
namespace MediaWiki\Auth;
25
26
use AuthPlugin;
27
use User;
28
29
/**
30
 * Primary authentication provider wrapper for AuthPlugin
31
 * @warning If anything depends on the wrapped AuthPlugin being $wgAuth, it won't work with this!
32
 * @ingroup Auth
33
 * @since 1.27
34
 * @deprecated since 1.27
35
 */
36
class AuthPluginPrimaryAuthenticationProvider
37
	extends AbstractPasswordPrimaryAuthenticationProvider
0 ignored issues
show
The extends keyword must be on the same line as the class name
Loading history...
38
{
39
	private $auth;
40
	private $hasDomain;
41
	private $requestType = null;
42
43
	/**
44
	 * @param AuthPlugin $auth AuthPlugin to wrap
45
	 * @param string|null $requestType Class name of the
46
	 *  PasswordAuthenticationRequest to use. If $auth->domainList() returns
47
	 *  more than one domain, this must be a PasswordDomainAuthenticationRequest.
48
	 */
49
	public function __construct( AuthPlugin $auth, $requestType = null ) {
50
		parent::__construct();
51
52
		if ( $auth instanceof AuthManagerAuthPlugin ) {
53
			throw new \InvalidArgumentException(
54
				'Trying to wrap AuthManagerAuthPlugin in AuthPluginPrimaryAuthenticationProvider ' .
55
					'makes no sense.'
56
			);
57
		}
58
59
		$need = count( $auth->domainList() ) > 1
60
			? PasswordDomainAuthenticationRequest::class
61
			: PasswordAuthenticationRequest::class;
62
		if ( $requestType === null ) {
63
			$requestType = $need;
64
		} elseif ( $requestType !== $need && !is_subclass_of( $requestType, $need ) ) {
65
			throw new \InvalidArgumentException( "$requestType is not a $need" );
66
		}
67
68
		$this->auth = $auth;
69
		$this->requestType = $requestType;
70
		$this->hasDomain = (
71
			$requestType === PasswordDomainAuthenticationRequest::class ||
72
			is_subclass_of( $requestType, PasswordDomainAuthenticationRequest::class )
73
		);
74
		$this->authoritative = $auth->strict();
75
76
		// Registering hooks from core is unusual, but is needed here to be
77
		// able to call the AuthPlugin methods those hooks replace.
78
		\Hooks::register( 'UserSaveSettings', [ $this, 'onUserSaveSettings' ] );
79
		\Hooks::register( 'UserGroupsChanged', [ $this, 'onUserGroupsChanged' ] );
80
		\Hooks::register( 'UserLoggedIn', [ $this, 'onUserLoggedIn' ] );
81
		\Hooks::register( 'LocalUserCreated', [ $this, 'onLocalUserCreated' ] );
82
	}
83
84
	/**
85
	 * Create an appropriate AuthenticationRequest
86
	 * @return PasswordAuthenticationRequest
87
	 */
88
	protected function makeAuthReq() {
89
		$class = $this->requestType;
90
		if ( $this->hasDomain ) {
91
			return new $class( $this->auth->domainList() );
92
		} else {
93
			return new $class();
94
		}
95
	}
96
97
	/**
98
	 * Call $this->auth->setDomain()
99
	 * @param PasswordAuthenticationRequest $req
100
	 */
101
	protected function setDomain( $req ) {
102
		if ( $this->hasDomain ) {
103
			$domain = $req->domain;
0 ignored issues
show
The property domain does not seem to exist in MediaWiki\Auth\PasswordAuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
104
		} else {
105
			// Just grab the first one.
106
			$domainList = $this->auth->domainList();
107
			$domain = reset( $domainList );
108
		}
109
110
		// Special:UserLogin does this. Strange.
111
		if ( !$this->auth->validDomain( $domain ) ) {
112
			$domain = $this->auth->getDomain();
113
		}
114
		$this->auth->setDomain( $domain );
115
	}
116
117
	/**
118
	 * Hook function to call AuthPlugin::updateExternalDB()
119
	 * @param User $user
120
	 * @codeCoverageIgnore
121
	 */
122
	public function onUserSaveSettings( $user ) {
123
		// No way to know the domain, just hope the provider handles that.
124
		$this->auth->updateExternalDB( $user );
125
	}
126
127
	/**
128
	 * Hook function to call AuthPlugin::updateExternalDBGroups()
129
	 * @param User $user
130
	 * @param array $added
131
	 * @param array $removed
132
	 */
133
	public function onUserGroupsChanged( $user, $added, $removed ) {
134
		// No way to know the domain, just hope the provider handles that.
135
		$this->auth->updateExternalDBGroups( $user, $added, $removed );
136
	}
137
138
	/**
139
	 * Hook function to call AuthPlugin::updateUser()
140
	 * @param User $user
141
	 */
142
	public function onUserLoggedIn( $user ) {
143
		$hookUser = $user;
144
		// No way to know the domain, just hope the provider handles that.
145
		$this->auth->updateUser( $hookUser );
146
		if ( $hookUser !== $user ) {
147
			throw new \UnexpectedValueException(
148
				get_class( $this->auth ) . '::updateUser() tried to replace $user!'
149
			);
150
		}
151
	}
152
153
	/**
154
	 * Hook function to call AuthPlugin::initUser()
155
	 * @param User $user
156
	 * @param bool $autocreated
157
	 */
158 View Code Duplication
	public function onLocalUserCreated( $user, $autocreated ) {
159
		// For $autocreated, see self::autoCreatedAccount()
160
		if ( !$autocreated ) {
161
			$hookUser = $user;
162
			// No way to know the domain, just hope the provider handles that.
163
			$this->auth->initUser( $hookUser, $autocreated );
164
			if ( $hookUser !== $user ) {
165
				throw new \UnexpectedValueException(
166
					get_class( $this->auth ) . '::initUser() tried to replace $user!'
167
				);
168
			}
169
		}
170
	}
171
172
	public function getUniqueId() {
173
		return parent::getUniqueId() . ':' . get_class( $this->auth );
174
	}
175
176
	public function getAuthenticationRequests( $action, array $options ) {
177
		switch ( $action ) {
178
			case AuthManager::ACTION_LOGIN:
179
			case AuthManager::ACTION_CREATE:
180
				return [ $this->makeAuthReq() ];
181
182
			case AuthManager::ACTION_CHANGE:
183
			case AuthManager::ACTION_REMOVE:
184
				// No way to know the domain, just hope the provider handles that.
185
				return $this->auth->allowPasswordChange() ? [ $this->makeAuthReq() ] : [];
186
187
			default:
188
				return [];
189
		}
190
	}
191
192
	public function beginPrimaryAuthentication( array $reqs ) {
193
		$req = AuthenticationRequest::getRequestByClass( $reqs, $this->requestType );
194 View Code Duplication
		if ( !$req || $req->username === null || $req->password === null ||
0 ignored issues
show
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
195
			( $this->hasDomain && $req->domain === null )
0 ignored issues
show
The property domain does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
196
		) {
197
			return AuthenticationResponse::newAbstain();
198
		}
199
200
		$username = User::getCanonicalName( $req->username, 'usable' );
201
		if ( $username === false ) {
202
			return AuthenticationResponse::newAbstain();
203
		}
204
205
		$this->setDomain( $req );
0 ignored issues
show
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
206
		if ( $this->testUserCanAuthenticateInternal( User::newFromName( $username ) ) &&
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 200 can also be of type boolean; however, User::newFromName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
It seems like \User::newFromName($username) targeting User::newFromName() can also be of type false; however, MediaWiki\Auth\AuthPlugi...nAuthenticateInternal() does only seem to accept object<User>, did you maybe forget to handle an error condition?
Loading history...
207
			$this->auth->authenticate( $username, $req->password )
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 200 can also be of type boolean; however, AuthPlugin::authenticate() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
208
		) {
209
			return AuthenticationResponse::newPass( $username );
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 200 can also be of type boolean; however, MediaWiki\Auth\AuthenticationResponse::newPass() does only seem to accept string|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
210
		} else {
211
			$this->authoritative = $this->auth->strict() || $this->auth->strictUserAuth( $username );
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 200 can also be of type boolean; however, AuthPlugin::strictUserAuth() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
212
			return $this->failResponse( $req );
0 ignored issues
show
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
213
		}
214
	}
215
216 View Code Duplication
	public function testUserCanAuthenticate( $username ) {
217
		$username = User::getCanonicalName( $username, 'usable' );
218
		if ( $username === false ) {
219
			return false;
220
		}
221
222
		// We have to check every domain, because at least LdapAuthentication
223
		// interprets AuthPlugin::userExists() as applying only to the current
224
		// domain.
225
		$curDomain = $this->auth->getDomain();
226
		$domains = $this->auth->domainList() ?: [ '' ];
227
		foreach ( $domains as $domain ) {
228
			$this->auth->setDomain( $domain );
229
			if ( $this->testUserCanAuthenticateInternal( User::newFromName( $username ) ) ) {
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($username, 'usable') on line 217 can also be of type boolean; however, User::newFromName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
It seems like \User::newFromName($username) targeting User::newFromName() can also be of type false; however, MediaWiki\Auth\AuthPlugi...nAuthenticateInternal() does only seem to accept object<User>, did you maybe forget to handle an error condition?
Loading history...
230
				$this->auth->setDomain( $curDomain );
231
				return true;
232
			}
233
		}
234
		$this->auth->setDomain( $curDomain );
235
		return false;
236
	}
237
238
	/**
239
	 * @see self::testUserCanAuthenticate
240
	 * @note The caller is responsible for calling $this->auth->setDomain()
241
	 * @param User $user
242
	 * @return bool
243
	 */
244
	private function testUserCanAuthenticateInternal( $user ) {
245
		if ( $this->auth->userExists( $user->getName() ) ) {
246
			return !$this->auth->getUserInstance( $user )->isLocked();
247
		} else {
248
			return false;
249
		}
250
	}
251
252
	public function providerRevokeAccessForUser( $username ) {
253
		$username = User::getCanonicalName( $username, 'usable' );
254
		if ( $username === false ) {
255
			return;
256
		}
257
		$user = User::newFromName( $username );
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($username, 'usable') on line 253 can also be of type boolean; however, User::newFromName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
258
		if ( $user ) {
259
			// Reset the password on every domain.
260
			$curDomain = $this->auth->getDomain();
261
			$domains = $this->auth->domainList() ?: [ '' ];
262
			$failed = [];
263
			foreach ( $domains as $domain ) {
264
				$this->auth->setDomain( $domain );
265
				if ( $this->testUserCanAuthenticateInternal( $user ) &&
266
					!$this->auth->setPassword( $user, null )
267
				) {
268
					$failed[] = $domain === '' ? '(default)' : $domain;
269
				}
270
			}
271
			$this->auth->setDomain( $curDomain );
272
			if ( $failed ) {
273
				throw new \UnexpectedValueException(
274
					"AuthPlugin failed to reset password for $username in the following domains: "
275
						. join( ' ', $failed )
276
				);
277
			}
278
		}
279
	}
280
281 View Code Duplication
	public function testUserExists( $username, $flags = User::READ_NORMAL ) {
282
		$username = User::getCanonicalName( $username, 'usable' );
283
		if ( $username === false ) {
284
			return false;
285
		}
286
287
		// We have to check every domain, because at least LdapAuthentication
288
		// interprets AuthPlugin::userExists() as applying only to the current
289
		// domain.
290
		$curDomain = $this->auth->getDomain();
291
		$domains = $this->auth->domainList() ?: [ '' ];
292
		foreach ( $domains as $domain ) {
293
			$this->auth->setDomain( $domain );
294
			if ( $this->auth->userExists( $username ) ) {
0 ignored issues
show
It seems like $username defined by \User::getCanonicalName($username, 'usable') on line 282 can also be of type boolean; however, AuthPlugin::userExists() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
295
				$this->auth->setDomain( $curDomain );
296
				return true;
297
			}
298
		}
299
		$this->auth->setDomain( $curDomain );
300
		return false;
301
	}
302
303
	public function providerAllowsPropertyChange( $property ) {
304
		// No way to know the domain, just hope the provider handles that.
305
		return $this->auth->allowPropChange( $property );
306
	}
307
308
	public function providerAllowsAuthenticationDataChange(
309
		AuthenticationRequest $req, $checkData = true
310
	) {
311
		if ( get_class( $req ) !== $this->requestType ) {
312
			return \StatusValue::newGood( 'ignored' );
313
		}
314
315
		// Hope it works, AuthPlugin gives us no way to do this.
316
		$curDomain = $this->auth->getDomain();
317
		$this->setDomain( $req );
0 ignored issues
show
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
318
		try {
319
			// If !$checkData the domain might be wrong. Nothing we can do about that.
320
			if ( !$this->auth->allowPasswordChange() ) {
321
				return \StatusValue::newFatal( 'authmanager-authplugin-setpass-denied' );
322
			}
323
324
			if ( !$checkData ) {
325
				return \StatusValue::newGood();
326
			}
327
328
			if ( $this->hasDomain ) {
329
				if ( $req->domain === null ) {
0 ignored issues
show
The property domain does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
330
					return \StatusValue::newGood( 'ignored' );
331
				}
332
				if ( !$this->auth->validDomain( $req->domain ) ) {
333
					return \StatusValue::newFatal( 'authmanager-authplugin-setpass-bad-domain' );
334
				}
335
			}
336
337
			$username = User::getCanonicalName( $req->username, 'usable' );
338
			if ( $username !== false ) {
339
				$sv = \StatusValue::newGood();
340 View Code Duplication
				if ( $req->password !== null ) {
341
					if ( $req->password !== $req->retype ) {
0 ignored issues
show
The property retype does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
342
						$sv->fatal( 'badretype' );
343
					} else {
344
						$sv->merge( $this->checkPasswordValidity( $username, $req->password ) );
0 ignored issues
show
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
It seems like $username defined by \User::getCanonicalName($req->username, 'usable') on line 337 can also be of type boolean; however, MediaWiki\Auth\AbstractP...checkPasswordValidity() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
345
					}
346
				}
347
				return $sv;
348
			} else {
349
				return \StatusValue::newGood( 'ignored' );
350
			}
351
		} finally {
352
			$this->auth->setDomain( $curDomain );
353
		}
354
	}
355
356
	public function providerChangeAuthenticationData( AuthenticationRequest $req ) {
357
		if ( get_class( $req ) === $this->requestType ) {
358
			$username = $req->username !== null ? User::getCanonicalName( $req->username, 'usable' ) : false;
359
			if ( $username === false ) {
360
				return;
361
			}
362
363
			if ( $this->hasDomain && $req->domain === null ) {
0 ignored issues
show
The property domain does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
364
				return;
365
			}
366
367
			$this->setDomain( $req );
0 ignored issues
show
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
368
			$user = User::newFromName( $username );
0 ignored issues
show
It seems like $username defined by $req->username !== null ...name, 'usable') : false on line 358 can also be of type boolean; however, User::newFromName() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
369
			if ( !$this->auth->setPassword( $user, $req->password ) ) {
0 ignored issues
show
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
It seems like $user defined by \User::newFromName($username) on line 368 can also be of type false; however, AuthPlugin::setPassword() does only seem to accept object<User>, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
370
				// This is totally unfriendly and leaves other
371
				// AuthenticationProviders in an uncertain state, but what else
372
				// can we do?
373
				throw new \ErrorPageError(
374
					'authmanager-authplugin-setpass-failed-title',
375
					'authmanager-authplugin-setpass-failed-message'
376
				);
377
			}
378
		}
379
	}
380
381
	public function accountCreationType() {
382
		// No way to know the domain, just hope the provider handles that.
383
		return $this->auth->canCreateAccounts() ? self::TYPE_CREATE : self::TYPE_NONE;
384
	}
385
386
	public function testForAccountCreation( $user, $creator, array $reqs ) {
387
		return \StatusValue::newGood();
388
	}
389
390
	public function beginPrimaryAccountCreation( $user, $creator, array $reqs ) {
391
		if ( $this->accountCreationType() === self::TYPE_NONE ) {
392
			throw new \BadMethodCallException( 'Shouldn\'t call this when accountCreationType() is NONE' );
393
		}
394
395
		$req = AuthenticationRequest::getRequestByClass( $reqs, $this->requestType );
396 View Code Duplication
		if ( !$req || $req->username === null || $req->password === null ||
0 ignored issues
show
The property password does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
397
			( $this->hasDomain && $req->domain === null )
0 ignored issues
show
The property domain does not seem to exist in MediaWiki\Auth\AuthenticationRequest.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
398
		) {
399
			return AuthenticationResponse::newAbstain();
400
		}
401
402
		$username = User::getCanonicalName( $req->username, 'usable' );
403
		if ( $username === false ) {
404
			return AuthenticationResponse::newAbstain();
405
		}
406
407
		$this->setDomain( $req );
0 ignored issues
show
$req of type object<MediaWiki\Auth\AuthenticationRequest> is not a sub-type of object<MediaWiki\Auth\Pa...dAuthenticationRequest>. It seems like you assume a child class of the class MediaWiki\Auth\AuthenticationRequest to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
408
		if ( $this->auth->addUser(
409
			$user, $req->password, $user->getEmail(), $user->getRealName()
410
		) ) {
411
			return AuthenticationResponse::newPass();
412
		} else {
413
			return AuthenticationResponse::newFail(
414
				new \Message( 'authmanager-authplugin-create-fail' )
415
			);
416
		}
417
	}
418
419 View Code Duplication
	public function autoCreatedAccount( $user, $source ) {
420
		$hookUser = $user;
421
		// No way to know the domain, just hope the provider handles that.
422
		$this->auth->initUser( $hookUser, true );
423
		if ( $hookUser !== $user ) {
424
			throw new \UnexpectedValueException(
425
				get_class( $this->auth ) . '::initUser() tried to replace $user!'
426
			);
427
		}
428
	}
429
}
430