wiki.techinc.nl/tests/phpunit/includes/auth/ThrottlerTest.php
Brad Jorsch d245bd25ae Add AuthManager
This implements the AuthManager class and its needed interfaces and
subclasses, and integrates them into the backend portion of MediaWiki.
Integration with frontend portions of MediaWiki (e.g. ApiLogin,
Special:Login) is left for a followup.

Bug: T91699
Bug: T71589
Bug: T111299
Co-Authored-By: Gergő Tisza <gtisza@wikimedia.org>
Change-Id: If89d24838e326fe25fe867d02181eebcfbb0e196
2016-05-16 15:11:02 +00:00

246 lines
8.9 KiB
PHP

<?php
namespace MediaWiki\Auth;
use BagOStuff;
use HashBagOStuff;
use InvalidArgumentException;
use Psr\Log\AbstractLogger;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger;
/**
* @group AuthManager
* @covers MediaWiki\Auth\Throttler
*/
class ThrottlerTest extends \MediaWikiTestCase {
protected function setUp() {
global $wgDisableAuthManager;
parent::setUp();
if ( $wgDisableAuthManager ) {
$this->markTestSkipped( '$wgDisableAuthManager is set' );
}
}
public function testConstructor() {
$cache = new \HashBagOStuff();
$logger = $this->getMockBuilder( AbstractLogger::class )
->setMethods( [ 'log' ] )
->getMockForAbstractClass();
$throttler = new Throttler(
[ [ 'count' => 123, 'seconds' => 456 ] ],
[ 'type' => 'foo', 'cache' => $cache ]
);
$throttler->setLogger( $logger );
$throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
$this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
$this->assertSame( 'foo', $throttlerPriv->type );
$this->assertSame( $cache, $throttlerPriv->cache );
$this->assertSame( $logger, $throttlerPriv->logger );
$throttler = new Throttler( [ [ 'count' => 123, 'seconds' => 456 ] ] );
$throttler->setLogger( new NullLogger() );
$throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
$this->assertSame( [ [ 'count' => 123, 'seconds' => 456 ] ], $throttlerPriv->conditions );
$this->assertSame( 'custom', $throttlerPriv->type );
$this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
$this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
$this->setMwGlobals( [ 'wgPasswordAttemptThrottle' => [ [ 'count' => 321,
'seconds' => 654 ] ] ] );
$throttler = new Throttler();
$throttler->setLogger( new NullLogger() );
$throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
$this->assertSame( [ [ 'count' => 321, 'seconds' => 654 ] ], $throttlerPriv->conditions );
$this->assertSame( 'password', $throttlerPriv->type );
$this->assertInstanceOf( BagOStuff::class, $throttlerPriv->cache );
$this->assertInstanceOf( LoggerInterface::class, $throttlerPriv->logger );
try {
new Throttler( [], [ 'foo' => 1, 'bar' => 2, 'baz' => 3 ] );
$this->fail( 'Expected exception not thrown' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'unrecognized parameters: foo, bar, baz', $ex->getMessage() );
}
}
/**
* @dataProvider provideNormalizeThrottleConditions
*/
public function testNormalizeThrottleConditions( $condition, $normalized ) {
$throttler = new Throttler( $condition );
$throttler->setLogger( new NullLogger() );
$throttlerPriv = \TestingAccessWrapper::newFromObject( $throttler );
$this->assertSame( $normalized, $throttlerPriv->conditions );
}
public function provideNormalizeThrottleConditions() {
return [
[
[],
[],
],
[
[ 'count' => 1, 'seconds' => 2 ],
[ [ 'count' => 1, 'seconds' => 2 ] ],
],
[
[ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
[ [ 'count' => 1, 'seconds' => 2 ], [ 'count' => 2, 'seconds' => 3 ] ],
],
];
}
public function testNormalizeThrottleConditions2() {
$priv = \TestingAccessWrapper::newFromClass( Throttler::class );
$this->assertSame( [], $priv->normalizeThrottleConditions( null ) );
$this->assertSame( [], $priv->normalizeThrottleConditions( 'bad' ) );
}
public function testIncrease() {
$cache = new \HashBagOStuff();
$throttler = new Throttler( [
[ 'count' => 2, 'seconds' => 10, ],
[ 'count' => 4, 'seconds' => 15, 'allIPs' => true ],
], [ 'cache' => $cache ] );
$throttler->setLogger( new NullLogger() );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertSame( [ 'throttleIndex' => 0, 'count' => 2, 'wait' => 10 ], $result );
$result = $throttler->increase( 'OtherUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '2.3.4.5' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '3.4.5.6' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '3.4.5.6' );
$this->assertSame( [ 'throttleIndex' => 1, 'count' => 4, 'wait' => 15 ], $result );
}
public function testZeroCount() {
$cache = new \HashBagOStuff();
$throttler = new Throttler( [ [ 'count' => 0, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
$throttler->setLogger( new NullLogger() );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle, count=0 is ignored' );
}
public function testNamespacing() {
$cache = new \HashBagOStuff();
$throttler1 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
[ 'cache' => $cache, 'type' => 'foo' ] );
$throttler2 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
[ 'cache' => $cache, 'type' => 'foo' ] );
$throttler3 = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ],
[ 'cache' => $cache, 'type' => 'bar' ] );
$throttler1->setLogger( new NullLogger() );
$throttler2->setLogger( new NullLogger() );
$throttler3->setLogger( new NullLogger() );
$throttled = [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ];
$result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler1->increase( 'SomeUser', '1.2.3.4' );
$this->assertEquals( $throttled, $result, 'should throttle' );
$result = $throttler2->increase( 'SomeUser', '1.2.3.4' );
$this->assertEquals( $throttled, $result, 'should throttle, same namespace' );
$result = $throttler3->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle, different namespace' );
}
public function testExpiration() {
$cache = $this->getMock( HashBagOStuff::class, [ 'add' ] );
$throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
$throttler->setLogger( new NullLogger() );
$cache->expects( $this->once() )->method( 'add' )->with( $this->anything(), 1, 10 );
$throttler->increase( 'SomeUser' );
}
/**
* @expectedException \InvalidArgumentException
*/
public function testException() {
$throttler = new Throttler( [ [ 'count' => 3, 'seconds' => 10 ] ] );
$throttler->setLogger( new NullLogger() );
$throttler->increase();
}
public function testLog() {
$cache = new \HashBagOStuff();
$throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
$logger = $this->getMockBuilder( AbstractLogger::class )
->setMethods( [ 'log' ] )
->getMockForAbstractClass();
$logger->expects( $this->never() )->method( 'log' );
$throttler->setLogger( $logger );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$logger = $this->getMockBuilder( AbstractLogger::class )
->setMethods( [ 'log' ] )
->getMockForAbstractClass();
$logger->expects( $this->once() )->method( 'log' )->with( $this->anything(), $this->anything(), [
'type' => 'custom',
'index' => 0,
'ip' => '1.2.3.4',
'username' => 'SomeUser',
'count' => 1,
'expiry' => 10,
'method' => 'foo',
] );
$throttler->setLogger( $logger );
$result = $throttler->increase( 'SomeUser', '1.2.3.4', 'foo' );
$this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
}
public function testClear() {
$cache = new \HashBagOStuff();
$throttler = new Throttler( [ [ 'count' => 1, 'seconds' => 10 ] ], [ 'cache' => $cache ] );
$throttler->setLogger( new NullLogger() );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
$result = $throttler->increase( 'OtherUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'OtherUser', '1.2.3.4' );
$this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
$throttler->clear( 'SomeUser', '1.2.3.4' );
$result = $throttler->increase( 'SomeUser', '1.2.3.4' );
$this->assertFalse( $result, 'should not throttle' );
$result = $throttler->increase( 'OtherUser', '1.2.3.4' );
$this->assertSame( [ 'throttleIndex' => 0, 'count' => 1, 'wait' => 10 ], $result );
}
}