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