Merge "API: Remove deprecated response values from action=login"
[lhc/web/wiklou.git] / tests / phpunit / includes / auth / ConfirmLinkSecondaryAuthenticationProviderTest.php
1 <?php
2
3 namespace MediaWiki\Auth;
4
5 /**
6 * @group AuthManager
7 * @covers MediaWiki\Auth\ConfirmLinkSecondaryAuthenticationProvider
8 */
9 class ConfirmLinkSecondaryAuthenticationProviderTest extends \MediaWikiTestCase {
10 /**
11 * @dataProvider provideGetAuthenticationRequests
12 * @param string $action
13 * @param array $response
14 */
15 public function testGetAuthenticationRequests( $action, $response ) {
16 $provider = new ConfirmLinkSecondaryAuthenticationProvider();
17
18 $this->assertEquals( $response, $provider->getAuthenticationRequests( $action, [] ) );
19 }
20
21 public static function provideGetAuthenticationRequests() {
22 return [
23 [ AuthManager::ACTION_LOGIN, [] ],
24 [ AuthManager::ACTION_CREATE, [] ],
25 [ AuthManager::ACTION_LINK, [] ],
26 [ AuthManager::ACTION_CHANGE, [] ],
27 [ AuthManager::ACTION_REMOVE, [] ],
28 ];
29 }
30
31 public function testBeginSecondaryAuthentication() {
32 $user = \User::newFromName( 'UTSysop' );
33 $obj = new \stdClass;
34
35 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
36 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
37 ->getMock();
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' );
42
43 $this->assertSame( $obj, $mock->beginSecondaryAuthentication( $user, [] ) );
44 }
45
46 public function testContinueSecondaryAuthentication() {
47 $user = \User::newFromName( 'UTSysop' );
48 $obj = new \stdClass;
49 $reqs = [ new \stdClass ];
50
51 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
52 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
53 ->getMock();
54 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
55 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
56 ->with(
57 $this->identicalTo( $user ),
58 $this->identicalTo( 'AuthManager::authnState' ),
59 $this->identicalTo( $reqs )
60 )
61 ->will( $this->returnValue( $obj ) );
62
63 $this->assertSame( $obj, $mock->continueSecondaryAuthentication( $user, $reqs ) );
64 }
65
66 public function testBeginSecondaryAccountCreation() {
67 $user = \User::newFromName( 'UTSysop' );
68 $obj = new \stdClass;
69
70 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
71 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
72 ->getMock();
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' );
77
78 $this->assertSame( $obj, $mock->beginSecondaryAccountCreation( $user, $user, [] ) );
79 }
80
81 public function testContinueSecondaryAccountCreation() {
82 $user = \User::newFromName( 'UTSysop' );
83 $obj = new \stdClass;
84 $reqs = [ new \stdClass ];
85
86 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
87 ->setMethods( [ 'beginLinkAttempt', 'continueLinkAttempt' ] )
88 ->getMock();
89 $mock->expects( $this->never() )->method( 'beginLinkAttempt' );
90 $mock->expects( $this->once() )->method( 'continueLinkAttempt' )
91 ->with(
92 $this->identicalTo( $user ),
93 $this->identicalTo( 'AuthManager::accountCreationState' ),
94 $this->identicalTo( $reqs )
95 )
96 ->will( $this->returnValue( $obj ) );
97
98 $this->assertSame( $obj, $mock->continueSecondaryAccountCreation( $user, $user, $reqs ) );
99 }
100
101 /**
102 * Get requests for testing
103 * @return AuthenticationRequest[]
104 */
105 private function getLinkRequests() {
106 $reqs = [];
107
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" ) );
114 $req->id = $i - 1;
115 $reqs[$req->getUniqueId()] = $req;
116 }
117
118 return $reqs;
119 }
120
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" ) );
127
128 $user = \User::newFromName( 'UTSysop' );
129 $provider = \TestingAccessWrapper::newFromObject(
130 new ConfirmLinkSecondaryAuthenticationProvider
131 );
132 $request = new \FauxRequest();
133 $manager = $this->getMockBuilder( AuthManager::class )
134 ->setMethods( [ 'allowsAuthenticationDataChange' ] )
135 ->setConstructorArgs( [ $request, \RequestContext::getMain()->getConfig() ] )
136 ->getMock();
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' );
142 } ) );
143 $provider->setManager( $manager );
144
145 $this->assertEquals(
146 AuthenticationResponse::newAbstain(),
147 $provider->beginLinkAttempt( $user, 'state' )
148 );
149
150 $request->getSession()->setSecret( 'state', [
151 'maybeLink' => [],
152 ] );
153 $this->assertEquals(
154 AuthenticationResponse::newAbstain(),
155 $provider->beginLinkAttempt( $user, 'state' )
156 );
157
158 $reqs = $this->getLinkRequests();
159 $request->getSession()->setSecret( 'state', [
160 'maybeLink' => $reqs + [ 'BadReq' => $badReq ]
161 ] );
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();
173 }
174 $this->assertEquals( $expectReqs, \TestingAccessWrapper::newFromObject( $req )->linkRequests );
175 }
176
177 public function testContinueLinkAttempt() {
178 $user = \User::newFromName( 'UTSysop' );
179 $obj = new \stdClass;
180 $reqs = $this->getLinkRequests();
181
182 $done = [ false, false, false ];
183
184 // First, test the pass-through for not containing the ConfirmLinkAuthenticationRequest
185 $mock = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
186 ->setMethods( [ 'beginLinkAttempt' ] )
187 ->getMock();
188 $mock->expects( $this->once() )->method( 'beginLinkAttempt' )
189 ->with( $this->identicalTo( $user ), $this->identicalTo( 'state' ) )
190 ->will( $this->returnValue( $obj ) );
191 $this->assertSame(
192 $obj,
193 \TestingAccessWrapper::newFromObject( $mock )->continueLinkAttempt( $user, 'state', $reqs )
194 );
195
196 // Now test the actual functioning
197 $provider = $this->getMockBuilder( ConfirmLinkSecondaryAuthenticationProvider::class )
198 ->setMethods( [
199 'beginLinkAttempt', 'providerAllowsAuthenticationDataChange',
200 'providerChangeAuthenticationData'
201 ] )
202 ->getMock();
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();
208 } ) );
209 $provider->expects( $this->any() )->method( 'providerChangeAuthenticationData' )
210 ->will( $this->returnCallback( function ( $req ) use ( &$done ) {
211 $done[$req->id] = true;
212 } ) );
213 $config = new \HashConfig( [
214 'AuthManagerConfig' => [
215 'preauth' => [],
216 'primaryauth' => [],
217 'secondaryauth' => [
218 [ 'factory' => function () use ( $provider ) {
219 return $provider;
220 } ],
221 ],
222 ],
223 ] );
224 $request = new \FauxRequest();
225 $manager = new AuthManager( $request, $config );
226 $provider->setManager( $manager );
227 $provider = \TestingAccessWrapper::newFromObject( $provider );
228
229 $req = new ConfirmLinkAuthenticationRequest( $reqs );
230
231 $this->assertEquals(
232 AuthenticationResponse::newAbstain(),
233 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
234 );
235
236 $request->getSession()->setSecret( 'state', [
237 'maybeLink' => [],
238 ] );
239 $this->assertEquals(
240 AuthenticationResponse::newAbstain(),
241 $provider->continueLinkAttempt( $user, 'state', [ $req ] )
242 );
243
244 $request->getSession()->setSecret( 'state', [
245 'maybeLink' => $reqs
246 ] );
247 $this->assertEquals(
248 AuthenticationResponse::newPass(),
249 $res = $provider->continueLinkAttempt( $user, 'state', [ $req ] )
250 );
251 $this->assertSame( [ false, false, false ], $done );
252
253 $request->getSession()->setSecret( 'state', [
254 'maybeLink' => [ $reqs['Request2'] ],
255 ] );
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 ];
261
262 $request->getSession()->setSecret( 'state', [
263 'maybeLink' => $reqs,
264 ] );
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 ];
270
271 $request->getSession()->setSecret( 'state', [
272 'maybeLink' => $reqs,
273 ] );
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 ];
281
282 $res = $provider->continueLinkAttempt( $user, 'state', [ $res->neededRequests[0] ] );
283 $this->assertEquals( AuthenticationResponse::newPass(), $res );
284 $this->assertSame( [ false, false, false ], $done );
285 }
286
287 }