]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / tests / phpunit / includes / session / ImmutableSessionProviderWithCookieTest.php
1 <?php
2
3 namespace MediaWiki\Session;
4
5 use MediaWikiTestCase;
6 use User;
7 use Wikimedia\TestingAccessWrapper;
8
9 /**
10  * @group Session
11  * @group Database
12  * @covers MediaWiki\Session\ImmutableSessionProviderWithCookie
13  */
14 class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
15
16         private function getProvider( $name, $prefix = null ) {
17                 $config = new \HashConfig();
18                 $config->set( 'CookiePrefix', 'wgCookiePrefix' );
19
20                 $params = [
21                         'sessionCookieName' => $name,
22                         'sessionCookieOptions' => [],
23                 ];
24                 if ( $prefix !== null ) {
25                         $params['sessionCookieOptions']['prefix'] = $prefix;
26                 }
27
28                 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
29                         ->setConstructorArgs( [ $params ] )
30                         ->getMockForAbstractClass();
31                 $provider->setLogger( new \TestLogger() );
32                 $provider->setConfig( $config );
33                 $provider->setManager( new SessionManager() );
34
35                 return $provider;
36         }
37
38         public function testConstructor() {
39                 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
40                         ->getMockForAbstractClass();
41                 $priv = TestingAccessWrapper::newFromObject( $provider );
42                 $this->assertNull( $priv->sessionCookieName );
43                 $this->assertSame( [], $priv->sessionCookieOptions );
44
45                 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
46                         ->setConstructorArgs( [ [
47                                 'sessionCookieName' => 'Foo',
48                                 'sessionCookieOptions' => [ 'Bar' ],
49                         ] ] )
50                         ->getMockForAbstractClass();
51                 $priv = TestingAccessWrapper::newFromObject( $provider );
52                 $this->assertSame( 'Foo', $priv->sessionCookieName );
53                 $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions );
54
55                 try {
56                         $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
57                                 ->setConstructorArgs( [ [
58                                         'sessionCookieName' => false,
59                                 ] ] )
60                                 ->getMockForAbstractClass();
61                         $this->fail( 'Expected exception not thrown' );
62                 } catch ( \InvalidArgumentException $ex ) {
63                         $this->assertSame(
64                                 'sessionCookieName must be a string',
65                                 $ex->getMessage()
66                         );
67                 }
68
69                 try {
70                         $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
71                                 ->setConstructorArgs( [ [
72                                         'sessionCookieOptions' => 'x',
73                                 ] ] )
74                                 ->getMockForAbstractClass();
75                         $this->fail( 'Expected exception not thrown' );
76                 } catch ( \InvalidArgumentException $ex ) {
77                         $this->assertSame(
78                                 'sessionCookieOptions must be an array',
79                                 $ex->getMessage()
80                         );
81                 }
82         }
83
84         public function testBasics() {
85                 $provider = $this->getProvider( null );
86                 $this->assertFalse( $provider->persistsSessionID() );
87                 $this->assertFalse( $provider->canChangeUser() );
88
89                 $provider = $this->getProvider( 'Foo' );
90                 $this->assertTrue( $provider->persistsSessionID() );
91                 $this->assertFalse( $provider->canChangeUser() );
92
93                 $msg = $provider->whyNoSession();
94                 $this->assertInstanceOf( 'Message', $msg );
95                 $this->assertSame( 'sessionprovider-nocookies', $msg->getKey() );
96         }
97
98         public function testGetVaryCookies() {
99                 $provider = $this->getProvider( null );
100                 $this->assertSame( [], $provider->getVaryCookies() );
101
102                 $provider = $this->getProvider( 'Foo' );
103                 $this->assertSame( [ 'wgCookiePrefixFoo' ], $provider->getVaryCookies() );
104
105                 $provider = $this->getProvider( 'Foo', 'Bar' );
106                 $this->assertSame( [ 'BarFoo' ], $provider->getVaryCookies() );
107
108                 $provider = $this->getProvider( 'Foo', '' );
109                 $this->assertSame( [ 'Foo' ], $provider->getVaryCookies() );
110         }
111
112         public function testGetSessionIdFromCookie() {
113                 $this->setMwGlobals( 'wgCookiePrefix', 'wgCookiePrefix' );
114                 $request = new \FauxRequest();
115                 $request->setCookies( [
116                         '' => 'empty---------------------------',
117                         'Foo' => 'foo-----------------------------',
118                         'wgCookiePrefixFoo' => 'wgfoo---------------------------',
119                         'BarFoo' => 'foobar--------------------------',
120                         'bad' => 'bad',
121                 ], '' );
122
123                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( null ) );
124                 try {
125                         $provider->getSessionIdFromCookie( $request );
126                         $this->fail( 'Expected exception not thrown' );
127                 } catch ( \BadMethodCallException $ex ) {
128                         $this->assertSame(
129                                 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie::getSessionIdFromCookie ' .
130                                         'may not be called when $this->sessionCookieName === null',
131                                 $ex->getMessage()
132                         );
133                 }
134
135                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo' ) );
136                 $this->assertSame(
137                         'wgfoo---------------------------',
138                         $provider->getSessionIdFromCookie( $request )
139                 );
140
141                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo', 'Bar' ) );
142                 $this->assertSame(
143                         'foobar--------------------------',
144                         $provider->getSessionIdFromCookie( $request )
145                 );
146
147                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo', '' ) );
148                 $this->assertSame(
149                         'foo-----------------------------',
150                         $provider->getSessionIdFromCookie( $request )
151                 );
152
153                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'bad', '' ) );
154                 $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
155
156                 $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'none', '' ) );
157                 $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
158         }
159
160         protected function getSentRequest() {
161                 $sentResponse = $this->getMockBuilder( 'FauxResponse' )
162                         ->setMethods( [ 'headersSent', 'setCookie', 'header' ] )
163                         ->getMock();
164                 $sentResponse->expects( $this->any() )->method( 'headersSent' )
165                         ->will( $this->returnValue( true ) );
166                 $sentResponse->expects( $this->never() )->method( 'setCookie' );
167                 $sentResponse->expects( $this->never() )->method( 'header' );
168
169                 $sentRequest = $this->getMockBuilder( 'FauxRequest' )
170                         ->setMethods( [ 'response' ] )->getMock();
171                 $sentRequest->expects( $this->any() )->method( 'response' )
172                         ->will( $this->returnValue( $sentResponse ) );
173                 return $sentRequest;
174         }
175
176         /**
177          * @dataProvider providePersistSession
178          * @param bool $secure
179          * @param bool $remember
180          */
181         public function testPersistSession( $secure, $remember ) {
182                 $this->setMwGlobals( [
183                         'wgCookieExpiration' => 100,
184                         'wgSecureLogin' => false,
185                 ] );
186
187                 $provider = $this->getProvider( 'session' );
188                 $provider->setLogger( new \Psr\Log\NullLogger() );
189                 $priv = TestingAccessWrapper::newFromObject( $provider );
190                 $priv->sessionCookieOptions = [
191                         'prefix' => 'x',
192                         'path' => 'CookiePath',
193                         'domain' => 'CookieDomain',
194                         'secure' => false,
195                         'httpOnly' => true,
196                 ];
197
198                 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
199                 $user = User::newFromName( 'UTSysop' );
200                 $this->assertFalse( $user->requiresHTTPS(), 'sanity check' );
201
202                 $backend = new SessionBackend(
203                         new SessionId( $sessionId ),
204                         new SessionInfo( SessionInfo::MIN_PRIORITY, [
205                                 'provider' => $provider,
206                                 'id' => $sessionId,
207                                 'persisted' => true,
208                                 'userInfo' => UserInfo::newFromUser( $user, true ),
209                                 'idIsSafe' => true,
210                         ] ),
211                         new TestBagOStuff(),
212                         new \Psr\Log\NullLogger(),
213                         10
214                 );
215                 TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = false;
216                 $backend->setRememberUser( $remember );
217                 $backend->setForceHTTPS( $secure );
218
219                 // No cookie
220                 $priv->sessionCookieName = null;
221                 $request = new \FauxRequest();
222                 $provider->persistSession( $backend, $request );
223                 $this->assertSame( [], $request->response()->getCookies() );
224
225                 // Cookie
226                 $priv->sessionCookieName = 'session';
227                 $request = new \FauxRequest();
228                 $time = time();
229                 $provider->persistSession( $backend, $request );
230
231                 $cookie = $request->response()->getCookieData( 'xsession' );
232                 $this->assertInternalType( 'array', $cookie );
233                 if ( isset( $cookie['expire'] ) && $cookie['expire'] > 0 ) {
234                         // Round expiry so we don't randomly fail if the seconds ticked during the test.
235                         $cookie['expire'] = round( $cookie['expire'] - $time, -2 );
236                 }
237                 $this->assertEquals( [
238                         'value' => $sessionId,
239                         'expire' => null,
240                         'path' => 'CookiePath',
241                         'domain' => 'CookieDomain',
242                         'secure' => $secure,
243                         'httpOnly' => true,
244                         'raw' => false,
245                 ], $cookie );
246
247                 $cookie = $request->response()->getCookieData( 'forceHTTPS' );
248                 if ( $secure ) {
249                         $this->assertInternalType( 'array', $cookie );
250                         if ( isset( $cookie['expire'] ) && $cookie['expire'] > 0 ) {
251                                 // Round expiry so we don't randomly fail if the seconds ticked during the test.
252                                 $cookie['expire'] = round( $cookie['expire'] - $time, -2 );
253                         }
254                         $this->assertEquals( [
255                                 'value' => 'true',
256                                 'expire' => null,
257                                 'path' => 'CookiePath',
258                                 'domain' => 'CookieDomain',
259                                 'secure' => false,
260                                 'httpOnly' => true,
261                                 'raw' => false,
262                         ], $cookie );
263                 } else {
264                         $this->assertNull( $cookie );
265                 }
266
267                 // Headers sent
268                 $request = $this->getSentRequest();
269                 $provider->persistSession( $backend, $request );
270                 $this->assertSame( [], $request->response()->getCookies() );
271         }
272
273         public static function providePersistSession() {
274                 return [
275                         [ false, false ],
276                         [ false, true ],
277                         [ true, false ],
278                         [ true, true ],
279                 ];
280         }
281
282         public function testUnpersistSession() {
283                 $provider = $this->getProvider( 'session', '' );
284                 $provider->setLogger( new \Psr\Log\NullLogger() );
285                 $priv = TestingAccessWrapper::newFromObject( $provider );
286
287                 // No cookie
288                 $priv->sessionCookieName = null;
289                 $request = new \FauxRequest();
290                 $provider->unpersistSession( $request );
291                 $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );
292
293                 // Cookie
294                 $priv->sessionCookieName = 'session';
295                 $request = new \FauxRequest();
296                 $provider->unpersistSession( $request );
297                 $this->assertSame( '', $request->response()->getCookie( 'session', '' ) );
298
299                 // Headers sent
300                 $request = $this->getSentRequest();
301                 $provider->unpersistSession( $request );
302                 $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );
303         }
304
305 }