Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiRemoveAuthenticationData
0.00% covered (danger)
0.00%
0 / 50
0.00% covered (danger)
0.00%
0 / 7
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 execute
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
42
 isWriteMode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 needsToken
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Copyright © 2016 Wikimedia Foundation and contributors
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Api;
10
11use MediaWiki\Auth\AuthenticationRequest;
12use MediaWiki\Auth\AuthManager;
13use MediaWiki\MainConfigNames;
14use MediaWiki\Session\SessionManager;
15
16/**
17 * Remove authentication data from AuthManager
18 *
19 * @ingroup API
20 */
21class ApiRemoveAuthenticationData extends ApiBase {
22
23    /** @var string */
24    private $authAction;
25    /** @var string */
26    private $operation;
27
28    public function __construct(
29        ApiMain $main,
30        string $action,
31        private readonly AuthManager $authManager,
32        private readonly SessionManager $sessionManager,
33    ) {
34        parent::__construct( $main, $action );
35
36        $this->authAction = $action === 'unlinkaccount'
37            ? AuthManager::ACTION_UNLINK
38            : AuthManager::ACTION_REMOVE;
39        $this->operation = $action === 'unlinkaccount'
40            ? 'UnlinkAccount'
41            : 'RemoveCredentials';
42    }
43
44    public function execute() {
45        if ( !$this->getUser()->isNamed() ) {
46            $this->dieWithError( 'apierror-mustbeloggedin-removeauth', 'notloggedin' );
47        }
48
49        $this->checkUserRightsAny( 'editmyprivateinfo' );
50
51        $params = $this->extractRequestParams();
52
53        // Check security-sensitive operation status
54        ApiAuthManagerHelper::newForModule( $this, $this->authManager )
55            ->securitySensitiveOperation( $this->operation );
56
57        // Fetch the request. No need to load from the request, so don't use
58        // ApiAuthManagerHelper's method.
59        $remove = $this->authAction === AuthManager::ACTION_REMOVE
60            ? array_fill_keys( $this->getConfig()->get(
61                MainConfigNames::RemoveCredentialsBlacklist ), true )
62            : [];
63        $reqs = array_filter(
64            $this->authManager->getAuthenticationRequests( $this->authAction, $this->getUser() ),
65            static function ( AuthenticationRequest $req ) use ( $params, $remove ) {
66                return $req->getUniqueId() === $params['request'] &&
67                    !isset( $remove[get_class( $req )] );
68            }
69        );
70        if ( count( $reqs ) !== 1 ) {
71            $this->dieWithError( 'apierror-changeauth-norequest', 'badrequest' );
72        }
73        $req = reset( $reqs );
74
75        // Perform the removal
76        $status = $this->authManager->allowsAuthenticationDataChange( $req, true );
77        $this->getHookRunner()->onChangeAuthenticationDataAudit( $req, $status );
78        if ( !$status->isGood() ) {
79            $this->dieStatus( $status );
80        }
81        $this->authManager->changeAuthenticationData( $req );
82
83        // Reset sessions - if the user removed a credential or unlinked an account
84        // because it was compromised, log attackers out from sessions obtained that way.
85        $session = $this->getRequest()->getSession();
86        $user = $this->getUser();
87        $this->sessionManager->invalidateSessionsForUser( $user );
88        $session->setUser( $user );
89        $session->resetId();
90
91        $this->getResult()->addValue( null, $this->getModuleName(), [ 'status' => 'success' ] );
92    }
93
94    /** @inheritDoc */
95    public function isWriteMode() {
96        return true;
97    }
98
99    /** @inheritDoc */
100    public function needsToken() {
101        return 'csrf';
102    }
103
104    /** @inheritDoc */
105    public function getAllowedParams() {
106        return ApiAuthManagerHelper::getStandardParams( $this->authAction,
107            'request'
108        );
109    }
110
111    /** @inheritDoc */
112    protected function getExamplesMessages() {
113        $path = $this->getModulePath();
114        $action = $this->getModuleName();
115        return [
116            "action={$action}&request=FooAuthenticationRequest&token=123ABC"
117                => "apihelp-{$path}-example-simple",
118        ];
119    }
120
121    /** @inheritDoc */
122    public function getHelpUrls() {
123        return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Manage_authentication_data';
124    }
125}
126
127/** @deprecated class alias since 1.43 */
128class_alias( ApiRemoveAuthenticationData::class, 'ApiRemoveAuthenticationData' );