3 namespace MediaWiki\Auth
;
7 * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
9 class ConfirmLinkSecondaryAuthenticationProviderTest
extends \MediaWikiTestCase
{
11 * @dataProvider provideGetAuthenticationRequests
12 * @param string $action
13 * @param array $response
15 public function testGetAuthenticationRequests( $action, $response ) {
16 $provider = new ConfirmLinkSecondaryAuthenticationProvider();
18 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
21 public static function provideGetAuthenticationRequests() {
23 [ AuthManager
::ACTION_LOGIN
, [] ],
24 [ AuthManager
::ACTION_CREATE
, [] ],
25 [ AuthManager
::ACTION_LINK
, [] ],
26 [ AuthManager
::ACTION_CHANGE
, [] ],
27 [ AuthManager
::ACTION_REMOVE
, [] ],
31 public function testBeginSecondaryAuthentication() {
32 $user = \User
::newFromName( 'UTSysop' );
35 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
36 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
38 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
39 ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::authnState' ) )
40 ->will( $this->returnValue( $obj ) );
41 $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
43 $this->assertSame( $obj, $mock->beginSecondaryAuthentication( $user, [] ) );
46 public function testContinueSecondaryAuthentication() {
47 $user = \User
::newFromName( 'UTSysop' );
49 $reqs = [ new \stdClass
];
51 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
52 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
54 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
55 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
57 $this->identicalTo( $user ),
58 $this->identicalTo( 'AuthManager::authnState' ),
59 $this->identicalTo( $reqs )
61 ->will( $this->returnValue( $obj ) );
63 $this->assertSame( $obj, $mock->continueSecondaryAuthentication( $user, $reqs ) );
66 public function testBeginSecondaryAccountCreation() {
67 $user = \User
::newFromName( 'UTSysop' );
70 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
71 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
73 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
74 ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::accountCreationState' ) )
75 ->will( $this->returnValue( $obj ) );
76 $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
78 $this->assertSame( $obj, $mock->beginSecondaryAccountCreation( $user, $user, [] ) );
81 public function testContinueSecondaryAccountCreation() {
82 $user = \User
::newFromName( 'UTSysop' );
84 $reqs = [ new \stdClass
];
86 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
87 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
89 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
90 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
92 $this->identicalTo( $user ),
93 $this->identicalTo( 'AuthManager::accountCreationState' ),
94 $this->identicalTo( $reqs )
96 ->will( $this->returnValue( $obj ) );
98 $this->assertSame( $obj, $mock->continueSecondaryAccountCreation( $user, $user, $reqs ) );
102 * Get requests for testing
103 * @return AuthenticationRequest[]
105 private function getLinkRequests() {
108 $mb = $this->getMockBuilder( AuthenticationRequest
::class )
109 ->setMethods( [ 'getUniqueId' ] );
110 for ( $i = 1; $i <= 3; $i++
) {
111 $req = $mb->getMockForAbstractClass();
112 $req->expects( $this->any() )->method( 'getUniqueId' )
113 ->will( $this->returnValue( "Request$i" ) );
115 $reqs[$req->getUniqueId()] = $req;
121 public function testBeginLinkAttempt() {
122 $badReq = $this->getMockBuilder( AuthenticationRequest
::class )
123 ->setMethods( [ 'getUniqueId' ] )
124 ->getMockForAbstractClass();
125 $badReq->expects( $this->any() )->method( 'getUniqueId' )
126 ->will( $this->returnValue( "BadReq" ) );
128 $user = \User
::newFromName( 'UTSysop' );
129 $provider = \TestingAccessWrapper
::newFromObject(
130 new ConfirmLinkSecondaryAuthenticationProvider
132 $request = new \
FauxRequest();
133 $manager = $this->getMockBuilder( AuthManager
::class )
134 ->setMethods( [ 'allowsAuthenticationDataChange' ] )
135 ->setConstructorArgs( [ $request, \RequestContext
::getMain()->getConfig() ] )
137 $manager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
138 ->will( $this->returnCallback( function ( $req ) {
139 return $req->getUniqueId() !== 'BadReq'
140 ? \StatusValue
::newGood()
141 : \StatusValue
::newFatal( 'no' );
143 $provider->setManager( $manager );
146 AuthenticationResponse
::newAbstain(),
147 $provider->beginLinkAttempt( $user, 'state' )
150 $request->getSession()->setSecret( 'state', [
154 AuthenticationResponse
::newAbstain(),
155 $provider->beginLinkAttempt( $user, 'state' )
158 $reqs = $this->getLinkRequests();
159 $request->getSession()->setSecret( 'state', [
160 'maybeLink' => $reqs +
[ 'BadReq' => $badReq ]
162 $res = $provider->beginLinkAttempt( $user, 'state' );
163 $this->assertInstanceOf( AuthenticationResponse
::class, $res );
164 $this->assertSame( AuthenticationResponse
::UI
, $res->status
);
165 $this->assertSame( 'authprovider-confirmlink-message', $res->message
->getKey() );
166 $this->assertCount( 1, $res->neededRequests
);
167 $req = $res->neededRequests
[0];
168 $this->assertInstanceOf( ConfirmLinkAuthenticationRequest
::class, $req );
169 $expectReqs = $this->getLinkRequests();
170 foreach ( $expectReqs as $r ) {
171 $r->action
= AuthManager
::ACTION_CHANGE
;
172 $r->username
= $user->getName();
174 $this->assertEquals( $expectReqs, \TestingAccessWrapper
::newFromObject( $req )->linkRequests
);
177 public function testContinueLinkAttempt() {
178 $user = \User
::newFromName( 'UTSysop' );
179 $obj = new \stdClass
;
180 $reqs = $this->getLinkRequests();
182 $done = [ false, false, false ];
184 // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
185 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
186 ->setMethods( [ 'beginLinkAttempt' ] )
188 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
189 ->with( $this->identicalTo( $user ), $this->identicalTo( 'state' ) )
190 ->will( $this->returnValue( $obj ) );
193 \TestingAccessWrapper
::newFromObject( $mock )->continueLinkAttempt( $user, 'state', $reqs )
196 // Now test the actual functioning
197 $provider = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
199 'beginLinkAttempt', 'providerAllowsAuthenticationDataChange',
200 'providerChangeAuthenticationData'
203 $provider->expects( $this->never() )->method( 'beginLinkAttempt' );
204 $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
205 ->will( $this->returnCallback( function ( $req ) use ( $reqs ) {
206 return $req->getUniqueId() === 'Request3'
207 ? \StatusValue
::newFatal( 'foo' ) : \StatusValue
::newGood();
209 $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
210 ->will( $this->returnCallback( function ( $req ) use ( &$done ) {
211 $done[$req->id
] = true;
213 $config = new \
HashConfig( [
214 'AuthManagerConfig' => [
218 [ 'factory' => function () use ( $provider ) {
224 $request = new \
FauxRequest();
225 $manager = new AuthManager( $request, $config );
226 $provider->setManager( $manager );
227 $provider = \TestingAccessWrapper
::newFromObject( $provider );
229 $req = new ConfirmLinkAuthenticationRequest( $reqs );
232 AuthenticationResponse
::newAbstain(),
233 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
236 $request->getSession()->setSecret( 'state', [
240 AuthenticationResponse
::newAbstain(),
241 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
244 $request->getSession()->setSecret( 'state', [
248 AuthenticationResponse
::newPass(),
249 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] )
251 $this->assertSame( [ false, false, false ], $done );
253 $request->getSession()->setSecret( 'state', [
254 'maybeLink' => [ $reqs['Request2'] ],
256 $req->confirmedLinkIDs
= [ 'Request1', 'Request2' ];
257 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
258 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
259 $this->assertSame( [ false, true, false ], $done );
260 $done = [ false, false, false ];
262 $request->getSession()->setSecret( 'state', [
263 'maybeLink' => $reqs,
265 $req->confirmedLinkIDs
= [ 'Request1', 'Request2' ];
266 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
267 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
268 $this->assertSame( [ true, true, false ], $done );
269 $done = [ false, false, false ];
271 $request->getSession()->setSecret( 'state', [
272 'maybeLink' => $reqs,
274 $req->confirmedLinkIDs
= [ 'Request1', 'Request3' ];
275 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
276 $this->assertEquals( AuthenticationResponse
::UI
, $res->status
);
277 $this->assertCount( 1, $res->neededRequests
);
278 $this->assertInstanceOf( ButtonAuthenticationRequest
::class, $res->neededRequests
[0] );
279 $this->assertSame( [ true, false, false ], $done );
280 $done = [ false, false, false ];
282 $res = $provider->continueLinkAttempt( $user, 'state', [ $res->neededRequests
[0] ] );
283 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
284 $this->assertSame( [ false, false, false ], $done );