summaryrefslogtreecommitdiff
path: root/www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php')
-rw-r--r--www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php305
1 files changed, 305 insertions, 0 deletions
diff --git a/www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php b/www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php
new file mode 100644
index 00000000..6dd32fcd
--- /dev/null
+++ b/www/wiki/tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php
@@ -0,0 +1,305 @@
+<?php
+
+namespace MediaWiki\Session;
+
+use MediaWikiTestCase;
+use User;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @group Session
+ * @group Database
+ * @covers MediaWiki\Session\ImmutableSessionProviderWithCookie
+ */
+class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
+
+ private function getProvider( $name, $prefix = null ) {
+ $config = new \HashConfig();
+ $config->set( 'CookiePrefix', 'wgCookiePrefix' );
+
+ $params = [
+ 'sessionCookieName' => $name,
+ 'sessionCookieOptions' => [],
+ ];
+ if ( $prefix !== null ) {
+ $params['sessionCookieOptions']['prefix'] = $prefix;
+ }
+
+ $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
+ ->setConstructorArgs( [ $params ] )
+ ->getMockForAbstractClass();
+ $provider->setLogger( new \TestLogger() );
+ $provider->setConfig( $config );
+ $provider->setManager( new SessionManager() );
+
+ return $provider;
+ }
+
+ public function testConstructor() {
+ $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
+ ->getMockForAbstractClass();
+ $priv = TestingAccessWrapper::newFromObject( $provider );
+ $this->assertNull( $priv->sessionCookieName );
+ $this->assertSame( [], $priv->sessionCookieOptions );
+
+ $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
+ ->setConstructorArgs( [ [
+ 'sessionCookieName' => 'Foo',
+ 'sessionCookieOptions' => [ 'Bar' ],
+ ] ] )
+ ->getMockForAbstractClass();
+ $priv = TestingAccessWrapper::newFromObject( $provider );
+ $this->assertSame( 'Foo', $priv->sessionCookieName );
+ $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions );
+
+ try {
+ $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
+ ->setConstructorArgs( [ [
+ 'sessionCookieName' => false,
+ ] ] )
+ ->getMockForAbstractClass();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'sessionCookieName must be a string',
+ $ex->getMessage()
+ );
+ }
+
+ try {
+ $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
+ ->setConstructorArgs( [ [
+ 'sessionCookieOptions' => 'x',
+ ] ] )
+ ->getMockForAbstractClass();
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \InvalidArgumentException $ex ) {
+ $this->assertSame(
+ 'sessionCookieOptions must be an array',
+ $ex->getMessage()
+ );
+ }
+ }
+
+ public function testBasics() {
+ $provider = $this->getProvider( null );
+ $this->assertFalse( $provider->persistsSessionID() );
+ $this->assertFalse( $provider->canChangeUser() );
+
+ $provider = $this->getProvider( 'Foo' );
+ $this->assertTrue( $provider->persistsSessionID() );
+ $this->assertFalse( $provider->canChangeUser() );
+
+ $msg = $provider->whyNoSession();
+ $this->assertInstanceOf( \Message::class, $msg );
+ $this->assertSame( 'sessionprovider-nocookies', $msg->getKey() );
+ }
+
+ public function testGetVaryCookies() {
+ $provider = $this->getProvider( null );
+ $this->assertSame( [], $provider->getVaryCookies() );
+
+ $provider = $this->getProvider( 'Foo' );
+ $this->assertSame( [ 'wgCookiePrefixFoo' ], $provider->getVaryCookies() );
+
+ $provider = $this->getProvider( 'Foo', 'Bar' );
+ $this->assertSame( [ 'BarFoo' ], $provider->getVaryCookies() );
+
+ $provider = $this->getProvider( 'Foo', '' );
+ $this->assertSame( [ 'Foo' ], $provider->getVaryCookies() );
+ }
+
+ public function testGetSessionIdFromCookie() {
+ $this->setMwGlobals( 'wgCookiePrefix', 'wgCookiePrefix' );
+ $request = new \FauxRequest();
+ $request->setCookies( [
+ '' => 'empty---------------------------',
+ 'Foo' => 'foo-----------------------------',
+ 'wgCookiePrefixFoo' => 'wgfoo---------------------------',
+ 'BarFoo' => 'foobar--------------------------',
+ 'bad' => 'bad',
+ ], '' );
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( null ) );
+ try {
+ $provider->getSessionIdFromCookie( $request );
+ $this->fail( 'Expected exception not thrown' );
+ } catch ( \BadMethodCallException $ex ) {
+ $this->assertSame(
+ 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie::getSessionIdFromCookie ' .
+ 'may not be called when $this->sessionCookieName === null',
+ $ex->getMessage()
+ );
+ }
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo' ) );
+ $this->assertSame(
+ 'wgfoo---------------------------',
+ $provider->getSessionIdFromCookie( $request )
+ );
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo', 'Bar' ) );
+ $this->assertSame(
+ 'foobar--------------------------',
+ $provider->getSessionIdFromCookie( $request )
+ );
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'Foo', '' ) );
+ $this->assertSame(
+ 'foo-----------------------------',
+ $provider->getSessionIdFromCookie( $request )
+ );
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'bad', '' ) );
+ $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
+
+ $provider = TestingAccessWrapper::newFromObject( $this->getProvider( 'none', '' ) );
+ $this->assertSame( null, $provider->getSessionIdFromCookie( $request ) );
+ }
+
+ protected function getSentRequest() {
+ $sentResponse = $this->getMockBuilder( \FauxResponse::class )
+ ->setMethods( [ 'headersSent', 'setCookie', 'header' ] )
+ ->getMock();
+ $sentResponse->expects( $this->any() )->method( 'headersSent' )
+ ->will( $this->returnValue( true ) );
+ $sentResponse->expects( $this->never() )->method( 'setCookie' );
+ $sentResponse->expects( $this->never() )->method( 'header' );
+
+ $sentRequest = $this->getMockBuilder( \FauxRequest::class )
+ ->setMethods( [ 'response' ] )->getMock();
+ $sentRequest->expects( $this->any() )->method( 'response' )
+ ->will( $this->returnValue( $sentResponse ) );
+ return $sentRequest;
+ }
+
+ /**
+ * @dataProvider providePersistSession
+ * @param bool $secure
+ * @param bool $remember
+ */
+ public function testPersistSession( $secure, $remember ) {
+ $this->setMwGlobals( [
+ 'wgCookieExpiration' => 100,
+ 'wgSecureLogin' => false,
+ ] );
+
+ $provider = $this->getProvider( 'session' );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $priv = TestingAccessWrapper::newFromObject( $provider );
+ $priv->sessionCookieOptions = [
+ 'prefix' => 'x',
+ 'path' => 'CookiePath',
+ 'domain' => 'CookieDomain',
+ 'secure' => false,
+ 'httpOnly' => true,
+ ];
+
+ $sessionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
+ $user = User::newFromName( 'UTSysop' );
+ $this->assertFalse( $user->requiresHTTPS(), 'sanity check' );
+
+ $backend = new SessionBackend(
+ new SessionId( $sessionId ),
+ new SessionInfo( SessionInfo::MIN_PRIORITY, [
+ 'provider' => $provider,
+ 'id' => $sessionId,
+ 'persisted' => true,
+ 'userInfo' => UserInfo::newFromUser( $user, true ),
+ 'idIsSafe' => true,
+ ] ),
+ new TestBagOStuff(),
+ new \Psr\Log\NullLogger(),
+ 10
+ );
+ TestingAccessWrapper::newFromObject( $backend )->usePhpSessionHandling = false;
+ $backend->setRememberUser( $remember );
+ $backend->setForceHTTPS( $secure );
+
+ // No cookie
+ $priv->sessionCookieName = null;
+ $request = new \FauxRequest();
+ $provider->persistSession( $backend, $request );
+ $this->assertSame( [], $request->response()->getCookies() );
+
+ // Cookie
+ $priv->sessionCookieName = 'session';
+ $request = new \FauxRequest();
+ $time = time();
+ $provider->persistSession( $backend, $request );
+
+ $cookie = $request->response()->getCookieData( 'xsession' );
+ $this->assertInternalType( 'array', $cookie );
+ if ( isset( $cookie['expire'] ) && $cookie['expire'] > 0 ) {
+ // Round expiry so we don't randomly fail if the seconds ticked during the test.
+ $cookie['expire'] = round( $cookie['expire'] - $time, -2 );
+ }
+ $this->assertEquals( [
+ 'value' => $sessionId,
+ 'expire' => null,
+ 'path' => 'CookiePath',
+ 'domain' => 'CookieDomain',
+ 'secure' => $secure,
+ 'httpOnly' => true,
+ 'raw' => false,
+ ], $cookie );
+
+ $cookie = $request->response()->getCookieData( 'forceHTTPS' );
+ if ( $secure ) {
+ $this->assertInternalType( 'array', $cookie );
+ if ( isset( $cookie['expire'] ) && $cookie['expire'] > 0 ) {
+ // Round expiry so we don't randomly fail if the seconds ticked during the test.
+ $cookie['expire'] = round( $cookie['expire'] - $time, -2 );
+ }
+ $this->assertEquals( [
+ 'value' => 'true',
+ 'expire' => null,
+ 'path' => 'CookiePath',
+ 'domain' => 'CookieDomain',
+ 'secure' => false,
+ 'httpOnly' => true,
+ 'raw' => false,
+ ], $cookie );
+ } else {
+ $this->assertNull( $cookie );
+ }
+
+ // Headers sent
+ $request = $this->getSentRequest();
+ $provider->persistSession( $backend, $request );
+ $this->assertSame( [], $request->response()->getCookies() );
+ }
+
+ public static function providePersistSession() {
+ return [
+ [ false, false ],
+ [ false, true ],
+ [ true, false ],
+ [ true, true ],
+ ];
+ }
+
+ public function testUnpersistSession() {
+ $provider = $this->getProvider( 'session', '' );
+ $provider->setLogger( new \Psr\Log\NullLogger() );
+ $priv = TestingAccessWrapper::newFromObject( $provider );
+
+ // No cookie
+ $priv->sessionCookieName = null;
+ $request = new \FauxRequest();
+ $provider->unpersistSession( $request );
+ $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );
+
+ // Cookie
+ $priv->sessionCookieName = 'session';
+ $request = new \FauxRequest();
+ $provider->unpersistSession( $request );
+ $this->assertSame( '', $request->response()->getCookie( 'session', '' ) );
+
+ // Headers sent
+ $request = $this->getSentRequest();
+ $provider->unpersistSession( $request );
+ $this->assertSame( null, $request->response()->getCookie( 'session', '' ) );
+ }
+
+}