MediaWiki REL1_30
AuthenticationRequestTest.php
Go to the documentation of this file.
1<?php
2
3namespace MediaWiki\Auth;
4
10 public function testBasics() {
11 $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
12
13 $this->assertSame( get_class( $mock ), $mock->getUniqueId() );
14
15 $this->assertType( 'array', $mock->getMetadata() );
16
17 $ret = $mock->describeCredentials();
18 $this->assertInternalType( 'array', $ret );
19 $this->assertArrayHasKey( 'provider', $ret );
20 $this->assertInstanceOf( 'Message', $ret['provider'] );
21 $this->assertArrayHasKey( 'account', $ret );
22 $this->assertInstanceOf( 'Message', $ret['account'] );
23 }
24
26 $mb = $this->getMockBuilder( AuthenticationRequest::class )
27 ->setMethods( [ 'loadFromSubmission' ] );
28
29 $data = [ 'foo', 'bar' ];
30
31 $req1 = $mb->getMockForAbstractClass();
32 $req1->expects( $this->once() )->method( 'loadFromSubmission' )
33 ->with( $this->identicalTo( $data ) )
34 ->will( $this->returnValue( false ) );
35
36 $req2 = $mb->getMockForAbstractClass();
37 $req2->expects( $this->once() )->method( 'loadFromSubmission' )
38 ->with( $this->identicalTo( $data ) )
39 ->will( $this->returnValue( true ) );
40
41 $this->assertSame(
42 [ $req2 ],
44 );
45 }
46
47 public function testGetRequestByClass() {
48 $mb = $this->getMockBuilder(
49 AuthenticationRequest::class, 'AuthenticationRequestTest_AuthenticationRequest2'
50 );
51
52 $reqs = [
53 $this->getMockForAbstractClass(
54 AuthenticationRequest::class, [], 'AuthenticationRequestTest_AuthenticationRequest1'
55 ),
56 $mb->getMockForAbstractClass(),
57 $mb->getMockForAbstractClass(),
58 $this->getMockForAbstractClass(
59 PasswordAuthenticationRequest::class, [],
60 'AuthenticationRequestTest_PasswordAuthenticationRequest'
61 ),
62 ];
63
65 $reqs, 'AuthenticationRequestTest_AuthenticationRequest0'
66 ) );
67 $this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
68 $reqs, 'AuthenticationRequestTest_AuthenticationRequest1'
69 ) );
71 $reqs, 'AuthenticationRequestTest_AuthenticationRequest2'
72 ) );
74 $reqs, PasswordAuthenticationRequest::class
75 ) );
77 $reqs, 'ClassThatDoesNotExist'
78 ) );
79
81 $reqs, 'AuthenticationRequestTest_AuthenticationRequest0', true
82 ) );
83 $this->assertSame( $reqs[0], AuthenticationRequest::getRequestByClass(
84 $reqs, 'AuthenticationRequestTest_AuthenticationRequest1', true
85 ) );
87 $reqs, 'AuthenticationRequestTest_AuthenticationRequest2', true
88 ) );
89 $this->assertSame( $reqs[3], AuthenticationRequest::getRequestByClass(
90 $reqs, PasswordAuthenticationRequest::class, true
91 ) );
93 $reqs, 'ClassThatDoesNotExist', true
94 ) );
95 }
96
97 public function testGetUsernameFromRequests() {
98 $mb = $this->getMockBuilder( AuthenticationRequest::class );
99
100 for ( $i = 0; $i < 3; $i++ ) {
101 $req = $mb->getMockForAbstractClass();
102 $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
103 'username' => [
104 'type' => 'string',
105 ],
106 ] ) );
107 $reqs[] = $req;
108 }
109
110 $req = $mb->getMockForAbstractClass();
111 $req->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
112 $req->username = 'baz';
113 $reqs[] = $req;
114
115 $this->assertNull( AuthenticationRequest::getUsernameFromRequests( $reqs ) );
116
117 $reqs[1]->username = 'foo';
118 $this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
119
120 $reqs[0]->username = 'foo';
121 $reqs[2]->username = 'foo';
122 $this->assertSame( 'foo', AuthenticationRequest::getUsernameFromRequests( $reqs ) );
123
124 $reqs[1]->username = 'bar';
125 try {
127 $this->fail( 'Expected exception not thrown' );
128 } catch ( \UnexpectedValueException $ex ) {
129 $this->assertSame(
130 'Conflicting username fields: "bar" from ' .
131 get_class( $reqs[1] ) . '::$username vs. "foo" from ' .
132 get_class( $reqs[0] ) . '::$username',
133 $ex->getMessage()
134 );
135 }
136 }
137
138 public function testMergeFieldInfo() {
139 $msg = wfMessage( 'foo' );
140
141 $req1 = $this->createMock( AuthenticationRequest::class );
142 $req1->required = AuthenticationRequest::REQUIRED;
143 $req1->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
144 'string1' => [
145 'type' => 'string',
146 'label' => $msg,
147 'help' => $msg,
148 ],
149 'string2' => [
150 'type' => 'string',
151 'label' => $msg,
152 'help' => $msg,
153 ],
154 'optional' => [
155 'type' => 'string',
156 'label' => $msg,
157 'help' => $msg,
158 'optional' => true,
159 ],
160 'select' => [
161 'type' => 'select',
162 'options' => [ 'foo' => $msg, 'baz' => $msg ],
163 'label' => $msg,
164 'help' => $msg,
165 ],
166 ] ) );
167
168 $req2 = $this->createMock( AuthenticationRequest::class );
169 $req2->required = AuthenticationRequest::REQUIRED;
170 $req2->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
171 'string1' => [
172 'type' => 'string',
173 'label' => $msg,
174 'help' => $msg,
175 'sensitive' => true,
176 ],
177 'string3' => [
178 'type' => 'string',
179 'label' => $msg,
180 'help' => $msg,
181 ],
182 'select' => [
183 'type' => 'select',
184 'options' => [ 'bar' => $msg, 'baz' => $msg ],
185 'label' => $msg,
186 'help' => $msg,
187 ],
188 ] ) );
189
190 $req3 = $this->createMock( AuthenticationRequest::class );
191 $req3->required = AuthenticationRequest::REQUIRED;
192 $req3->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [
193 'string1' => [
194 'type' => 'checkbox',
195 'label' => $msg,
196 'help' => $msg,
197 ],
198 ] ) );
199
200 $req4 = $this->createMock( AuthenticationRequest::class );
201 $req4->required = AuthenticationRequest::REQUIRED;
202 $req4->expects( $this->any() )->method( 'getFieldInfo' )->will( $this->returnValue( [] ) );
203
204 // Basic combining
205
206 $fields = AuthenticationRequest::mergeFieldInfo( [ $req1 ] );
207 $expect = $req1->getFieldInfo();
208 foreach ( $expect as $name => &$options ) {
209 $options['optional'] = !empty( $options['optional'] );
210 $options['sensitive'] = !empty( $options['sensitive'] );
211 }
212 unset( $options );
213 $this->assertEquals( $expect, $fields );
214
215 $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req4 ] );
216 $this->assertEquals( $expect, $fields );
217
218 try {
219 AuthenticationRequest::mergeFieldInfo( [ $req1, $req3 ] );
220 $this->fail( 'Expected exception not thrown' );
221 } catch ( \UnexpectedValueException $ex ) {
222 $this->assertSame(
223 'Field type conflict for "string1", "string" vs "checkbox"',
224 $ex->getMessage()
225 );
226 }
227
228 $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
229 $expect += $req2->getFieldInfo();
230 $expect['string1']['sensitive'] = true;
231 $expect['string2']['optional'] = false;
232 $expect['string3']['optional'] = false;
233 $expect['string3']['sensitive'] = false;
234 $expect['select']['options']['bar'] = $msg;
235 $this->assertEquals( $expect, $fields );
236
237 // Combining with something not required
238
240
241 $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
242 $expect += $req2->getFieldInfo();
243 $expect['string1']['optional'] = false;
244 $expect['string1']['sensitive'] = true;
245 $expect['string3']['optional'] = false;
246 $expect['select']['optional'] = false;
247 $expect['select']['options']['bar'] = $msg;
248 $this->assertEquals( $expect, $fields );
249
251
252 $fields = AuthenticationRequest::mergeFieldInfo( [ $req1, $req2 ] );
253 $expect = $req1->getFieldInfo() + $req2->getFieldInfo();
254 foreach ( $expect as $name => &$options ) {
255 $options['sensitive'] = !empty( $options['sensitive'] );
256 }
257 $expect['string1']['optional'] = false;
258 $expect['string1']['sensitive'] = true;
259 $expect['string2']['optional'] = true;
260 $expect['string3']['optional'] = true;
261 $expect['select']['optional'] = false;
262 $expect['select']['options']['bar'] = $msg;
263 $this->assertEquals( $expect, $fields );
264 }
265
272 public function testLoadFromSubmission( $fieldInfo, $data, $expectState ) {
273 $mock = $this->getMockForAbstractClass( AuthenticationRequest::class );
274 $mock->expects( $this->any() )->method( 'getFieldInfo' )
275 ->will( $this->returnValue( $fieldInfo ) );
276
277 $ret = $mock->loadFromSubmission( $data );
278 if ( is_array( $expectState ) ) {
279 $this->assertTrue( $ret );
280 $expect = call_user_func( [ get_class( $mock ), '__set_state' ], $expectState );
281 $this->assertEquals( $expect, $mock );
282 } else {
283 $this->assertFalse( $ret );
284 }
285 }
286
287 public static function provideLoadFromSubmission() {
288 return [
289 'No fields' => [
290 [],
291 $data = [ 'foo' => 'bar' ],
292 false
293 ],
294
295 'Simple field' => [
296 [
297 'field' => [
298 'type' => 'string',
299 ],
300 ],
301 $data = [ 'field' => 'string!' ],
302 $data
303 ],
304 'Simple field, not supplied' => [
305 [
306 'field' => [
307 'type' => 'string',
308 ],
309 ],
310 [],
311 false
312 ],
313 'Simple field, empty' => [
314 [
315 'field' => [
316 'type' => 'string',
317 ],
318 ],
319 [ 'field' => '' ],
320 false
321 ],
322 'Simple field, optional, not supplied' => [
323 [
324 'field' => [
325 'type' => 'string',
326 'optional' => true,
327 ],
328 ],
329 [],
330 false
331 ],
332 'Simple field, optional, empty' => [
333 [
334 'field' => [
335 'type' => 'string',
336 'optional' => true,
337 ],
338 ],
339 $data = [ 'field' => '' ],
340 $data
341 ],
342
343 'Checkbox, checked' => [
344 [
345 'check' => [
346 'type' => 'checkbox',
347 ],
348 ],
349 [ 'check' => '' ],
350 [ 'check' => true ]
351 ],
352 'Checkbox, unchecked' => [
353 [
354 'check' => [
355 'type' => 'checkbox',
356 ],
357 ],
358 [],
359 false
360 ],
361 'Checkbox, optional, unchecked' => [
362 [
363 'check' => [
364 'type' => 'checkbox',
365 'optional' => true,
366 ],
367 ],
368 [],
369 [ 'check' => false ]
370 ],
371
372 'Button, used' => [
373 [
374 'push' => [
375 'type' => 'button',
376 ],
377 ],
378 [ 'push' => '' ],
379 [ 'push' => true ]
380 ],
381 'Button, unused' => [
382 [
383 'push' => [
384 'type' => 'button',
385 ],
386 ],
387 [],
388 false
389 ],
390 'Button, optional, unused' => [
391 [
392 'push' => [
393 'type' => 'button',
394 'optional' => true,
395 ],
396 ],
397 [],
398 [ 'push' => false ]
399 ],
400 'Button, image-style' => [
401 [
402 'push' => [
403 'type' => 'button',
404 ],
405 ],
406 [ 'push_x' => 0, 'push_y' => 0 ],
407 [ 'push' => true ]
408 ],
409
410 'Select' => [
411 [
412 'choose' => [
413 'type' => 'select',
414 'options' => [
415 'foo' => wfMessage( 'mainpage' ),
416 'bar' => wfMessage( 'mainpage' ),
417 ],
418 ],
419 ],
420 $data = [ 'choose' => 'foo' ],
421 $data
422 ],
423 'Select, invalid choice' => [
424 [
425 'choose' => [
426 'type' => 'select',
427 'options' => [
428 'foo' => wfMessage( 'mainpage' ),
429 'bar' => wfMessage( 'mainpage' ),
430 ],
431 ],
432 ],
433 $data = [ 'choose' => 'baz' ],
434 false
435 ],
436 'Multiselect (2)' => [
437 [
438 'choose' => [
439 'type' => 'multiselect',
440 'options' => [
441 'foo' => wfMessage( 'mainpage' ),
442 'bar' => wfMessage( 'mainpage' ),
443 ],
444 ],
445 ],
446 $data = [ 'choose' => [ 'foo', 'bar' ] ],
447 $data
448 ],
449 'Multiselect (1)' => [
450 [
451 'choose' => [
452 'type' => 'multiselect',
453 'options' => [
454 'foo' => wfMessage( 'mainpage' ),
455 'bar' => wfMessage( 'mainpage' ),
456 ],
457 ],
458 ],
459 $data = [ 'choose' => [ 'bar' ] ],
460 $data
461 ],
462 'Multiselect, string for some reason' => [
463 [
464 'choose' => [
465 'type' => 'multiselect',
466 'options' => [
467 'foo' => wfMessage( 'mainpage' ),
468 'bar' => wfMessage( 'mainpage' ),
469 ],
470 ],
471 ],
472 [ 'choose' => 'foo' ],
473 [ 'choose' => [ 'foo' ] ]
474 ],
475 'Multiselect, invalid choice' => [
476 [
477 'choose' => [
478 'type' => 'multiselect',
479 'options' => [
480 'foo' => wfMessage( 'mainpage' ),
481 'bar' => wfMessage( 'mainpage' ),
482 ],
483 ],
484 ],
485 [ 'choose' => [ 'foo', 'baz' ] ],
486 false
487 ],
488 'Multiselect, empty' => [
489 [
490 'choose' => [
491 'type' => 'multiselect',
492 'options' => [
493 'foo' => wfMessage( 'mainpage' ),
494 'bar' => wfMessage( 'mainpage' ),
495 ],
496 ],
497 ],
498 [ 'choose' => [] ],
499 false
500 ],
501 'Multiselect, optional, nothing submitted' => [
502 [
503 'choose' => [
504 'type' => 'multiselect',
505 'options' => [
506 'foo' => wfMessage( 'mainpage' ),
507 'bar' => wfMessage( 'mainpage' ),
508 ],
509 'optional' => true,
510 ],
511 ],
512 [],
513 [ 'choose' => [] ]
514 ],
515 ];
516 }
517}
they could even be mouse clicks or menu items whatever suits your program You should also get your if any
Definition COPYING.txt:326
assertType( $type, $actual, $message='')
Asserts the type of the provided value.
AuthManager MediaWiki\Auth\AuthenticationRequest.
testLoadFromSubmission( $fieldInfo, $data, $expectState)
provideLoadFromSubmission
static mergeFieldInfo(array $reqs)
Merge the output of multiple AuthenticationRequest::getFieldInfo() calls.
static loadRequestsFromSubmission(array $reqs, array $data)
Update a set of requests with form submit data, discarding ones that fail.
const PRIMARY_REQUIRED
Indicates that the request is required by a primary authentication provider.
const REQUIRED
Indicates that the request is required for authentication to proceed.
static getUsernameFromRequests(array $reqs)
Get the username from the set of requests.
static getRequestByClass(array $reqs, $class, $allowSubclasses=false)
Select a request by class name.
this hook is for auditing only $req
Definition hooks.txt:988
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition hooks.txt:1971
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt;div ...>$1&lt;/div>"). - flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException':Called before an exception(or PHP error) is logged. This is meant for integration with external error aggregation services
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition hooks.txt:1976
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition hooks.txt:1975
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187