3 namespace MediaWiki\Tests\Auth
;
5 use MediaWiki\Auth\AuthenticationResponse
;
6 use MediaWiki\Auth\ThrottlePreAuthenticationProvider
;
7 use MediaWiki\Auth\UsernameAuthenticationRequest
;
8 use MediaWiki\Config\HashConfig
;
9 use MediaWiki\MainConfigNames
;
10 use MediaWiki\Tests\Unit\Auth\AuthenticationProviderTestTrait
;
11 use MediaWiki\User\User
;
12 use MediaWikiIntegrationTestCase
;
17 use Wikimedia\ObjectCache\HashBagOStuff
;
18 use Wikimedia\TestingAccessWrapper
;
23 * @covers \MediaWiki\Auth\ThrottlePreAuthenticationProvider
25 class ThrottlePreAuthenticationProviderTest
extends MediaWikiIntegrationTestCase
{
26 use AuthenticationProviderTestTrait
;
28 public function testConstructor() {
29 $provider = new ThrottlePreAuthenticationProvider();
30 $providerPriv = TestingAccessWrapper
::newFromObject( $provider );
31 $config = new HashConfig( [
32 MainConfigNames
::AccountCreationThrottle
=> [ [
36 MainConfigNames
::PasswordAttemptThrottle
=> [ [
41 $this->initProvider( $provider, $config );
43 'accountCreationThrottle' => [ [ 'count' => 123, 'seconds' => 86400 ] ],
44 'passwordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300 ] ]
45 ], $providerPriv->throttleSettings
);
46 $accountCreationThrottle = TestingAccessWrapper
::newFromObject(
47 $providerPriv->accountCreationThrottle
);
48 $this->assertSame( [ [ 'count' => 123, 'seconds' => 86400 ] ],
49 $accountCreationThrottle->conditions
);
50 $passwordAttemptThrottle = TestingAccessWrapper
::newFromObject(
51 $providerPriv->passwordAttemptThrottle
);
52 $this->assertSame( [ [ 'count' => 5, 'seconds' => 300 ] ],
53 $passwordAttemptThrottle->conditions
);
55 $provider = new ThrottlePreAuthenticationProvider( [
56 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
57 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
59 $providerPriv = TestingAccessWrapper
::newFromObject( $provider );
60 $config = new HashConfig( [
61 MainConfigNames
::AccountCreationThrottle
=> [ [
65 MainConfigNames
::PasswordAttemptThrottle
=> [ [
70 $this->initProvider( $provider, $config );
72 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
73 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
74 ], $providerPriv->throttleSettings
);
76 $cache = new HashBagOStuff();
77 $provider = new ThrottlePreAuthenticationProvider( [ 'cache' => $cache ] );
78 $providerPriv = TestingAccessWrapper
::newFromObject( $provider );
79 $config = new HashConfig( [
80 MainConfigNames
::AccountCreationThrottle
=> [ [ 'count' => 1, 'seconds' => 1 ] ],
81 MainConfigNames
::PasswordAttemptThrottle
=> [ [ 'count' => 1, 'seconds' => 1 ] ],
83 $this->initProvider( $provider, $config );
84 $accountCreationThrottle = TestingAccessWrapper
::newFromObject(
85 $providerPriv->accountCreationThrottle
);
86 $this->assertSame( $cache, $accountCreationThrottle->cache
);
87 $passwordAttemptThrottle = TestingAccessWrapper
::newFromObject(
88 $providerPriv->passwordAttemptThrottle
);
89 $this->assertSame( $cache, $passwordAttemptThrottle->cache
);
92 public function testDisabled() {
93 $provider = new ThrottlePreAuthenticationProvider( [
94 'accountCreationThrottle' => [],
95 'passwordAttemptThrottle' => [],
96 'cache' => new HashBagOStuff(),
101 MainConfigNames
::AccountCreationThrottle
=> null,
102 MainConfigNames
::PasswordAttemptThrottle
=> null,
105 $this->getServiceContainer()->getAuthManager()
109 StatusValue
::newGood(),
110 $provider->testForAccountCreation(
111 User
::newFromName( 'Created' ),
112 User
::newFromName( 'Creator' ),
117 StatusValue
::newGood(),
118 $provider->testForAuthentication( [] )
123 * @dataProvider provideTestForAccountCreation
124 * @param bool $creatorIsSysop
125 * @param bool $succeed
128 public function testTestForAccountCreation( bool $creatorIsSysop, $succeed, $hook ) {
130 $mock = $this->getMockBuilder( stdClass
::class )
131 ->addMethods( [ 'onExemptFromAccountCreationThrottle' ] )
133 $mock->method( 'onExemptFromAccountCreationThrottle' )
134 ->willReturn( false );
135 $this->setTemporaryHook( 'ExemptFromAccountCreationThrottle', $mock );
138 $provider = new ThrottlePreAuthenticationProvider( [
139 'accountCreationThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
140 'cache' => new HashBagOStuff(),
145 MainConfigNames
::AccountCreationThrottle
=> null,
146 MainConfigNames
::PasswordAttemptThrottle
=> null,
149 $this->getServiceContainer()->getAuthManager(),
150 $this->getServiceContainer()->getHookContainer()
153 $user = User
::newFromName( 'RandomUser' );
154 $creator = $creatorIsSysop ?
$this->getTestSysop()->getUser() : $this->getTestUser()->getUser();
158 $provider->testForAccountCreation( $user, $creator, [] )->isOK(),
163 $provider->testForAccountCreation( $user, $creator, [] )->isOK(),
168 $provider->testForAccountCreation( $user, $creator, [] )->isOK(),
173 public static function provideTestForAccountCreation() {
175 'Normal user' => [ false, false, false ],
176 'Sysop' => [ true, true, false ],
177 'Normal user with hook' => [ false, true, true ],
181 public function testTestForAuthentication() {
182 $provider = new ThrottlePreAuthenticationProvider( [
183 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
184 'cache' => new HashBagOStuff(),
189 MainConfigNames
::AccountCreationThrottle
=> null,
190 MainConfigNames
::PasswordAttemptThrottle
=> null,
193 $this->getServiceContainer()->getAuthManager()
196 $req = new UsernameAuthenticationRequest
;
197 $req->username
= 'SomeUser';
198 for ( $i = 1; $i <= 3; $i++
) {
199 $status = $provider->testForAuthentication( [ $req ] );
200 $this->assertEquals( $i < 3, $status->isGood(), "attempt #$i" );
202 $this->assertStatusError( 'login-throttled', $status );
204 $provider->postAuthentication( User
::newFromName( 'SomeUser' ),
205 AuthenticationResponse
::newFail( wfMessage( 'foo' ) ) );
206 $this->assertStatusNotOk( $provider->testForAuthentication( [ $req ] ), 'after FAIL' );
208 $provider->postAuthentication( User
::newFromName( 'SomeUser' ),
209 AuthenticationResponse
::newPass() );
210 $this->assertStatusGood( $provider->testForAuthentication( [ $req ] ), 'after PASS' );
212 $req1 = new UsernameAuthenticationRequest
;
213 $req1->username
= 'foo';
214 $req2 = new UsernameAuthenticationRequest
;
215 $req2->username
= 'bar';
216 $this->assertStatusGood( $provider->testForAuthentication( [ $req1, $req2 ] ) );
218 $req = new UsernameAuthenticationRequest
;
219 $req->username
= 'Some user';
220 $provider->testForAuthentication( [ $req ] );
221 $req->username
= 'Some_user';
222 $provider->testForAuthentication( [ $req ] );
223 $req->username
= 'some user';
224 $status = $provider->testForAuthentication( [ $req ] );
225 $this->assertStatusNotOk( $status, 'denormalized usernames are normalized' );
228 public function testPostAuthentication() {
229 $provider = new ThrottlePreAuthenticationProvider( [
230 'passwordAttemptThrottle' => [],
231 'cache' => new HashBagOStuff(),
236 MainConfigNames
::AccountCreationThrottle
=> null,
237 MainConfigNames
::PasswordAttemptThrottle
=> null,
240 $this->getServiceContainer()->getAuthManager()
242 $provider->postAuthentication( User
::newFromName( 'SomeUser' ),
243 AuthenticationResponse
::newPass() );
245 $provider = new ThrottlePreAuthenticationProvider( [
246 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
247 'cache' => new HashBagOStuff(),
249 $logger = new TestLogger( true );
253 MainConfigNames
::AccountCreationThrottle
=> null,
254 MainConfigNames
::PasswordAttemptThrottle
=> null,
257 $this->getServiceContainer()->getAuthManager()
259 $provider->postAuthentication( User
::newFromName( 'SomeUser' ),
260 AuthenticationResponse
::newPass() );
262 [ LogLevel
::INFO
, 'throttler data not found for {user}' ],
263 ], $logger->getBuffer() );