Merge "Disable Cucumber scenarios that are broken in daily Jenkins jobs"
[lhc/web/wiklou.git] / tests / phpunit / includes / auth / ThrottlePreAuthenticationProviderTest.php
1 <?php
2
3 namespace MediaWiki\Auth;
4
5 /**
6 * @group AuthManager
7 * @group Database
8 * @covers MediaWiki\Auth\ThrottlePreAuthenticationProvider
9 */
10 class ThrottlePreAuthenticationProviderTest extends \MediaWikiTestCase {
11 protected function setUp() {
12 global $wgDisableAuthManager;
13
14 parent::setUp();
15 if ( $wgDisableAuthManager ) {
16 $this->markTestSkipped( '$wgDisableAuthManager is set' );
17 }
18 }
19
20 public function testConstructor() {
21 $provider = new ThrottlePreAuthenticationProvider();
22 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
23 $config = new \HashConfig( [
24 'AccountCreationThrottle' => 123,
25 'PasswordAttemptThrottle' => [ [
26 'count' => 5,
27 'seconds' => 300,
28 ] ],
29 ] );
30 $provider->setConfig( $config );
31 $this->assertSame( [
32 'accountCreationThrottle' => [ [ 'count' => 123, 'seconds' => 86400 ] ],
33 'passwordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300 ] ]
34 ], $providerPriv->throttleSettings );
35 $accountCreationThrottle = \TestingAccessWrapper::newFromObject(
36 $providerPriv->accountCreationThrottle );
37 $this->assertSame( [ [ 'count' => 123, 'seconds' => 86400 ] ],
38 $accountCreationThrottle->conditions );
39 $passwordAttemptThrottle = \TestingAccessWrapper::newFromObject(
40 $providerPriv->passwordAttemptThrottle );
41 $this->assertSame( [ [ 'count' => 5, 'seconds' => 300 ] ],
42 $passwordAttemptThrottle->conditions );
43
44 $provider = new ThrottlePreAuthenticationProvider( [
45 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
46 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
47 ] );
48 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
49 $config = new \HashConfig( [
50 'AccountCreationThrottle' => 123,
51 'PasswordAttemptThrottle' => [ [
52 'count' => 5,
53 'seconds' => 300,
54 ] ],
55 ] );
56 $provider->setConfig( $config );
57 $this->assertSame( [
58 'accountCreationThrottle' => [ [ 'count' => 43, 'seconds' => 10000 ] ],
59 'passwordAttemptThrottle' => [ [ 'count' => 11, 'seconds' => 100 ] ],
60 ], $providerPriv->throttleSettings );
61
62 $cache = new \HashBagOStuff();
63 $provider = new ThrottlePreAuthenticationProvider( [ 'cache' => $cache ] );
64 $providerPriv = \TestingAccessWrapper::newFromObject( $provider );
65 $provider->setConfig( new \HashConfig( [
66 'AccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 1 ] ],
67 'PasswordAttemptThrottle' => [ [ 'count' => 1, 'seconds' => 1 ] ],
68 ] ) );
69 $accountCreationThrottle = \TestingAccessWrapper::newFromObject(
70 $providerPriv->accountCreationThrottle );
71 $this->assertSame( $cache, $accountCreationThrottle->cache );
72 $passwordAttemptThrottle = \TestingAccessWrapper::newFromObject(
73 $providerPriv->passwordAttemptThrottle );
74 $this->assertSame( $cache, $passwordAttemptThrottle->cache );
75 }
76
77 public function testDisabled() {
78 $provider = new ThrottlePreAuthenticationProvider( [
79 'accountCreationThrottle' => [],
80 'passwordAttemptThrottle' => [],
81 'cache' => new \HashBagOStuff(),
82 ] );
83 $provider->setLogger( new \Psr\Log\NullLogger() );
84 $provider->setConfig( new \HashConfig( [
85 'AccountCreationThrottle' => null,
86 'PasswordAttemptThrottle' => null,
87 ] ) );
88 $provider->setManager( AuthManager::singleton() );
89
90 $this->assertEquals(
91 \StatusValue::newGood(),
92 $provider->testForAccountCreation(
93 \User::newFromName( 'Created' ),
94 \User::newFromName( 'Creator' ),
95 []
96 )
97 );
98 $this->assertEquals(
99 \StatusValue::newGood(),
100 $provider->testForAuthentication( [] )
101 );
102 }
103
104 /**
105 * @dataProvider provideTestForAccountCreation
106 * @param string $creatorname
107 * @param bool $succeed
108 * @param bool $hook
109 */
110 public function testTestForAccountCreation( $creatorname, $succeed, $hook ) {
111 $provider = new ThrottlePreAuthenticationProvider( [
112 'accountCreationThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
113 'cache' => new \HashBagOStuff(),
114 ] );
115 $provider->setLogger( new \Psr\Log\NullLogger() );
116 $provider->setConfig( new \HashConfig( [
117 'AccountCreationThrottle' => null,
118 'PasswordAttemptThrottle' => null,
119 ] ) );
120 $provider->setManager( AuthManager::singleton() );
121
122 $user = \User::newFromName( 'RandomUser' );
123 $creator = \User::newFromName( $creatorname );
124 if ( $hook ) {
125 $mock = $this->getMock( 'stdClass', [ 'onExemptFromAccountCreationThrottle' ] );
126 $mock->expects( $this->any() )->method( 'onExemptFromAccountCreationThrottle' )
127 ->will( $this->returnValue( false ) );
128 $this->mergeMwGlobalArrayValue( 'wgHooks', [
129 'ExemptFromAccountCreationThrottle' => [ $mock ],
130 ] );
131 }
132
133 $this->assertEquals(
134 \StatusValue::newGood(),
135 $provider->testForAccountCreation( $user, $creator, [] ),
136 'attempt #1'
137 );
138 $this->assertEquals(
139 \StatusValue::newGood(),
140 $provider->testForAccountCreation( $user, $creator, [] ),
141 'attempt #2'
142 );
143 $this->assertEquals(
144 $succeed ? \StatusValue::newGood() : \StatusValue::newFatal( 'acct_creation_throttle_hit', 2 ),
145 $provider->testForAccountCreation( $user, $creator, [] ),
146 'attempt #3'
147 );
148 }
149
150 public static function provideTestForAccountCreation() {
151 return [
152 'Normal user' => [ 'NormalUser', false, false ],
153 'Sysop' => [ 'UTSysop', true, false ],
154 'Normal user with hook' => [ 'NormalUser', true, true ],
155 ];
156 }
157
158 public function testTestForAuthentication() {
159 $provider = new ThrottlePreAuthenticationProvider( [
160 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
161 'cache' => new \HashBagOStuff(),
162 ] );
163 $provider->setLogger( new \Psr\Log\NullLogger() );
164 $provider->setConfig( new \HashConfig( [
165 'AccountCreationThrottle' => null,
166 'PasswordAttemptThrottle' => null,
167 ] ) );
168 $provider->setManager( AuthManager::singleton() );
169
170 $req = new UsernameAuthenticationRequest;
171 $req->username = 'SomeUser';
172 for ( $i = 1; $i <= 3; $i++ ) {
173 $status = $provider->testForAuthentication( [ $req ] );
174 $this->assertEquals( $i < 3, $status->isGood(), "attempt #$i" );
175 }
176 $this->assertCount( 1, $status->getErrors() );
177 $msg = new \Message( $status->getErrors()[0]['message'], $status->getErrors()[0]['params'] );
178 $this->assertEquals( 'login-throttled', $msg->getKey() );
179
180 $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
181 AuthenticationResponse::newFail( wfMessage( 'foo' ) ) );
182 $this->assertFalse( $provider->testForAuthentication( [ $req ] )->isGood(), 'after FAIL' );
183
184 $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
185 AuthenticationResponse::newPass() );
186 $this->assertTrue( $provider->testForAuthentication( [ $req ] )->isGood(), 'after PASS' );
187
188 $req1 = new UsernameAuthenticationRequest;
189 $req1->username = 'foo';
190 $req2 = new UsernameAuthenticationRequest;
191 $req2->username = 'bar';
192 $this->assertTrue( $provider->testForAuthentication( [ $req1, $req2 ] )->isGood() );
193
194 $req = new UsernameAuthenticationRequest;
195 $req->username = 'Some user';
196 $provider->testForAuthentication( [ $req ] );
197 $req->username = 'Some_user';
198 $provider->testForAuthentication( [ $req ] );
199 $req->username = 'some user';
200 $status = $provider->testForAuthentication( [ $req ] );
201 $this->assertFalse( $status->isGood(), 'denormalized usernames are normalized' );
202 }
203
204 public function testPostAuthentication() {
205 $provider = new ThrottlePreAuthenticationProvider( [
206 'passwordAttemptThrottle' => [],
207 'cache' => new \HashBagOStuff(),
208 ] );
209 $provider->setLogger( new \TestLogger );
210 $provider->setConfig( new \HashConfig( [
211 'AccountCreationThrottle' => null,
212 'PasswordAttemptThrottle' => null,
213 ] ) );
214 $provider->setManager( AuthManager::singleton() );
215 $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
216 AuthenticationResponse::newPass() );
217
218 $provider = new ThrottlePreAuthenticationProvider( [
219 'passwordAttemptThrottle' => [ [ 'count' => 2, 'seconds' => 86400 ] ],
220 'cache' => new \HashBagOStuff(),
221 ] );
222 $logger = new \TestLogger( true );
223 $provider->setLogger( $logger );
224 $provider->setConfig( new \HashConfig( [
225 'AccountCreationThrottle' => null,
226 'PasswordAttemptThrottle' => null,
227 ] ) );
228 $provider->setManager( AuthManager::singleton() );
229 $provider->postAuthentication( \User::newFromName( 'SomeUser' ),
230 AuthenticationResponse::newPass() );
231 $this->assertSame( [
232 [ \Psr\Log\LogLevel::ERROR, 'throttler data not found for {user}' ],
233 ], $logger->getBuffer() );
234 }
235 }