Passed
Push — 4 ( 54647a...f3132c )
by Guy
07:01 queued 10s
created

SessionTest::testDisabledUserAgentLockout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 22
rs 9.8666
1
<?php
2
3
namespace SilverStripe\Control\Tests;
4
5
use http\Exception\BadMessageException;
6
use SilverStripe\Control\Cookie;
7
use SilverStripe\Control\Session;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\Control\HTTPRequest;
10
11
/**
12
 * Tests to cover the {@link Session} class
13
 */
14
class SessionTest extends SapphireTest
15
{
16
    /**
17
     * @var Session
18
     */
19
    protected $session = null;
20
21
    protected function setUp()
22
    {
23
        $this->session = new Session([]);
24
        return parent::setUp();
25
    }
26
27
    /**
28
     * @runInSeparateProcess
29
     * @preserveGlobalState disabled
30
     */
31
    public function testInitDoesNotStartSessionWithoutIdentifier()
32
    {
33
        $req = new HTTPRequest('GET', '/');
34
        $session = new Session(null); // unstarted session
35
        $session->init($req);
36
        $this->assertFalse($session->isStarted());
37
    }
38
39
    /**
40
     * @runInSeparateProcess
41
     * @preserveGlobalState disabled
42
     */
43
    public function testInitStartsSessionWithIdentifier()
44
    {
45
        $req = new HTTPRequest('GET', '/');
46
        Cookie::set(session_name(), '1234');
47
        $session = new Session(null); // unstarted session
48
        $session->init($req);
49
        $this->assertTrue($session->isStarted());
50
    }
51
52
    /**
53
     * @runInSeparateProcess
54
     * @preserveGlobalState disabled
55
     */
56
    public function testInitStartsSessionWithData()
57
    {
58
        $req = new HTTPRequest('GET', '/');
59
        $session = new Session([]);
60
        $session->init($req);
61
        $this->assertTrue($session->isStarted());
62
    }
63
64
    /**
65
     * @runInSeparateProcess
66
     * @preserveGlobalState disabled
67
     */
68
    public function testStartUsesDefaultCookieNameWithHttp()
69
    {
70
        $req = (new HTTPRequest('GET', '/'))
71
            ->setScheme('http');
72
        Cookie::set(session_name(), '1234');
73
        $session = new Session(null); // unstarted session
74
        $session->start($req);
75
        $this->assertNotEquals(session_name(), $session->config()->get('cookie_name_secure'));
76
    }
77
78
    /**
79
     * @runInSeparateProcess
80
     * @preserveGlobalState disabled
81
     */
82
    public function testStartUsesDefaultCookieNameWithHttpsAndCookieSecureOff()
83
    {
84
        $req = (new HTTPRequest('GET', '/'))
85
            ->setScheme('https');
86
        Cookie::set(session_name(), '1234');
87
        $session = new Session(null); // unstarted session
88
        $session->start($req);
89
        $this->assertNotEquals(session_name(), $session->config()->get('cookie_name_secure'));
90
    }
91
92
    /**
93
     * @runInSeparateProcess
94
     * @preserveGlobalState disabled
95
     */
96
    public function testStartUsesSecureCookieNameWithHttpsAndCookieSecureOn()
97
    {
98
        $req = (new HTTPRequest('GET', '/'))
99
            ->setScheme('https');
100
        Cookie::set(session_name(), '1234');
101
        $session = new Session(null); // unstarted session
102
        $session->config()->update('cookie_secure', true);
103
        $session->start($req);
104
        $this->assertEquals(session_name(), $session->config()->get('cookie_name_secure'));
105
    }
106
107
    /**
108
     * @runInSeparateProcess
109
     * @preserveGlobalState disabled
110
     * @expectedException BadMethodCallException
111
     * @expectedExceptionMessage Session has already started
112
     */
113
    public function testStartErrorsWhenStartingTwice()
114
    {
115
        $req = new HTTPRequest('GET', '/');
116
        $session = new Session(null); // unstarted session
117
        $session->start($req);
118
        $session->start($req);
119
    }
120
121
    /**
122
     * @runInSeparateProcess
123
     * @preserveGlobalState disabled
124
     */
125
    public function testStartRetainsInMemoryData()
126
    {
127
        $this->markTestIncomplete('Test');
128
        // TODO Figure out how to simulate session vars without a session_start() resetting them
129
        // $_SESSION['existing'] = true;
130
        // $_SESSION['merge'] = 1;
131
        $req = new HTTPRequest('GET', '/');
132
        $session = new Session(null); // unstarted session
133
        $session->set('new', true);
134
        $session->set('merge', 2);
135
        $session->start($req); // simulate lazy start
136
        $this->assertEquals(
137
            [
138
                // 'existing' => true,
139
                'new' => true,
140
                'merge' => 2,
141
            ],
142
            $session->getAll()
143
        );
144
145
        unset($_SESSION);
146
    }
147
148
    public function testGetSetBasics()
149
    {
150
        $this->session->set('Test', 'Test');
151
152
        $this->assertEquals($this->session->get('Test'), 'Test');
153
    }
154
155
    public function testClearElement()
156
    {
157
        $this->session->set('Test', 'Test');
158
        $this->session->clear('Test');
159
160
        $this->assertEquals($this->session->get('Test'), '');
161
    }
162
163
    public function testClearAllElements()
164
    {
165
        $this->session->set('Test', 'Test');
166
        $this->session->set('Test-1', 'Test-1');
167
168
        $this->session->clearAll();
169
170
        // should session get return null? The array key should probably be
171
        // unset from the data array
172
        $this->assertEquals($this->session->get('Test'), '');
173
        $this->assertEquals($this->session->get('Test-1'), '');
174
    }
175
176
    public function testGetAllElements()
177
    {
178
        $this->session->clearAll(); // Remove all session that might've been set by the test harness
179
180
        $this->session->set('Test', 'Test');
181
        $this->session->set('Test-2', 'Test-2');
182
183
        $session = $this->session->getAll();
184
        unset($session['HTTP_USER_AGENT']);
185
186
        $this->assertEquals($session, ['Test' => 'Test', 'Test-2' => 'Test-2']);
187
    }
188
189
    public function testSettingExistingDoesntClear()
190
    {
191
        $s = new Session(['something' => ['does' => 'exist']]);
192
193
        $s->set('something.does', 'exist');
194
        $result = $s->changedData();
195
        unset($result['HTTP_USER_AGENT']);
196
        $this->assertEmpty($result);
197
    }
198
199
    /**
200
     * Check that changedData isn't populated with junk when clearing non-existent entries.
201
     */
202
    public function testClearElementThatDoesntExist()
203
    {
204
        $s = new Session(['something' => ['does' => 'exist']]);
205
        $s->clear('something.doesnt.exist');
206
207
        // Clear without existing data
208
        $data = $s->get('something.doesnt.exist');
209
        $this->assertEmpty($s->changedData());
210
        $this->assertNull($data);
211
212
        // Clear with existing change
213
        $s->set('something-else', 'val');
214
        $s->clear('something-new');
215
        $data = $s->get('something-else');
216
        $this->assertEquals(['something-else' => true], $s->changedData());
217
        $this->assertEquals('val', $data);
218
    }
219
220
    /**
221
     * Check that changedData is populated with clearing data.
222
     */
223
    public function testClearElementThatDoesExist()
224
    {
225
        $s = new Session(['something' => ['does' => 'exist']]);
226
227
        // Ensure keys are properly removed and not simply nullified
228
        $s->clear('something.does');
229
        $this->assertEquals(
230
            ['something' => ['does' => true]],
231
            $s->changedData()
232
        );
233
        $this->assertEquals(
234
            [], // 'does' removed
235
            $s->get('something')
236
        );
237
238
        // Clear at more specific level should also clear other changes
239
        $s->clear('something');
240
        $this->assertEquals(
241
            ['something' => true],
242
            $s->changedData()
243
        );
244
        $this->assertEquals(
245
            null, // Should be removed not just empty array
246
            $s->get('something')
247
        );
248
    }
249
250
    public function testRequestContainsSessionId()
251
    {
252
        $req = new HTTPRequest('GET', '/');
253
        $session = new Session(null); // unstarted session
254
        $this->assertFalse($session->requestContainsSessionId($req));
255
        Cookie::set(session_name(), '1234');
256
        $this->assertTrue($session->requestContainsSessionId($req));
257
    }
258
259
    public function testRequestContainsSessionIdRespectsCookieNameSecure()
260
    {
261
        $req = (new HTTPRequest('GET', '/'))
262
            ->setScheme('https');
263
        $session = new Session(null); // unstarted session
264
        Cookie::set($session->config()->get('cookie_name_secure'), '1234');
265
        $session->config()->update('cookie_secure', true);
266
        $this->assertTrue($session->requestContainsSessionId($req));
267
    }
268
269
    public function testUserAgentLockout()
270
    {
271
        // Set a user agent
272
        $req1 = new HTTPRequest('GET', '/');
273
        $req1->addHeader('User-Agent', 'Test Agent');
274
275
        // Generate our session
276
        $s = new Session([]);
277
        $s->init($req1);
278
        $s->set('val', 123);
279
        $s->finalize($req1);
280
281
        // Change our UA
282
        $req2 = new HTTPRequest('GET', '/');
283
        $req2->addHeader('User-Agent', 'Fake Agent');
284
285
        // Verify the new session reset our values
286
        $s2 = new Session($s);
287
        $s2->init($req2);
288
        $this->assertEmpty($s2->get('val'));
289
    }
290
291
    public function testDisabledUserAgentLockout()
292
    {
293
        Session::config()->set('strict_user_agent_check', false);
294
295
        // Set a user agent
296
        $req1 = new HTTPRequest('GET', '/');
297
        $req1->addHeader('User-Agent', 'Test Agent');
298
299
        // Generate our session
300
        $s = new Session([]);
301
        $s->init($req1);
302
        $s->set('val', 123);
303
        $s->finalize($req1);
304
305
        // Change our UA
306
        $req2 = new HTTPRequest('GET', '/');
307
        $req2->addHeader('User-Agent', 'Fake Agent');
308
309
        // Verify the new session reset our values
310
        $s2 = new Session($s);
311
        $s2->init($req2);
312
        $this->assertEquals($s2->get('val'), 123);
313
    }
314
315
    public function testSave()
316
    {
317
        $request = new HTTPRequest('GET', '/');
318
319
        // Test change of nested array type
320
        $s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]);
321
        $s->set('something', 'string');
322
        $s->save($request);
323
        $this->assertEquals(
324
            ['something' => 'string'],
325
            $_SESSION
326
        );
327
328
        // Test multiple changes combine safely
329
        $s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]);
330
        $s->set('something.another', 'newanother');
331
        $s->clear('something.some');
332
        $s->set('something.newkey', 'new value');
333
        $s->save($request);
334
        $this->assertEquals(
335
            [
336
                'something' => [
337
                    'another' => 'newanother',
338
                    'newkey' => 'new value',
339
                ],
340
            ],
341
            $_SESSION
342
        );
343
344
        // Test cleared keys are restorable
345
        $s = new Session($_SESSION = ['bookmarks' => [1 => 1, 2 => 2]]);
346
        $s->clear('bookmarks');
347
        $s->set('bookmarks', [
348
            1 => 1,
349
            3 => 3,
350
        ]);
351
        $s->save($request);
352
        $this->assertEquals(
353
            [
354
                'bookmarks' => [
355
                    1 => 1,
356
                    3 => 3,
357
                ],
358
            ],
359
            $_SESSION
360
        );
361
    }
362
}
363