3 namespace MediaWiki\Auth
;
8 * Links third-party authentication to the user's account
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.
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.
18 class ConfirmLinkSecondaryAuthenticationProvider
extends AbstractSecondaryAuthenticationProvider
{
20 public function getAuthenticationRequests( $action, array $options ) {
24 public function beginSecondaryAuthentication( $user, array $reqs ) {
25 return $this->beginLinkAttempt( $user, 'AuthManager::authnState' );
28 public function continueSecondaryAuthentication( $user, array $reqs ) {
29 return $this->continueLinkAttempt( $user, 'AuthManager::authnState', $reqs );
32 public function beginSecondaryAccountCreation( $user, $creator, array $reqs ) {
33 return $this->beginLinkAttempt( $user, 'AuthManager::accountCreationState' );
36 public function continueSecondaryAccountCreation( $user, $creator, array $reqs ) {
37 return $this->continueLinkAttempt( $user, 'AuthManager::accountCreationState', $reqs );
41 * Begin the link attempt
43 * @param string $key Session key to look in
44 * @return AuthenticationResponse
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();
53 $maybeLink = array_filter( $state['maybeLink'], function ( $req ) use ( $user ) {
54 if ( !$req->action
) {
55 $req->action
= AuthManager
::ACTION_CHANGE
;
57 $req->username
= $user->getName();
58 return $this->manager
->allowsAuthenticationDataChange( $req )->isGood();
61 return AuthenticationResponse
::newAbstain();
64 $req = new ConfirmLinkAuthenticationRequest( $maybeLink );
65 return AuthenticationResponse
::newUI(
67 wfMessage( 'authprovider-confirmlink-message' ),
73 * Continue the link attempt
75 * @param string $key Session key to look in
76 * @param AuthenticationRequest[] $reqs
77 * @return AuthenticationResponse
79 protected function continueLinkAttempt( $user, $key, array $reqs ) {
80 $req = ButtonAuthenticationRequest
::getRequestByName( $reqs, 'linkOk' );
82 return AuthenticationResponse
::newPass();
85 $req = AuthenticationRequest
::getRequestByClass( $reqs, ConfirmLinkAuthenticationRequest
::class );
88 return $this->beginLinkAttempt( $user, $key );
91 $session = $this->manager
->getRequest()->getSession();
92 $state = $session->getSecret( $key );
93 if ( !is_array( $state ) ) {
94 return AuthenticationResponse
::newAbstain();
98 foreach ( $state['maybeLink'] as $linkReq ) {
99 $maybeLink[$linkReq->getUniqueId()] = $linkReq;
102 return AuthenticationResponse
::newAbstain();
105 $state['maybeLink'] = [];
106 $session->setSecret( $key, $state );
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
;
119 $status = $this->manager
->allowsAuthenticationDataChange( $req );
120 $statuses[] = [ $req, $status ];
121 if ( $status->isGood() ) {
122 $this->manager
->changeAuthenticationData( $req );
129 return AuthenticationResponse
::newPass();
132 $combinedStatus = \Status
::newGood();
133 foreach ( $statuses as $data ) {
134 list( $req, $status ) = $data;
135 $descriptionInfo = $req->describeCredentials();
136 $description = wfMessage(
137 'authprovider-confirmlink-option',
138 $descriptionInfo['provider']->text(), $descriptionInfo['account']->text()
140 if ( $status->isGood() ) {
141 $combinedStatus->error( wfMessage( 'authprovider-confirmlink-success-line', $description ) );
143 $combinedStatus->error( wfMessage(
144 'authprovider-confirmlink-failed-line', $description, $status->getMessage()->text()
148 return AuthenticationResponse
::newUI(
150 new ButtonAuthenticationRequest(
151 'linkOk', wfMessage( 'ok' ), wfMessage( 'authprovider-confirmlink-ok-help' )
154 $combinedStatus->getMessage( 'authprovider-confirmlink-failed' ),