3 namespace MediaWiki\Session
;
7 use Wikimedia\TestingAccessWrapper
;
12 * @covers MediaWiki\Session\ImmutableSessionProviderWithCookie
14 class ImmutableSessionProviderWithCookieTest
extends MediaWikiTestCase
{
16 private function getProvider( $name, $prefix = null ) {
17 $config = new \
HashConfig();
18 $config->set( 'CookiePrefix', 'wgCookiePrefix' );
21 'sessionCookieName' => $name,
22 'sessionCookieOptions' => [],
24 if ( $prefix !== null ) {
25 $params['sessionCookieOptions']['prefix'] = $prefix;
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() );
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
);
45 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie
::class )
46 ->setConstructorArgs( [ [
47 'sessionCookieName' => 'Foo',
48 'sessionCookieOptions' => [ 'Bar' ],
50 ->getMockForAbstractClass();
51 $priv = TestingAccessWrapper
::newFromObject( $provider );
52 $this->assertSame( 'Foo', $priv->sessionCookieName
);
53 $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions
);
56 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie
::class )
57 ->setConstructorArgs( [ [
58 'sessionCookieName' => false,
60 ->getMockForAbstractClass();
61 $this->fail( 'Expected exception not thrown' );
62 } catch ( \InvalidArgumentException
$ex ) {
64 'sessionCookieName must be a string',
70 $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie
::class )
71 ->setConstructorArgs( [ [
72 'sessionCookieOptions' => 'x',
74 ->getMockForAbstractClass();
75 $this->fail( 'Expected exception not thrown' );
76 } catch ( \InvalidArgumentException
$ex ) {
78 'sessionCookieOptions must be an array',
84 public function testBasics() {
85 $provider = $this->getProvider( null );
86 $this->assertFalse( $provider->persistsSessionID() );
87 $this->assertFalse( $provider->canChangeUser() );
89 $provider = $this->getProvider( 'Foo' );
90 $this->assertTrue( $provider->persistsSessionID() );
91 $this->assertFalse( $provider->canChangeUser() );
93 $msg = $provider->whyNoSession();
94 $this->assertInstanceOf( 'Message', $msg );
95 $this->assertSame( 'sessionprovider-nocookies', $msg->getKey() );
98 public function testGetVaryCookies() {
99 $provider = $this->getProvider( null );
100 $this->assertSame( [], $provider->getVaryCookies() );
102 $provider = $this->getProvider( 'Foo' );
103 $this->assertSame( [ 'wgCookiePrefixFoo' ], $provider->getVaryCookies() );
105 $provider = $this->getProvider( 'Foo', 'Bar' );
106 $this->assertSame( [ 'BarFoo' ], $provider->getVaryCookies() );
108 $provider = $this->getProvider( 'Foo', '' );
109 $this->assertSame( [ 'Foo' ], $provider->getVaryCookies() );
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--------------------------',
123 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( null ) );
125 $provider->getSessionIdFromCookie( $request );
126 $this->fail( 'Expected exception not thrown' );
127 } catch ( \BadMethodCallException
$ex ) {
129 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie::getSessionIdFromCookie ' .
130 'may not be called when $this->sessionCookieName === null',
135 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( 'Foo' ) );
137 'wgfoo---------------------------',
138 $provider->getSessionIdFromCookie( $request )
141 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( 'Foo', 'Bar' ) );
143 'foobar--------------------------',
144 $provider->getSessionIdFromCookie( $request )
147 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( 'Foo', '' ) );
149 'foo-----------------------------',
150 $provider->getSessionIdFromCookie( $request )
153 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( 'bad', '' ) );
154 $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
156 $provider = TestingAccessWrapper
::newFromObject( $this->getProvider( 'none', '' ) );
157 $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
160 protected function getSentRequest() {
161 $sentResponse = $this->getMockBuilder( 'FauxResponse' )
162 ->setMethods( [ 'headersSent', 'setCookie', 'header' ] )
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' );
169 $sentRequest = $this->getMockBuilder( 'FauxRequest' )
170 ->setMethods( [ 'response' ] )->getMock();
171 $sentRequest->expects( $this->any() )->method( 'response' )
172 ->will( $this->returnValue( $sentResponse ) );
177 * @dataProvider providePersistSession
178 * @param bool $secure
179 * @param bool $remember
181 public function testPersistSession( $secure, $remember ) {
182 $this->setMwGlobals( [
183 'wgCookieExpiration' => 100,
184 'wgSecureLogin' => false,
187 $provider = $this->getProvider( 'session' );
188 $provider->setLogger( new \Psr\Log\
NullLogger() );
189 $priv = TestingAccessWrapper
::newFromObject( $provider );
190 $priv->sessionCookieOptions
= [
192 'path' => 'CookiePath',
193 'domain' => 'CookieDomain',
198 $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
199 $user = User
::newFromName( 'UTSysop' );
200 $this->assertFalse( $user->requiresHTTPS(), 'sanity check' );
202 $backend = new SessionBackend(
203 new SessionId( $sessionId ),
204 new SessionInfo( SessionInfo
::MIN_PRIORITY
, [
205 'provider' => $provider,
208 'userInfo' => UserInfo
::newFromUser( $user, true ),
212 new \Psr\Log\
NullLogger(),
215 TestingAccessWrapper
::newFromObject( $backend )->usePhpSessionHandling
= false;
216 $backend->setRememberUser( $remember );
217 $backend->setForceHTTPS( $secure );
220 $priv->sessionCookieName
= null;
221 $request = new \
FauxRequest();
222 $provider->persistSession( $backend, $request );
223 $this->assertSame( [], $request->response()->getCookies() );
226 $priv->sessionCookieName
= 'session';
227 $request = new \
FauxRequest();
229 $provider->persistSession( $backend, $request );
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 );
237 $this->assertEquals( [
238 'value' => $sessionId,
240 'path' => 'CookiePath',
241 'domain' => 'CookieDomain',
247 $cookie = $request->response()->getCookieData( 'forceHTTPS' );
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 );
254 $this->assertEquals( [
257 'path' => 'CookiePath',
258 'domain' => 'CookieDomain',
264 $this->assertNull( $cookie );
268 $request = $this->getSentRequest();
269 $provider->persistSession( $backend, $request );
270 $this->assertSame( [], $request->response()->getCookies() );
273 public static function providePersistSession() {
282 public function testUnpersistSession() {
283 $provider = $this->getProvider( 'session', '' );
284 $provider->setLogger( new \Psr\Log\
NullLogger() );
285 $priv = TestingAccessWrapper
::newFromObject( $provider );
288 $priv->sessionCookieName
= null;
289 $request = new \
FauxRequest();
290 $provider->unpersistSession( $request );
291 $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );
294 $priv->sessionCookieName
= 'session';
295 $request = new \
FauxRequest();
296 $provider->unpersistSession( $request );
297 $this->assertSame( '', $request->response()->getCookie( 'session', '' ) );
300 $request = $this->getSentRequest();
301 $provider->unpersistSession( $request );
302 $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );