Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
76 / 76 |
|
100.00% |
7 / 7 |
CRAP | |
100.00% |
1 / 1 |
ConfirmLinkSecondaryAuthenticationProvider | |
100.00% |
76 / 76 |
|
100.00% |
7 / 7 |
22 | |
100.00% |
1 / 1 |
getAuthenticationRequests | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
beginSecondaryAuthentication | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
continueSecondaryAuthentication | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
beginSecondaryAccountCreation | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
continueSecondaryAccountCreation | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
beginLinkAttempt | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
4 | |||
continueLinkAttempt | |
100.00% |
53 / 53 |
|
100.00% |
1 / 1 |
13 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Auth; |
4 | |
5 | use MediaWiki\User\User; |
6 | |
7 | /** |
8 | * Links third-party authentication to the user's account |
9 | * |
10 | * If the user logged into linking provider accounts that aren't linked to a |
11 | * local user, this provider will prompt the user to link them after a |
12 | * successful login or account creation. |
13 | * |
14 | * To avoid confusing behavior, this provider should be later in the |
15 | * configuration list than any provider that can abort the authentication |
16 | * process, so that it is only invoked for successful authentication. |
17 | */ |
18 | class ConfirmLinkSecondaryAuthenticationProvider extends AbstractSecondaryAuthenticationProvider { |
19 | |
20 | public function getAuthenticationRequests( $action, array $options ) { |
21 | return []; |
22 | } |
23 | |
24 | public function beginSecondaryAuthentication( $user, array $reqs ) { |
25 | return $this->beginLinkAttempt( $user, AuthManager::AUTHN_STATE ); |
26 | } |
27 | |
28 | public function continueSecondaryAuthentication( $user, array $reqs ) { |
29 | return $this->continueLinkAttempt( $user, AuthManager::AUTHN_STATE, $reqs ); |
30 | } |
31 | |
32 | public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) { |
33 | return $this->beginLinkAttempt( $user, AuthManager::ACCOUNT_CREATION_STATE ); |
34 | } |
35 | |
36 | public function continueSecondaryAccountCreation( $user, $creator, array $reqs ) { |
37 | return $this->continueLinkAttempt( $user, AuthManager::ACCOUNT_CREATION_STATE, $reqs ); |
38 | } |
39 | |
40 | /** |
41 | * Begin the link attempt |
42 | * @param User $user |
43 | * @param string $key Session key to look in |
44 | * @return AuthenticationResponse |
45 | */ |
46 | protected function beginLinkAttempt( $user, $key ) { |
47 | $session = $this->manager->getRequest()->getSession(); |
48 | $state = $session->getSecret( $key ); |
49 | if ( !is_array( $state ) ) { |
50 | return AuthenticationResponse::newAbstain(); |
51 | } |
52 | |
53 | $maybeLink = array_filter( $state['maybeLink'], function ( $req ) use ( $user ) { |
54 | if ( !$req->action ) { |
55 | $req->action = AuthManager::ACTION_CHANGE; |
56 | } |
57 | $req->username = $user->getName(); |
58 | return $this->manager->allowsAuthenticationDataChange( $req )->isGood(); |
59 | } ); |
60 | if ( !$maybeLink ) { |
61 | return AuthenticationResponse::newAbstain(); |
62 | } |
63 | |
64 | $req = new ConfirmLinkAuthenticationRequest( $maybeLink ); |
65 | return AuthenticationResponse::newUI( |
66 | [ $req ], |
67 | wfMessage( 'authprovider-confirmlink-message' ), |
68 | 'warning' |
69 | ); |
70 | } |
71 | |
72 | /** |
73 | * Continue the link attempt |
74 | * @param User $user |
75 | * @param string $key Session key to look in |
76 | * @param AuthenticationRequest[] $reqs |
77 | * @return AuthenticationResponse |
78 | */ |
79 | protected function continueLinkAttempt( $user, $key, array $reqs ) { |
80 | $req = ButtonAuthenticationRequest::getRequestByName( $reqs, 'linkOk' ); |
81 | if ( $req ) { |
82 | return AuthenticationResponse::newPass(); |
83 | } |
84 | |
85 | $req = AuthenticationRequest::getRequestByClass( $reqs, ConfirmLinkAuthenticationRequest::class ); |
86 | if ( !$req ) { |
87 | // WTF? Retry. |
88 | return $this->beginLinkAttempt( $user, $key ); |
89 | } |
90 | |
91 | $session = $this->manager->getRequest()->getSession(); |
92 | $state = $session->getSecret( $key ); |
93 | if ( !is_array( $state ) ) { |
94 | return AuthenticationResponse::newAbstain(); |
95 | } |
96 | |
97 | $maybeLink = []; |
98 | foreach ( $state['maybeLink'] as $linkReq ) { |
99 | $maybeLink[$linkReq->getUniqueId()] = $linkReq; |
100 | } |
101 | if ( !$maybeLink ) { |
102 | return AuthenticationResponse::newAbstain(); |
103 | } |
104 | |
105 | $state['maybeLink'] = []; |
106 | $session->setSecret( $key, $state ); |
107 | |
108 | $statuses = []; |
109 | $anyFailed = false; |
110 | foreach ( $req->confirmedLinkIDs as $id ) { |
111 | if ( isset( $maybeLink[$id] ) ) { |
112 | $req = $maybeLink[$id]; |
113 | $req->username = $user->getName(); |
114 | if ( !$req->action ) { |
115 | // Make sure the action is set, but don't override it if |
116 | // the provider filled it in. |
117 | $req->action = AuthManager::ACTION_CHANGE; |
118 | } |
119 | $status = $this->manager->allowsAuthenticationDataChange( $req ); |
120 | $statuses[] = [ $req, $status ]; |
121 | if ( $status->isGood() ) { |
122 | // We're not changing credentials, just adding a new link |
123 | // to an already-known user. |
124 | $this->manager->changeAuthenticationData( $req, /* $isAddition */ true ); |
125 | } else { |
126 | $anyFailed = true; |
127 | } |
128 | } |
129 | } |
130 | if ( !$anyFailed ) { |
131 | return AuthenticationResponse::newPass(); |
132 | } |
133 | |
134 | $combinedStatus = \MediaWiki\Status\Status::newGood(); |
135 | foreach ( $statuses as [ $req, $status ] ) { |
136 | $descriptionInfo = $req->describeCredentials(); |
137 | $description = wfMessage( |
138 | 'authprovider-confirmlink-option', |
139 | $descriptionInfo['provider']->text(), $descriptionInfo['account']->text() |
140 | )->text(); |
141 | if ( $status->isGood() ) { |
142 | $combinedStatus->error( wfMessage( 'authprovider-confirmlink-success-line', $description ) ); |
143 | } else { |
144 | $combinedStatus->error( wfMessage( |
145 | 'authprovider-confirmlink-failed-line', $description, $status->getMessage()->text() |
146 | ) ); |
147 | } |
148 | } |
149 | return AuthenticationResponse::newUI( |
150 | [ |
151 | new ButtonAuthenticationRequest( |
152 | 'linkOk', wfMessage( 'ok' ), wfMessage( 'authprovider-confirmlink-ok-help' ) |
153 | ) |
154 | ], |
155 | $combinedStatus->getMessage( 'authprovider-confirmlink-failed' ), |
156 | 'error' |
157 | ); |
158 | } |
159 | } |