wiki.techinc.nl/tests/phpunit/includes/session/SessionInfoTest.php
Brad Jorsch afdcd30599 Add SessionInfo force-use flag
A provider that uses SessionProvider::hashToSessionId() will likely have
issues if something such as a call to $user->setToken() causes
SessionManager::loadSessionInfoFromStore() to fail, since the provider
can't just arbitrarily change the session ID it returns.

The two solutions to this problem are:
* Somehow include everything that could cause loadSessionInfoFromStore
  to fail in the data hashed by hashToSessionId.
* Flag the SessionInfo so that, if stored data and the SessionInfo
  conflict, it should delete the stored data instead of discarding the
  SessionInfo.

Since the second is less complexity overall due to the lack of need to
define "everything", this patch takes that approach.

Change-Id: I8c6fab2ec295e71242bbcb19d0ee5ade6bd655df
2016-05-10 15:59:32 -04:00

356 lines
12 KiB
PHP

<?php
namespace MediaWiki\Session;
use MediaWikiTestCase;
/**
* @group Session
* @group Database
* @covers MediaWiki\Session\SessionInfo
*/
class SessionInfoTest extends MediaWikiTestCase {
public function testBasics() {
$anonInfo = UserInfo::newAnonymous();
$userInfo = UserInfo::newFromName( 'UTSysop', true );
$unverifiedUserInfo = UserInfo::newFromName( 'UTSysop', false );
try {
new SessionInfo( SessionInfo::MIN_PRIORITY - 1, [] );
$this->fail( 'Expected exception not thrown', 'priority < min' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid priority', $ex->getMessage(), 'priority < min' );
}
try {
new SessionInfo( SessionInfo::MAX_PRIORITY + 1, [] );
$this->fail( 'Expected exception not thrown', 'priority > max' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid priority', $ex->getMessage(), 'priority > max' );
}
try {
new SessionInfo( SessionInfo::MIN_PRIORITY, [ 'id' => 'ABC?' ] );
$this->fail( 'Expected exception not thrown', 'bad session ID' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid session ID', $ex->getMessage(), 'bad session ID' );
}
try {
new SessionInfo( SessionInfo::MIN_PRIORITY, [ 'userInfo' => new \stdClass ] );
$this->fail( 'Expected exception not thrown', 'bad userInfo' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid userInfo', $ex->getMessage(), 'bad userInfo' );
}
try {
new SessionInfo( SessionInfo::MIN_PRIORITY, [] );
$this->fail( 'Expected exception not thrown', 'no provider, no id' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Must supply an ID when no provider is given', $ex->getMessage(),
'no provider, no id' );
}
try {
new SessionInfo( SessionInfo::MIN_PRIORITY, [ 'copyFrom' => new \stdClass ] );
$this->fail( 'Expected exception not thrown', 'bad copyFrom' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid copyFrom', $ex->getMessage(),
'bad copyFrom' );
}
$manager = new SessionManager();
$provider = $this->getMockBuilder( SessionProvider::class )
->setMethods( [ 'persistsSessionId', 'canChangeUser', '__toString' ] )
->getMockForAbstractClass();
$provider->setManager( $manager );
$provider->expects( $this->any() )->method( 'persistsSessionId' )
->will( $this->returnValue( true ) );
$provider->expects( $this->any() )->method( 'canChangeUser' )
->will( $this->returnValue( true ) );
$provider->expects( $this->any() )->method( '__toString' )
->will( $this->returnValue( 'Mock' ) );
$provider2 = $this->getMockBuilder( SessionProvider::class )
->setMethods( [ 'persistsSessionId', 'canChangeUser', '__toString' ] )
->getMockForAbstractClass();
$provider2->setManager( $manager );
$provider2->expects( $this->any() )->method( 'persistsSessionId' )
->will( $this->returnValue( true ) );
$provider2->expects( $this->any() )->method( 'canChangeUser' )
->will( $this->returnValue( true ) );
$provider2->expects( $this->any() )->method( '__toString' )
->will( $this->returnValue( 'Mock2' ) );
try {
new SessionInfo( SessionInfo::MIN_PRIORITY, [
'provider' => $provider,
'userInfo' => $anonInfo,
'metadata' => 'foo',
] );
$this->fail( 'Expected exception not thrown', 'bad metadata' );
} catch ( \InvalidArgumentException $ex ) {
$this->assertSame( 'Invalid metadata', $ex->getMessage(), 'bad metadata' );
}
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'userInfo' => $anonInfo
] );
$this->assertSame( $provider, $info->getProvider() );
$this->assertNotNull( $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $anonInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'userInfo' => $unverifiedUserInfo,
'metadata' => [ 'Foo' ],
] );
$this->assertSame( $provider, $info->getProvider() );
$this->assertNotNull( $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $unverifiedUserInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertSame( [ 'Foo' ], $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'userInfo' => $userInfo
] );
$this->assertSame( $provider, $info->getProvider() );
$this->assertNotNull( $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$id = $manager->generateSessionId();
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'persisted' => true,
'userInfo' => $anonInfo
] );
$this->assertSame( $provider, $info->getProvider() );
$this->assertSame( $id, $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $anonInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'userInfo' => $userInfo
] );
$this->assertSame( $provider, $info->getProvider() );
$this->assertSame( $id, $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'id' => $id,
'persisted' => true,
'userInfo' => $userInfo,
'metadata' => [ 'Foo' ],
] );
$this->assertSame( $id, $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'id' => $id,
'remembered' => true,
'userInfo' => $userInfo,
] );
$this->assertFalse( $info->wasRemembered(), 'no provider' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'remembered' => true,
] );
$this->assertFalse( $info->wasRemembered(), 'no user' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'remembered' => true,
'userInfo' => $anonInfo,
] );
$this->assertFalse( $info->wasRemembered(), 'anonymous user' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'remembered' => true,
'userInfo' => $unverifiedUserInfo,
] );
$this->assertFalse( $info->wasRemembered(), 'unverified user' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'remembered' => false,
'userInfo' => $userInfo,
] );
$this->assertFalse( $info->wasRemembered(), 'specific override' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'id' => $id,
'idIsSafe' => true,
] );
$this->assertSame( $id, $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 5, $info->getPriority() );
$this->assertTrue( $info->isIdSafe() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'id' => $id,
'forceUse' => true,
] );
$this->assertFalse( $info->forceUse(), 'no provider' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'forceUse' => true,
] );
$this->assertFalse( $info->forceUse(), 'no id' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 5, [
'provider' => $provider,
'id' => $id,
'forceUse' => true,
] );
$this->assertTrue( $info->forceUse(), 'correct use' );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'id' => $id,
'forceHTTPS' => 1,
] );
$this->assertTrue( $info->forceHTTPS() );
$fromInfo = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'id' => $id . 'A',
'provider' => $provider,
'userInfo' => $userInfo,
'idIsSafe' => true,
'forceUse' => true,
'persisted' => true,
'remembered' => true,
'forceHTTPS' => true,
'metadata' => [ 'foo!' ],
] );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 4, [
'copyFrom' => $fromInfo,
] );
$this->assertSame( $id . 'A', $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 4, $info->getPriority() );
$this->assertSame( $provider, $info->getProvider() );
$this->assertSame( $userInfo, $info->getUserInfo() );
$this->assertTrue( $info->isIdSafe() );
$this->assertTrue( $info->forceUse() );
$this->assertTrue( $info->wasPersisted() );
$this->assertTrue( $info->wasRemembered() );
$this->assertTrue( $info->forceHTTPS() );
$this->assertSame( [ 'foo!' ], $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY + 4, [
'id' => $id . 'X',
'provider' => $provider2,
'userInfo' => $unverifiedUserInfo,
'idIsSafe' => false,
'forceUse' => false,
'persisted' => false,
'remembered' => false,
'forceHTTPS' => false,
'metadata' => null,
'copyFrom' => $fromInfo,
] );
$this->assertSame( $id . 'X', $info->getId() );
$this->assertSame( SessionInfo::MIN_PRIORITY + 4, $info->getPriority() );
$this->assertSame( $provider2, $info->getProvider() );
$this->assertSame( $unverifiedUserInfo, $info->getUserInfo() );
$this->assertFalse( $info->isIdSafe() );
$this->assertFalse( $info->forceUse() );
$this->assertFalse( $info->wasPersisted() );
$this->assertFalse( $info->wasRemembered() );
$this->assertFalse( $info->forceHTTPS() );
$this->assertNull( $info->getProviderMetadata() );
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'id' => $id,
] );
$this->assertSame(
'[' . SessionInfo::MIN_PRIORITY . "]null<null>$id",
(string)$info,
'toString'
);
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'provider' => $provider,
'id' => $id,
'persisted' => true,
'userInfo' => $userInfo
] );
$this->assertSame(
'[' . SessionInfo::MIN_PRIORITY . "]Mock<+:{$userInfo->getId()}:UTSysop>$id",
(string)$info,
'toString'
);
$info = new SessionInfo( SessionInfo::MIN_PRIORITY, [
'provider' => $provider,
'id' => $id,
'persisted' => true,
'userInfo' => $unverifiedUserInfo
] );
$this->assertSame(
'[' . SessionInfo::MIN_PRIORITY . "]Mock<-:{$userInfo->getId()}:UTSysop>$id",
(string)$info,
'toString'
);
}
public function testCompare() {
$id = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
$info1 = new SessionInfo( SessionInfo::MIN_PRIORITY + 1, [ 'id' => $id ] );
$info2 = new SessionInfo( SessionInfo::MIN_PRIORITY + 2, [ 'id' => $id ] );
$this->assertTrue( SessionInfo::compare( $info1, $info2 ) < 0, '<' );
$this->assertTrue( SessionInfo::compare( $info2, $info1 ) > 0, '>' );
$this->assertTrue( SessionInfo::compare( $info1, $info1 ) === 0, '==' );
}
}