|
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, array('Test' => 'Test', 'Test-2' => 'Test-2')); |
|
187
|
|
|
} |
|
188
|
|
|
|
|
189
|
|
|
public function testSettingExistingDoesntClear() |
|
190
|
|
|
{ |
|
191
|
|
|
$s = new Session(array('something' => array('does' => 'exist'))); |
|
192
|
|
|
|
|
193
|
|
|
$s->set('something.does', 'exist'); |
|
194
|
|
|
$result = $s->changedData(); |
|
195
|
|
|
unset($result['HTTP_USER_AGENT']); |
|
196
|
|
|
$this->assertEquals(array(), $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->assertEquals(array(), $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(array()); |
|
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->assertNotEquals($s2->get('val'), 123); |
|
289
|
|
|
} |
|
290
|
|
|
|
|
291
|
|
|
public function testSave() |
|
292
|
|
|
{ |
|
293
|
|
|
$request = new HTTPRequest('GET', '/'); |
|
294
|
|
|
|
|
295
|
|
|
// Test change of nested array type |
|
296
|
|
|
$s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]); |
|
297
|
|
|
$s->set('something', 'string'); |
|
298
|
|
|
$s->save($request); |
|
299
|
|
|
$this->assertEquals( |
|
300
|
|
|
['something' => 'string'], |
|
301
|
|
|
$_SESSION |
|
302
|
|
|
); |
|
303
|
|
|
|
|
304
|
|
|
// Test multiple changes combine safely |
|
305
|
|
|
$s = new Session($_SESSION = ['something' => ['some' => 'value', 'another' => 'item']]); |
|
306
|
|
|
$s->set('something.another', 'newanother'); |
|
307
|
|
|
$s->clear('something.some'); |
|
308
|
|
|
$s->set('something.newkey', 'new value'); |
|
309
|
|
|
$s->save($request); |
|
310
|
|
|
$this->assertEquals( |
|
311
|
|
|
[ |
|
312
|
|
|
'something' => [ |
|
313
|
|
|
'another' => 'newanother', |
|
314
|
|
|
'newkey' => 'new value', |
|
315
|
|
|
] |
|
316
|
|
|
], |
|
317
|
|
|
$_SESSION |
|
318
|
|
|
); |
|
319
|
|
|
|
|
320
|
|
|
// Test cleared keys are restorable |
|
321
|
|
|
$s = new Session($_SESSION = ['bookmarks' => [ 1 => 1, 2 => 2]]); |
|
322
|
|
|
$s->clear('bookmarks'); |
|
323
|
|
|
$s->set('bookmarks', [ |
|
324
|
|
|
1 => 1, |
|
325
|
|
|
3 => 3, |
|
326
|
|
|
]); |
|
327
|
|
|
$s->save($request); |
|
328
|
|
|
$this->assertEquals( |
|
329
|
|
|
[ |
|
330
|
|
|
'bookmarks' => [ |
|
331
|
|
|
1 => 1, |
|
332
|
|
|
3 => 3, |
|
333
|
|
|
] |
|
334
|
|
|
], |
|
335
|
|
|
$_SESSION |
|
336
|
|
|
); |
|
337
|
|
|
} |
|
338
|
|
|
} |
|
339
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.