3 namespace MediaWiki\Auth
;
7 * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
9 class ConfirmLinkSecondaryAuthenticationProviderTest
extends \MediaWikiTestCase
{
10 protected function setUp() {
11 global $wgDisableAuthManager;
14 if ( $wgDisableAuthManager ) {
15 $this->markTestSkipped( '$wgDisableAuthManager is set' );
20 * @dataProvider provideGetAuthenticationRequests
21 * @param string $action
22 * @param array $response
24 public function testGetAuthenticationRequests( $action, $response ) {
25 $provider = new ConfirmLinkSecondaryAuthenticationProvider();
27 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
30 public static function provideGetAuthenticationRequests() {
32 [ AuthManager
::ACTION_LOGIN
, [] ],
33 [ AuthManager
::ACTION_CREATE
, [] ],
34 [ AuthManager
::ACTION_LINK
, [] ],
35 [ AuthManager
::ACTION_CHANGE
, [] ],
36 [ AuthManager
::ACTION_REMOVE
, [] ],
40 public function testBeginSecondaryAuthentication() {
41 $user = \User
::newFromName( 'UTSysop' );
44 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
45 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
47 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
48 ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::authnState' ) )
49 ->will( $this->returnValue( $obj ) );
50 $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
52 $this->assertSame( $obj, $mock->beginSecondaryAuthentication( $user, [] ) );
55 public function testContinueSecondaryAuthentication() {
56 $user = \User
::newFromName( 'UTSysop' );
58 $reqs = [ new \stdClass
];
60 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
61 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
63 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
64 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
66 $this->identicalTo( $user ),
67 $this->identicalTo( 'AuthManager::authnState' ),
68 $this->identicalTo( $reqs )
70 ->will( $this->returnValue( $obj ) );
72 $this->assertSame( $obj, $mock->continueSecondaryAuthentication( $user, $reqs ) );
75 public function testBeginSecondaryAccountCreation() {
76 $user = \User
::newFromName( 'UTSysop' );
79 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
80 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
82 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
83 ->with( $this->identicalTo( $user ), $this->identicalTo( 'AuthManager::accountCreationState' ) )
84 ->will( $this->returnValue( $obj ) );
85 $mock->expects( $this->never() )->method( 'continueLinkAttempt' );
87 $this->assertSame( $obj, $mock->beginSecondaryAccountCreation( $user, $user, [] ) );
90 public function testContinueSecondaryAccountCreation() {
91 $user = \User
::newFromName( 'UTSysop' );
93 $reqs = [ new \stdClass
];
95 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
96 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
98 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
99 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
101 $this->identicalTo( $user ),
102 $this->identicalTo( 'AuthManager::accountCreationState' ),
103 $this->identicalTo( $reqs )
105 ->will( $this->returnValue( $obj ) );
107 $this->assertSame( $obj, $mock->continueSecondaryAccountCreation( $user, $user, $reqs ) );
111 * Get requests for testing
112 * @return AuthenticationRequest[]
114 private function getLinkRequests() {
117 $mb = $this->getMockBuilder( AuthenticationRequest
::class )
118 ->setMethods( [ 'getUniqueId' ] );
119 for ( $i = 1; $i <= 3; $i++
) {
120 $req = $mb->getMockForAbstractClass();
121 $req->expects( $this->any() )->method( 'getUniqueId' )
122 ->will( $this->returnValue( "Request$i" ) );
124 $reqs[$req->getUniqueId()] = $req;
130 public function testBeginLinkAttempt() {
131 $badReq = $this->getMockBuilder( AuthenticationRequest
::class )
132 ->setMethods( [ 'getUniqueId' ] )
133 ->getMockForAbstractClass();
134 $badReq->expects( $this->any() )->method( 'getUniqueId' )
135 ->will( $this->returnValue( "BadReq" ) );
137 $user = \User
::newFromName( 'UTSysop' );
138 $provider = \TestingAccessWrapper
::newFromObject(
139 new ConfirmLinkSecondaryAuthenticationProvider
141 $request = new \
FauxRequest();
142 $manager = $this->getMockBuilder( AuthManager
::class )
143 ->setMethods( [ 'allowsAuthenticationDataChange' ] )
144 ->setConstructorArgs( [ $request, \RequestContext
::getMain()->getConfig() ] )
146 $manager->expects( $this->any() )->method( 'allowsAuthenticationDataChange' )
147 ->will( $this->returnCallback( function ( $req ) {
148 return $req->getUniqueId() !== 'BadReq'
149 ? \StatusValue
::newGood()
150 : \StatusValue
::newFatal( 'no' );
152 $provider->setManager( $manager );
155 AuthenticationResponse
::newAbstain(),
156 $provider->beginLinkAttempt( $user, 'state' )
159 $request->getSession()->setSecret( 'state', [
163 AuthenticationResponse
::newAbstain(),
164 $provider->beginLinkAttempt( $user, 'state' )
167 $reqs = $this->getLinkRequests();
168 $request->getSession()->setSecret( 'state', [
169 'maybeLink' => $reqs +
[ 'BadReq' => $badReq ]
171 $res = $provider->beginLinkAttempt( $user, 'state' );
172 $this->assertInstanceOf( AuthenticationResponse
::class, $res );
173 $this->assertSame( AuthenticationResponse
::UI
, $res->status
);
174 $this->assertSame( 'authprovider-confirmlink-message', $res->message
->getKey() );
175 $this->assertCount( 1, $res->neededRequests
);
176 $req = $res->neededRequests
[0];
177 $this->assertInstanceOf( ConfirmLinkAuthenticationRequest
::class, $req );
178 $this->assertEquals( $reqs, \TestingAccessWrapper
::newFromObject( $req )->linkRequests
);
181 public function testContinueLinkAttempt() {
182 $user = \User
::newFromName( 'UTSysop' );
183 $obj = new \stdClass
;
184 $reqs = $this->getLinkRequests();
186 $done = [ false, false, false ];
188 // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
189 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
190 ->setMethods( [ 'beginLinkAttempt' ] )
192 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
193 ->with( $this->identicalTo( $user ), $this->identicalTo( 'state' ) )
194 ->will( $this->returnValue( $obj ) );
197 \TestingAccessWrapper
::newFromObject( $mock )->continueLinkAttempt( $user, 'state', $reqs )
200 // Now test the actual functioning
201 $provider = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider
::class )
203 'beginLinkAttempt', 'providerAllowsAuthenticationDataChange',
204 'providerChangeAuthenticationData'
207 $provider->expects( $this->never() )->method( 'beginLinkAttempt' );
208 $provider->expects( $this->any() )->method( 'providerAllowsAuthenticationDataChange' )
209 ->will( $this->returnCallback( function ( $req ) use ( $reqs ) {
210 return $req->getUniqueId() === 'Request3'
211 ? \StatusValue
::newFatal( 'foo' ) : \StatusValue
::newGood();
213 $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
214 ->will( $this->returnCallback( function ( $req ) use ( &$done ) {
215 $done[$req->id
] = true;
217 $config = new \
HashConfig( [
218 'AuthManagerConfig' => [
222 [ 'factory' => function () use ( $provider ) {
228 $request = new \
FauxRequest();
229 $manager = new AuthManager( $request, $config );
230 $provider->setManager( $manager );
231 $provider = \TestingAccessWrapper
::newFromObject( $provider );
233 $req = new ConfirmLinkAuthenticationRequest( $reqs );
236 AuthenticationResponse
::newAbstain(),
237 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
240 $request->getSession()->setSecret( 'state', [
244 AuthenticationResponse
::newAbstain(),
245 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
248 $request->getSession()->setSecret( 'state', [
252 AuthenticationResponse
::newPass(),
253 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] )
255 $this->assertSame( [ false, false, false ], $done );
257 $request->getSession()->setSecret( 'state', [
258 'maybeLink' => [ $reqs['Request2'] ],
260 $req->confirmedLinkIDs
= [ 'Request1', 'Request2' ];
261 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
262 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
263 $this->assertSame( [ false, true, false ], $done );
264 $done = [ false, false, false ];
266 $request->getSession()->setSecret( 'state', [
267 'maybeLink' => $reqs,
269 $req->confirmedLinkIDs
= [ 'Request1', 'Request2' ];
270 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
271 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
272 $this->assertSame( [ true, true, false ], $done );
273 $done = [ false, false, false ];
275 $request->getSession()->setSecret( 'state', [
276 'maybeLink' => $reqs,
278 $req->confirmedLinkIDs
= [ 'Request1', 'Request3' ];
279 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] );
280 $this->assertEquals( AuthenticationResponse
::UI
, $res->status
);
281 $this->assertCount( 1, $res->neededRequests
);
282 $this->assertInstanceOf( ButtonAuthenticationRequest
::class, $res->neededRequests
[0] );
283 $this->assertSame( [ true, false, false ], $done );
284 $done = [ false, false, false ];
286 $res = $provider->continueLinkAttempt( $user, 'state', [ $res->neededRequests
[0] ] );
287 $this->assertEquals( AuthenticationResponse
::newPass(), $res );
288 $this->assertSame( [ false, false, false ], $done );