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