3 namespace MediaWiki\Tests\Session
;
5 use BadMethodCallException
;
6 use InvalidArgumentException
;
7 use MediaWiki\Config\HashConfig
;
8 use MediaWiki\MainConfigNames
;
9 use MediaWiki\Request\FauxRequest
;
10 use MediaWiki\Session\MetadataMergeException
;
11 use MediaWiki\Session\SessionInfo
;
12 use MediaWiki\Session\SessionManager
;
13 use MediaWiki\Session\SessionProvider
;
14 use MediaWiki\User\User
;
15 use MediaWiki\User\UserNameUtils
;
16 use MediaWikiIntegrationTestCase
;
18 use Wikimedia\TestingAccessWrapper
;
23 * @covers \MediaWiki\Session\SessionProvider
25 class SessionProviderTest
extends MediaWikiIntegrationTestCase
{
26 use SessionProviderTestTrait
;
28 public function testBasics() {
29 $this->hideDeprecated( 'MediaWiki\Session\SessionProvider::setConfig' );
30 $this->hideDeprecated( 'MediaWiki\Session\SessionProvider::setLogger' );
31 $this->hideDeprecated( 'MediaWiki\Session\SessionProvider::setManager' );
32 $this->hideDeprecated( 'MediaWiki\Session\SessionProvider::setHookContainer' );
34 $manager = new SessionManager();
35 $logger = new TestLogger();
36 $config = new HashConfig();
37 $hookContainer = $this->createHookContainer();
38 $userNameUtils = $this->createNoOpMock( UserNameUtils
::class );
40 $provider = $this->getMockForAbstractClass( SessionProvider
::class );
41 $priv = TestingAccessWrapper
::newFromObject( $provider );
43 $this->initProvider( $provider, $logger, $config, $manager, $hookContainer, $userNameUtils );
44 $this->assertSame( $logger, $priv->logger
);
45 $this->assertSame( $config, $priv->getConfig() );
46 $this->assertSame( $manager, $priv->manager
);
47 $this->assertSame( $manager, $provider->getManager() );
48 $this->assertSame( $hookContainer, $priv->getHookContainer() );
49 $this->assertSame( $userNameUtils, $priv->userNameUtils
);
50 $provider->setConfig( $config );
51 $this->assertSame( $config, $priv->getConfig() );
52 $provider->setLogger( $logger );
53 $this->assertSame( $logger, $priv->logger
);
54 $provider->setManager( $manager );
55 $this->assertSame( $manager, $priv->manager
);
56 $this->assertSame( $manager, $provider->getManager() );
57 $provider->setHookContainer( $hookContainer );
58 $this->assertSame( $hookContainer, $priv->getHookContainer() );
60 $provider->invalidateSessionsForUser( new User
);
62 $this->assertSame( [], $provider->getVaryHeaders() );
63 $this->assertSame( [], $provider->getVaryCookies() );
64 $this->assertSame( null, $provider->suggestLoginUsername( new FauxRequest
) );
66 $this->assertSame( get_class( $provider ), (string)$provider );
68 $this->assertNull( $provider->getRememberUserDuration() );
70 $this->assertNull( $provider->whyNoSession() );
71 $this->assertFalse( $provider->safeAgainstCsrf() );
73 $info = new SessionInfo( SessionInfo
::MIN_PRIORITY
, [
74 'id' => 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
75 'provider' => $provider,
77 $metadata = [ 'foo' ];
78 $this->assertTrue( $provider->refreshSessionInfo( $info, new FauxRequest
, $metadata ) );
79 $this->assertSame( [ 'foo' ], $metadata );
83 * @dataProvider provideNewSessionInfo
84 * @param bool $persistId Return value for ->persistsSessionId()
85 * @param bool $persistUser Return value for ->persistsSessionUser()
86 * @param bool $ok Whether a SessionInfo is provided
88 public function testNewSessionInfo( $persistId, $persistUser, $ok ) {
89 $manager = new SessionManager();
91 $provider = $this->getMockBuilder( SessionProvider
::class )
92 ->onlyMethods( [ 'canChangeUser', 'persistsSessionId' ] )
93 ->getMockForAbstractClass();
94 $provider->method( 'persistsSessionId' )
95 ->willReturn( $persistId );
96 $provider->method( 'canChangeUser' )
97 ->willReturn( $persistUser );
98 $this->initProvider( $provider, null, null, $manager );
101 $info = $provider->newSessionInfo();
102 $this->assertNotNull( $info );
103 $this->assertFalse( $info->wasPersisted() );
104 $this->assertTrue( $info->isIdSafe() );
106 $id = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
107 $info = $provider->newSessionInfo( $id );
108 $this->assertNotNull( $info );
109 $this->assertSame( $id, $info->getId() );
110 $this->assertFalse( $info->wasPersisted() );
111 $this->assertTrue( $info->isIdSafe() );
113 $this->assertNull( $provider->newSessionInfo() );
117 public function testMergeMetadata() {
118 $provider = $this->getMockBuilder( SessionProvider
::class )
119 ->getMockForAbstractClass();
122 $provider->mergeMetadata(
123 [ 'foo' => 1, 'baz' => 3 ],
124 [ 'bar' => 2, 'baz' => '3' ]
126 $this->fail( 'Expected exception not thrown' );
127 } catch ( MetadataMergeException
$ex ) {
128 $this->assertSame( 'Key "baz" changed', $ex->getMessage() );
130 [ 'old_value' => 3, 'new_value' => '3' ], $ex->getContext() );
133 $res = $provider->mergeMetadata(
134 [ 'foo' => 1, 'baz' => 3 ],
135 [ 'bar' => 2, 'baz' => 3 ]
137 $this->assertSame( [ 'bar' => 2, 'baz' => 3 ], $res );
140 public static function provideNewSessionInfo() {
142 [ false, false, false ],
143 [ true, false, false ],
144 [ false, true, false ],
145 [ true, true, true ],
149 public function testImmutableSessions() {
150 $provider = $this->getMockBuilder( SessionProvider
::class )
151 ->onlyMethods( [ 'canChangeUser', 'persistsSessionId' ] )
152 ->getMockForAbstractClass();
153 $provider->method( 'canChangeUser' )
154 ->willReturn( true );
155 $provider->preventSessionsForUser( 'Foo' );
157 $provider = $this->getMockBuilder( SessionProvider
::class )
158 ->onlyMethods( [ 'canChangeUser', 'persistsSessionId' ] )
159 ->getMockForAbstractClass();
160 $provider->method( 'canChangeUser' )
161 ->willReturn( false );
163 $provider->preventSessionsForUser( 'Foo' );
164 $this->fail( 'Expected exception not thrown' );
165 } catch ( BadMethodCallException
$ex ) {
167 'MediaWiki\\Session\\SessionProvider::preventSessionsForUser must be implemented ' .
168 'when canChangeUser() is false',
174 public function testHashToSessionId() {
175 $config = new HashConfig( [
176 MainConfigNames
::SecretKey
=> 'Shhh!',
179 $provider = $this->getMockForAbstractClass( SessionProvider
::class,
180 [], 'MockSessionProvider' );
181 $this->initProvider( $provider, null, $config );
182 $priv = TestingAccessWrapper
::newFromObject( $provider );
184 $this->assertSame( 'eoq8cb1mg7j30ui5qolafps4hg29k5bb', $priv->hashToSessionId( 'foobar' ) );
185 $this->assertSame( '4do8j7tfld1g8tte9jqp3csfgmulaun9',
186 $priv->hashToSessionId( 'foobar', 'secret' ) );
189 $priv->hashToSessionId( [] );
190 $this->fail( 'Expected exception not thrown' );
191 } catch ( InvalidArgumentException
$ex ) {
193 '$data must be a string, array was passed',
198 $priv->hashToSessionId( '', false );
199 $this->fail( 'Expected exception not thrown' );
200 } catch ( InvalidArgumentException
$ex ) {
202 '$key must be a string or null, bool was passed',
208 public function testDescribe() {
209 $provider = $this->getMockForAbstractClass( SessionProvider
::class,
210 [], 'MockSessionProvider' );
213 'MockSessionProvider sessions',
215 $this->getServiceContainer()->getLanguageFactory()->getLanguage( 'en' ) )
219 public function testGetAllowedUserRights() {
220 $provider = $this->getMockForAbstractClass( SessionProvider
::class );
221 $backend = TestUtils
::getDummySessionBackend();
224 $provider->getAllowedUserRights( $backend );
225 $this->fail( 'Expected exception not thrown' );
226 } catch ( InvalidArgumentException
$ex ) {
228 'Backend\'s provider isn\'t $this',
233 TestingAccessWrapper
::newFromObject( $backend )->provider
= $provider;
234 $this->assertNull( $provider->getAllowedUserRights( $backend ) );