3 namespace MediaWiki\Tests\Session
;
5 use MediaWiki\User\User
;
6 use MediaWikiIntegrationTestCase
;
9 use Wikimedia\TestingAccessWrapper
;
13 * @covers \MediaWiki\Session\Session
15 class SessionTest
extends MediaWikiIntegrationTestCase
{
17 public function testClear() {
18 $session = TestUtils
::getDummySession();
19 $priv = TestingAccessWrapper
::newFromObject( $session );
21 $backend = $this->getMockBuilder( DummySessionBackend
::class )
22 ->addMethods( [ 'canSetUser', 'setUser', 'save' ] )
24 $backend->expects( $this->once() )->method( 'canSetUser' )
26 $backend->expects( $this->once() )->method( 'setUser' )
27 ->with( $this->callback( static function ( $user ) {
28 return $user instanceof User
&& $user->isAnon();
30 $backend->expects( $this->once() )->method( 'save' );
31 $priv->backend
= $backend;
33 $this->assertSame( [], $backend->data
);
34 $this->assertTrue( $backend->dirty
);
36 $backend = $this->getMockBuilder( DummySessionBackend
::class )
37 ->addMethods( [ 'canSetUser', 'setUser', 'save' ] )
40 $backend->expects( $this->once() )->method( 'canSetUser' )
42 $backend->expects( $this->once() )->method( 'setUser' )
43 ->with( $this->callback( static function ( $user ) {
44 return $user instanceof User
&& $user->isAnon();
46 $backend->expects( $this->once() )->method( 'save' );
47 $priv->backend
= $backend;
49 $this->assertFalse( $backend->dirty
);
51 $backend = $this->getMockBuilder( DummySessionBackend
::class )
52 ->addMethods( [ 'canSetUser', 'setUser', 'save' ] )
54 $backend->expects( $this->once() )->method( 'canSetUser' )
55 ->willReturn( false );
56 $backend->expects( $this->never() )->method( 'setUser' );
57 $backend->expects( $this->once() )->method( 'save' );
58 $priv->backend
= $backend;
60 $this->assertSame( [], $backend->data
);
61 $this->assertTrue( $backend->dirty
);
64 public function testSecrets() {
65 $logger = new TestLogger
;
66 $session = TestUtils
::getDummySession( null, -1, $logger );
69 $this->assertEquals( 'defaulted', $session->getSecret( 'test', 'defaulted' ) );
72 $session->set( 'test', 'foobar' );
73 $logger->setCollect( true );
74 $this->assertEquals( 'defaulted', $session->getSecret( 'test', 'defaulted' ) );
75 $logger->setCollect( false );
77 [ LogLevel
::WARNING
, 'Invalid sealed-secret format' ]
78 ], $logger->getBuffer() );
79 $logger->clearBuffer();
82 $session->setSecret( 'test', 'foobar' );
83 $encrypted = $session->get( 'test' );
84 $session->set( 'test', $encrypted . 'x' );
85 $logger->setCollect( true );
86 $this->assertEquals( 'defaulted', $session->getSecret( 'test', 'defaulted' ) );
87 $logger->setCollect( false );
89 [ LogLevel
::WARNING
, 'Sealed secret has been tampered with, aborting.' ]
90 ], $logger->getBuffer() );
91 $logger->clearBuffer();
93 // Unserializable data
94 $iv = random_bytes( 16 );
95 [ $encKey, $hmacKey ] = TestingAccessWrapper
::newFromObject( $session )->getSecretKeys();
96 $ciphertext = openssl_encrypt( 'foobar', 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA
, $iv );
97 $sealed = base64_encode( $iv ) . '.' . base64_encode( $ciphertext );
98 $hmac = hash_hmac( 'sha256', $sealed, $hmacKey, true );
99 $encrypted = base64_encode( $hmac ) . '.' . $sealed;
100 $session->set( 'test', $encrypted );
101 $this->assertEquals( 'defaulted', @$session->getSecret( 'test', 'defaulted' ) );
105 * @dataProvider provideSecretsRoundTripping
107 public function testSecretsRoundTripping( $data ) {
108 $session = TestUtils
::getDummySession();
111 $session->setSecret( 'secret', $data );
112 // Cast to strings because PHPUnit sometimes considers true as equal to a string,
113 // depending on the other of the parameters (T317750)
114 $raw = $session->get( 'secret' );
115 $this->assertIsString( $raw );
116 if ( is_scalar( $data ) ) {
117 $this->assertNotSame( (string)$data, $raw );
119 $this->assertEquals( $data, $session->getSecret( 'secret', 'defaulted' ) );
122 public static function provideSecretsRoundTripping() {
126 [ [ 'foo', 'bar' => 'baz', 'subarray' => [ 1, 2, 3 ] ] ],
127 [ (object)[ 'foo', 'bar' => 'baz', 'subarray' => [ 1, 2, 3 ] ] ],