Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialUserLogin
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 15
702
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isListed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getLoginSecurityLevel
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultAction
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setHeaders
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
12
 isSignup
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 beforeExecute
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 successfulAction
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
72
 getToken
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 clearToken
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTokenName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 logAuthResult
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
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 */
20
21namespace MediaWiki\Specials;
22
23use LoginHelper;
24use MediaWiki\Auth\AuthManager;
25use MediaWiki\Logger\LoggerFactory;
26use MediaWiki\MainConfigNames;
27use MediaWiki\SpecialPage\LoginSignupSpecialPage;
28use MediaWiki\SpecialPage\SpecialPage;
29use MediaWiki\User\UserIdentity;
30use MediaWiki\User\UserIdentityUtils;
31use StatusValue;
32
33/**
34 * Implements Special:UserLogin
35 *
36 * @ingroup SpecialPage
37 * @ingroup Auth
38 */
39class SpecialUserLogin extends LoginSignupSpecialPage {
40    /** @inheritDoc */
41    protected static $allowedActions = [
42        AuthManager::ACTION_LOGIN,
43        AuthManager::ACTION_LOGIN_CONTINUE
44    ];
45
46    /** @inheritDoc */
47    protected static $messages = [
48        'authform-newtoken' => 'nocookiesforlogin',
49        'authform-notoken' => 'sessionfailure',
50        'authform-wrongtoken' => 'sessionfailure',
51    ];
52
53    private UserIdentityUtils $identityUtils;
54
55    /**
56     * @param AuthManager $authManager
57     */
58    public function __construct( AuthManager $authManager, UserIdentityUtils $identityUtils ) {
59        parent::__construct( 'Userlogin' );
60        $this->setAuthManager( $authManager );
61        $this->identityUtils = $identityUtils;
62    }
63
64    public function doesWrites() {
65        return true;
66    }
67
68    public function isListed() {
69        return $this->getAuthManager()->canAuthenticateNow();
70    }
71
72    protected function getLoginSecurityLevel() {
73        return false;
74    }
75
76    protected function getDefaultAction( $subPage ) {
77        return AuthManager::ACTION_LOGIN;
78    }
79
80    public function getDescription() {
81        return $this->msg( 'login' );
82    }
83
84    public function setHeaders() {
85        // override the page title if we are doing a forced reauthentication
86        parent::setHeaders();
87        if ( $this->securityLevel && $this->getUser()->isRegistered() ) {
88            $this->getOutput()->setPageTitleMsg( $this->msg( 'login-security' ) );
89        }
90    }
91
92    protected function isSignup() {
93        return false;
94    }
95
96    protected function beforeExecute( $subPage ) {
97        if ( $subPage === 'signup' || $this->getRequest()->getText( 'type' ) === 'signup' ) {
98            // B/C for old account creation URLs
99            $title = SpecialPage::getTitleFor( 'CreateAccount' );
100            $query = array_diff_key( $this->getRequest()->getQueryValues(),
101                array_fill_keys( [ 'type', 'title' ], true ) );
102            $url = $title->getFullURL( $query, false, PROTO_CURRENT );
103            $this->getOutput()->redirect( $url );
104            return false;
105        }
106        return parent::beforeExecute( $subPage );
107    }
108
109    /**
110     * Run any hooks registered for logins, then HTTP redirect to
111     * $this->mReturnTo (or Main Page if that's undefined).  Formerly we had a
112     * nice message here, but that's really not as useful as just being sent to
113     * wherever you logged in from.  It should be clear that the action was
114     * successful, given the lack of error messages plus the appearance of your
115     * name in the upper right.
116     * @param bool $direct True if the action was successful just now; false if that happened
117     *    pre-redirection (so this handler was called already)
118     * @param StatusValue|null $extraMessages
119     */
120    protected function successfulAction( $direct = false, $extraMessages = null ) {
121        $secureLogin = $this->getConfig()->get( MainConfigNames::SecureLogin );
122
123        $user = $this->targetUser ?: $this->getUser();
124        $session = $this->getRequest()->getSession();
125
126        $injected_html = '';
127        if ( $direct ) {
128            $user->touch();
129
130            $this->clearToken();
131
132            if ( $user->requiresHTTPS() ) {
133                $this->mStickHTTPS = true;
134            }
135            $session->setForceHTTPS( $secureLogin && $this->mStickHTTPS );
136
137            // If the user does not have a session cookie at this point, they probably need to
138            // do something to their browser.
139            if ( !$this->hasSessionCookie() ) {
140                $this->mainLoginForm( [ /*?*/ ], $session->getProvider()->whyNoSession() );
141                // TODO something more specific? This used to use nocookieslogin
142                return;
143            }
144
145            # Run any hooks; display injected HTML if any, else redirect
146            $this->getHookRunner()->onUserLoginComplete(
147                $user, $injected_html, $direct );
148        }
149
150        if ( $injected_html !== '' || $extraMessages ) {
151            $this->showSuccessPage( 'success', $this->msg( 'loginsuccesstitle' ),
152                'loginsuccess', $injected_html, $extraMessages );
153        } else {
154            $helper = new LoginHelper( $this->getContext() );
155            $helper->showReturnToPage( 'successredirect', $this->mReturnTo, $this->mReturnToQuery,
156                $this->mStickHTTPS, $this->mReturnToAnchor );
157        }
158    }
159
160    protected function getToken() {
161        return $this->getRequest()->getSession()->getToken( '', 'login' );
162    }
163
164    protected function clearToken() {
165        $this->getRequest()->getSession()->resetToken( 'login' );
166    }
167
168    protected function getTokenName() {
169        return 'wpLoginToken';
170    }
171
172    protected function getGroupName() {
173        return 'login';
174    }
175
176    protected function logAuthResult( $success, UserIdentity $performer, $status = null ) {
177        LoggerFactory::getInstance( 'authevents' )->info( 'Login attempt', [
178            'event' => 'login',
179            'successful' => $success,
180            'accountType' => $this->identityUtils->getShortUserTypeInternal( $performer ),
181            'status' => strval( $status ),
182        ] );
183    }
184}
185
186/**
187 * Retain the old class name for backwards compatibility.
188 * @deprecated since 1.41
189 */
190class_alias( SpecialUserLogin::class, 'SpecialUserLogin' );