Completed
Branch master (1b8556)
by
unknown
26:56
created

failResponse()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 6
c 1
b 0
f 1
nc 2
nop 1
dl 0
loc 9
rs 9.6666
1
<?php
2
/**
3
 * This program is free software; you can redistribute it and/or modify
4
 * it under the terms of the GNU General Public License as published by
5
 * the Free Software Foundation; either version 2 of the License, or
6
 * (at your option) any later version.
7
 *
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
 * GNU General Public License for more details.
12
 *
13
 * You should have received a copy of the GNU General Public License along
14
 * with this program; if not, write to the Free Software Foundation, Inc.,
15
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
 * http://www.gnu.org/copyleft/gpl.html
17
 *
18
 * @file
19
 * @ingroup Auth
20
 */
21
22
namespace MediaWiki\Auth;
23
24
use Password;
25
use PasswordFactory;
26
use Status;
27
28
/**
29
 * Basic framework for a primary authentication provider that uses passwords
30
 * @ingroup Auth
31
 * @since 1.27
32
 */
33
abstract class AbstractPasswordPrimaryAuthenticationProvider
34
	extends AbstractPrimaryAuthenticationProvider
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
35
{
36
	/** @var bool Whether this provider should ABSTAIN (false) or FAIL (true) on password failure */
37
	protected $authoritative = true;
38
39
	private $passwordFactory = null;
40
41
	/**
42
	 * @param array $params Settings
43
	 *  - authoritative: Whether this provider should ABSTAIN (false) or FAIL
44
	 *    (true) on password failure
45
	 */
46
	public function __construct( array $params = [] ) {
47
		$this->authoritative = !isset( $params['authoritative'] ) || (bool)$params['authoritative'];
48
	}
49
50
	/**
51
	 * Get the PasswordFactory
52
	 * @return PasswordFactory
53
	 */
54
	protected function getPasswordFactory() {
55
		if ( $this->passwordFactory === null ) {
56
			$this->passwordFactory = new PasswordFactory();
57
			$this->passwordFactory->init( $this->config );
58
		}
59
		return $this->passwordFactory;
60
	}
61
62
	/**
63
	 * Get a Password object from the hash
64
	 * @param string $hash
65
	 * @return Password
66
	 */
67
	protected function getPassword( $hash ) {
68
		$passwordFactory = $this->getPasswordFactory();
69
		try {
70
			return $passwordFactory->newFromCiphertext( $hash );
71
		} catch ( \PasswordError $e ) {
72
			$class = static::class;
73
			$this->logger->debug( "Invalid password hash in {$class}::getPassword()" );
74
			return $passwordFactory->newFromCiphertext( null );
75
		}
76
	}
77
78
	/**
79
	 * Return the appropriate response for failure
80
	 * @param PasswordAuthenticationRequest $req
81
	 * @return AuthenticationResponse
82
	 */
83
	protected function failResponse( PasswordAuthenticationRequest $req ) {
84
		if ( $this->authoritative ) {
85
			return AuthenticationResponse::newFail(
86
				wfMessage( $req->password === '' ? 'wrongpasswordempty' : 'wrongpassword' )
87
			);
88
		} else {
89
			return AuthenticationResponse::newAbstain();
90
		}
91
	}
92
93
	/**
94
	 * Check that the password is valid
95
	 *
96
	 * This should be called *before* validating the password. If the result is
97
	 * not ok, login should fail immediately.
98
	 *
99
	 * @param string $username
100
	 * @param string $password
101
	 * @return Status
102
	 */
103
	protected function checkPasswordValidity( $username, $password ) {
104
		return \User::newFromName( $username )->checkPasswordValidity( $password );
105
	}
106
107
	/**
108
	 * Check if the password should be reset
109
	 *
110
	 * This should be called after a successful login. It sets 'reset-pass'
111
	 * authentication data if necessary, see
112
	 * ResetPassSecondaryAuthenticationProvider.
113
	 *
114
	 * @param string $username
115
	 * @param Status $status From $this->checkPasswordValidity()
116
	 * @param mixed $data Passed through to $this->getPasswordResetData()
117
	 */
118
	protected function setPasswordResetFlag( $username, Status $status, $data = null ) {
119
		$reset = $this->getPasswordResetData( $username, $data );
120
121
		if ( !$reset && $this->config->get( 'InvalidPasswordReset' ) && !$status->isGood() ) {
122
			$reset = (object)[
123
				'msg' => $status->getMessage( 'resetpass-validity-soft' ),
124
				'hard' => false,
125
			];
126
		}
127
128
		if ( $reset ) {
129
			$this->manager->setAuthenticationSessionData( 'reset-pass', $reset );
130
		}
131
	}
132
133
	/**
134
	 * Get password reset data, if any
135
	 *
136
	 * @param string $username
137
	 * @param mixed $data
138
	 * @return object|null { 'hard' => bool, 'msg' => Message }
139
	 */
140
	protected function getPasswordResetData( $username, $data ) {
141
		return null;
142
	}
143
144
	/**
145
	 * Get expiration date for a new password, if any
146
	 *
147
	 * @param string $username
148
	 * @return string|null
149
	 */
150
	protected function getNewPasswordExpiry( $username ) {
151
		$days = $this->config->get( 'PasswordExpirationDays' );
152
		$expires = $days ? wfTimestamp( TS_MW, time() + $days * 86400 ) : null;
153
154
		// Give extensions a chance to force an expiration
155
		\Hooks::run( 'ResetPasswordExpiration', [ \User::newFromName( $username ), &$expires ] );
156
157
		return $expires;
158
	}
159
160
	public function getAuthenticationRequests( $action, array $options ) {
161
		switch ( $action ) {
162
			case AuthManager::ACTION_LOGIN:
163
			case AuthManager::ACTION_REMOVE:
164
			case AuthManager::ACTION_CREATE:
165
			case AuthManager::ACTION_CHANGE:
166
				return [ new PasswordAuthenticationRequest() ];
167
			default:
168
				return [];
169
		}
170
	}
171
}
172