Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.14% covered (success)
97.14%
34 / 35
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
AuthenticationResponse
97.14% covered (success)
97.14%
34 / 35
83.33% covered (warning)
83.33%
5 / 6
10
0.00% covered (danger)
0.00%
0 / 1
 newPass
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 newFail
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 newRestart
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 newAbstain
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 newUI
90.00% covered (success)
90.00%
9 / 10
0.00% covered (danger)
0.00%
0 / 1
4.02
 newRedirect
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2/**
3 * Authentication response value object
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
24namespace MediaWiki\Auth;
25
26use InvalidArgumentException;
27use MediaWiki\Message\Message;
28
29/**
30 * This is a value object to hold authentication response data
31 *
32 * An AuthenticationResponse represents both the status of the authentication
33 * (success, failure, in progress) and its state (what data is needed to continue).
34 *
35 * @ingroup Auth
36 * @since 1.27
37 */
38class AuthenticationResponse {
39    /** Indicates that the authentication succeeded. */
40    public const PASS = 'PASS';
41
42    /** Indicates that the authentication failed. */
43    public const FAIL = 'FAIL';
44
45    /** Indicates that third-party authentication succeeded but no user exists.
46     * Either treat this like a UI response or pass $this->createRequest to
47     * AuthManager::beginCreateAccount(). For use by AuthManager only (providers
48     * should just return a PASS with no username).
49     */
50    public const RESTART = 'RESTART';
51
52    /** Indicates that the authentication provider does not handle this request. */
53    public const ABSTAIN = 'ABSTAIN';
54
55    /** Indicates that the authentication needs further user input of some sort. */
56    public const UI = 'UI';
57
58    /** Indicates that the authentication needs to be redirected to a third party to proceed. */
59    public const REDIRECT = 'REDIRECT';
60
61    /** @var string One of the constants above */
62    public $status;
63
64    /** @var string|null URL to redirect to for a REDIRECT response */
65    public $redirectTarget = null;
66
67    /**
68     * @var mixed Data for a REDIRECT response that a client might use to
69     * query the remote site via its API rather than by following $redirectTarget.
70     * Value must be something acceptable to ApiResult::addValue().
71     */
72    public $redirectApiData = null;
73
74    /**
75     * @var AuthenticationRequest[] Needed AuthenticationRequests to continue
76     * after a UI or REDIRECT response. This plays the same role when continuing
77     * authentication as AuthManager::getAuthenticationRequests() does when
78     * beginning it.
79     */
80    public $neededRequests = [];
81
82    /** @var Message|null I18n message to display in case of UI or FAIL */
83    public $message = null;
84
85    /** @var string Whether the $message is an error or warning message, for styling reasons */
86    public $messageType = 'warning';
87
88    /**
89     * @var string|null Local username from authentication.
90     * The value may be null if the authentication passed, but no local user is known.
91     */
92    public $username = null;
93
94    /**
95     * @var AuthenticationRequest|null
96     *
97     * Returned with a PrimaryAuthenticationProvider login FAIL or a PASS with
98     * no username, this can be set to a request that should result in a PASS when
99     * passed to that provider's PrimaryAuthenticationProvider::beginPrimaryAccountCreation().
100     * The client will be able to send that back for expedited account creation where only
101     * the username needs to be filled.
102     *
103     * Returned with an AuthManager login FAIL or RESTART, this holds a
104     * CreateFromLoginAuthenticationRequest that may be passed to
105     * AuthManager::beginCreateAccount(), possibly in place of any
106     * "primary-required" requests. It may also be passed to
107     * AuthManager::beginAuthentication() to preserve the list of
108     * accounts which can be linked after success (see $linkRequest).
109     */
110    public $createRequest = null;
111
112    /**
113     * @var AuthenticationRequest|null When returned with a PrimaryAuthenticationProvider
114     *  login PASS with no username, the request this holds will be passed to
115     *  AuthManager::changeAuthenticationData() once the local user has been determined and the
116     *  user has confirmed the account ownership (by reviewing the information given by
117     *  $linkRequest->describeCredentials()). The provider should handle that
118     *  changeAuthenticationData() call by doing the actual linking.
119     */
120    public $linkRequest = null;
121
122    /**
123     * @var AuthenticationRequest|null Returned with an AuthManager account
124     *  creation PASS, this holds a request to pass to AuthManager::beginAuthentication()
125     *  to immediately log into the created account. All provider methods except
126     *   postAuthentication will be skipped.
127     */
128    public $loginRequest = null;
129
130    /**
131     * @var string[]|null String data that is optionally provided on a FAIL. It describes information about the
132     *  failed AuthenticationResponse that shouldn't be shared with the client.
133     *
134     *  The CheckUser extension uses this so that it can receive whether a login request for a locked
135     *  account had the correct password. Using the I18n message would allow the client to see if the
136     *  password they tried on the locked account was correct while this method does not show the client this info.
137     */
138    public $failReasons = null;
139
140    /**
141     * @param string|null $username Local username
142     * @return AuthenticationResponse
143     * @see AuthenticationResponse::PASS
144     */
145    public static function newPass( $username = null ) {
146        $ret = new AuthenticationResponse;
147        $ret->status = self::PASS;
148        $ret->username = $username;
149        return $ret;
150    }
151
152    /**
153     * @param Message $msg
154     * @param string[] $failReasons An array of strings that describes the reason(s) for a login failure
155     * @return AuthenticationResponse
156     * @see AuthenticationResponse::FAIL
157     */
158    public static function newFail( Message $msg, array $failReasons = [] ) {
159        $ret = new AuthenticationResponse;
160        $ret->status = self::FAIL;
161        $ret->message = $msg;
162        $ret->messageType = 'error';
163        $ret->failReasons = $failReasons;
164        return $ret;
165    }
166
167    /**
168     * @param Message $msg
169     * @return AuthenticationResponse
170     * @see AuthenticationResponse::RESTART
171     */
172    public static function newRestart( Message $msg ) {
173        $ret = new AuthenticationResponse;
174        $ret->status = self::RESTART;
175        $ret->message = $msg;
176        return $ret;
177    }
178
179    /**
180     * @return AuthenticationResponse
181     * @see AuthenticationResponse::ABSTAIN
182     */
183    public static function newAbstain() {
184        $ret = new AuthenticationResponse;
185        $ret->status = self::ABSTAIN;
186        return $ret;
187    }
188
189    /**
190     * @param AuthenticationRequest[] $reqs AuthenticationRequests needed to continue
191     * @param Message $msg
192     * @param string $msgtype
193     * @return AuthenticationResponse
194     * @see AuthenticationResponse::UI
195     */
196    public static function newUI( array $reqs, Message $msg, $msgtype = 'warning' ) {
197        if ( !$reqs ) {
198            throw new InvalidArgumentException( '$reqs may not be empty' );
199        }
200        if ( $msgtype !== 'warning' && $msgtype !== 'error' ) {
201            throw new InvalidArgumentException( $msgtype . ' is not a valid message type.' );
202        }
203
204        $ret = new AuthenticationResponse;
205        $ret->status = self::UI;
206        $ret->neededRequests = $reqs;
207        $ret->message = $msg;
208        $ret->messageType = $msgtype;
209        return $ret;
210    }
211
212    /**
213     * @param AuthenticationRequest[] $reqs AuthenticationRequests needed to continue
214     * @param string $redirectTarget URL
215     * @param mixed|null $redirectApiData Data suitable for adding to an ApiResult
216     * @return AuthenticationResponse
217     * @see AuthenticationResponse::REDIRECT
218     */
219    public static function newRedirect( array $reqs, $redirectTarget, $redirectApiData = null ) {
220        if ( !$reqs ) {
221            throw new InvalidArgumentException( '$reqs may not be empty' );
222        }
223
224        $ret = new AuthenticationResponse;
225        $ret->status = self::REDIRECT;
226        $ret->neededRequests = $reqs;
227        $ret->redirectTarget = $redirectTarget;
228        $ret->redirectApiData = $redirectApiData;
229        return $ret;
230    }
231
232}