Issues (14)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

tests/Middleware/SessionWareTest.php (4 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * SessionWare (https://github.com/juliangut/sessionware)
4
 * PSR7 session management middleware
5
 *
6
 * @license BSD-3-Clause
7
 * @author Julián Gutiérrez <[email protected]>
8
 */
9
10
namespace Jgut\Middleware\Sessionware\Tests;
11
12
use Jgut\Middleware\SessionWare;
13
use Zend\Diactoros\Response;
14
use Zend\Diactoros\ServerRequestFactory;
15
16
/**
17
 * PHP session handler middleware test class.
18
 */
19
class SessionWareTest extends \PHPUnit_Framework_TestCase
20
{
21
    /**
22
     * @var \Zend\Diactoros\Request
23
     */
24
    protected $request;
25
26
    /**
27
     * @var Response
28
     */
29
    protected $response;
30
31
    /**
32
     * @var callable
33
     */
34
    protected $callback;
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    public function setUp()
40
    {
41
        // Set a high probability to launch garbage collector
42
        ini_set('session.gc_probability', 1);
43
        ini_set('session.gc_divisor', 4);
44
45
        if (session_status() === PHP_SESSION_ACTIVE) {
46
            session_unset();
47
            session_destroy();
48
        }
49
50
        $this->request = ServerRequestFactory::fromGlobals();
0 ignored issues
show
Documentation Bug introduced by
It seems like \Zend\Diactoros\ServerRe...tFactory::fromGlobals() of type object<Zend\Diactoros\ServerRequest> is incompatible with the declared type object<Zend\Diactoros\Request> of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
51
        $this->response = new Response;
52
        $this->callback = function ($request, $response) {
53
            return $response;
54
        };
55
    }
56
57
    /**
58
     * @runInSeparateProcess
59
     * @preserveGlobalState disabled
60
     *
61
     * @expectedException \RuntimeException
62
     * @expectedExceptionMessageRegExp /^Session has already been started/
63
     */
64
    public function testSessionAlreadyStarted()
65
    {
66
        session_id('SessionWareSession');
67
68
        session_start();
69
70
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
71
72
        $middleware($this->request, $this->response, $this->callback);
73
    }
74
75
    /**
76
     * @runInSeparateProcess
77
     * @preserveGlobalState disabled
78
     */
79
    public function testSessionTimeoutControlKey()
0 ignored issues
show
testSessionTimeoutControlKey uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
80
    {
81
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'timeoutKey' => '__TIMEOUT__']);
82
83
        $middleware($this->request, $this->response, $this->callback);
84
85
        $limitTimeout = time() - SessionWare::SESSION_LIFETIME_EXTENDED;
86
        $_SESSION['__TIMEOUT__'] = $limitTimeout;
87
        session_write_close();
88
89
        $sessionHolder = new \stdClass();
90
        $middleware->addListener('pre.session_timeout', function ($sessionId) use ($sessionHolder) {
91
            $sessionHolder->id = $sessionId;
92
        });
93
94
        $assert = $this;
95
        $middleware->addListener('post.session_timeout', function ($sessionId) use ($assert, $sessionHolder) {
96
            $assert::assertNotNull($sessionHolder->id);
97
            $assert::assertNotEquals($sessionHolder->id, $sessionId);
98
        });
99
100
        $middleware($this->request, $this->response, $this->callback);
101
102
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
103
        self::assertTrue(array_key_exists('__TIMEOUT__', $_SESSION));
104
        self::assertNotEquals($_SESSION['__TIMEOUT__'], $limitTimeout);
105
    }
106
107
    /**
108
     * @runInSeparateProcess
109
     * @preserveGlobalState disabled
110
     *
111
     * @expectedException \InvalidArgumentException
112
     * @expectedExceptionMessage "  " is not a valid session timeout
113
     */
114
    public function testSessionErrorTimeoutControlKey()
115
    {
116
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'timeoutKey' => '  ']);
117
118
        $middleware($this->request, $this->response, $this->callback);
119
    }
120
121
    /**
122
     * @runInSeparateProcess
123
     * @preserveGlobalState disabled
124
     *
125
     * @expectedException \InvalidArgumentException
126
     * @expectedExceptionMessage Session name must be a non empty string
127
     */
128
    public function testEmptySessionName()
129
    {
130
        $middleware = new SessionWare(['name' => '']);
131
132
        $middleware($this->request, $this->response, $this->callback);
133
    }
134
135
    /**
136
     * @runInSeparateProcess
137
     * @preserveGlobalState disabled
138
     */
139
    public function testSessionName()
140
    {
141
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
142
143
        /** @var Response $response */
144
        $response = $middleware($this->request, $this->response, $this->callback);
145
146
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
147
        self::assertEquals('SessionWareSession', session_name());
148
        self::assertSame(strpos($response->getHeaderLine('Set-Cookie'), 'SessionWareSession'), 0);
149
    }
150
151
    /**
152
     * @runInSeparateProcess
153
     * @preserveGlobalState disabled
154
     */
155
    public function testSessionIdFromFunction()
156
    {
157
        $sessionId = SessionWare::generateSessionId();
158
159
        session_id($sessionId);
160
161
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
162
163
        /** @var Response $response */
164
        $response = $middleware($this->request, $this->response, $this->callback);
165
166
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
167
        self::assertNotSame(strpos($response->getHeaderLine('Set-Cookie'), $sessionId), false);
168
    }
169
170
    /**
171
     * @runInSeparateProcess
172
     * @preserveGlobalState disabled
173
     */
174
    public function testSessionIdFromRequest()
175
    {
176
        $sessionId = SessionWare::generateSessionId();
177
178
        $request = ServerRequestFactory::fromGlobals(null, null, null, ['SessionWareSession' => $sessionId]);
179
180
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
181
182
        /** @var Response $response */
183
        $response = $middleware($request, $this->response, $this->callback);
184
185
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
186
        self::assertNotSame(strpos($response->getHeaderLine('Set-Cookie'), $sessionId), false);
187
    }
188
189
    /**
190
     * @runInSeparateProcess
191
     * @preserveGlobalState disabled
192
     */
193
    public function testGeneratedSessionId()
194
    {
195
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
196
197
        $middleware($this->request, $this->response, $this->callback);
198
199
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
200
    }
201
202
    /**
203
     * @runInSeparateProcess
204
     * @preserveGlobalState disabled
205
     */
206
    public function testSessionEmptySavePath()
207
    {
208
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'savePath' => '']);
209
210
        $middleware($this->request, $this->response, $this->callback);
211
212
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
213
        self::assertTrue(is_dir(sys_get_temp_dir() . '/SessionWareSession'));
214
    }
215
216
    /**
217
     * @runInSeparateProcess
218
     * @preserveGlobalState disabled
219
     */
220
    public function testSessionSavePathFromFunction()
221
    {
222
        $tmpPath = sys_get_temp_dir() . '/SessionWareSession';
223
224
        session_save_path($tmpPath);
225
226
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
227
228
        $middleware($this->request, $this->response, $this->callback);
229
230
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
231
        self::assertTrue(is_dir($tmpPath));
232
    }
233
234
    /**
235
     * @runInSeparateProcess
236
     * @preserveGlobalState disabled
237
     */
238
    public function testSessionSavePathFromParameter()
239
    {
240
        $tmpPath = sys_get_temp_dir() . '/SessionWareSession';
241
242
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'savePath' => $tmpPath]);
243
244
        $middleware($this->request, $this->response, $this->callback);
245
246
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
247
        self::assertTrue(is_dir($tmpPath));
248
    }
249
250
    /**
251
     * @runInSeparateProcess
252
     * @preserveGlobalState disabled
253
     *
254
     * @expectedException \RuntimeException
255
     * @expectedExceptionMessageRegExp /^Failed to create session save path/
256
     */
257
    public function testSessionErrorSavePath()
258
    {
259
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'savePath' => '/my-fake-dir']);
260
261
        $middleware($this->request, $this->response, $this->callback);
262
    }
263
264
    /**
265
     * @runInSeparateProcess
266
     * @preserveGlobalState disabled
267
     */
268
    public function testSessionTimeoutDefault()
269
    {
270
        ini_set('session.cookie_lifetime', 0);
271
        ini_set('session.gc_maxlifetime', 0);
272
273
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
274
275
        $middleware($this->request, $this->response, $this->callback);
276
277
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
278
        self::assertEquals(SessionWare::SESSION_LIFETIME_DEFAULT, ini_get('session.gc_maxlifetime'));
279
    }
280
281
    /**
282
     * @runInSeparateProcess
283
     * @preserveGlobalState disabled
284
     */
285
    public function testSessionTimeoutByCookieLifetime()
286
    {
287
        ini_set('session.cookie_lifetime', 10);
288
        ini_set('session.gc_maxlifetime', SessionWare::SESSION_LIFETIME_EXTENDED);
289
290
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
291
292
        $middleware($this->request, $this->response, $this->callback);
293
294
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
295
        self::assertEquals(10, ini_get('session.gc_maxlifetime'));
296
    }
297
298
    /**
299
     * @runInSeparateProcess
300
     * @preserveGlobalState disabled
301
     */
302
    public function testSessionTimeoutByMaxLifetime()
303
    {
304
        ini_set('session.cookie_lifetime', 0);
305
        ini_set('session.gc_maxlifetime', SessionWare::SESSION_LIFETIME_NORMAL);
306
307
        $middleware = new SessionWare(['name' => 'SessionWareSession']);
308
309
        $middleware($this->request, $this->response, $this->callback);
310
311
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
312
        self::assertEquals(SessionWare::SESSION_LIFETIME_NORMAL, ini_get('session.gc_maxlifetime'));
313
    }
314
315
    /**
316
     * @runInSeparateProcess
317
     * @preserveGlobalState disabled
318
     */
319
    public function testSessionTimeoutByParameter()
320
    {
321
        $middleware = new SessionWare([
322
            'name' => 'SessionWareSession',
323
            'lifetime' => SessionWare::SESSION_LIFETIME_SHORT,
324
        ]);
325
326
        $middleware($this->request, $this->response, $this->callback);
327
328
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
329
        self::assertEquals(SessionWare::SESSION_LIFETIME_SHORT, ini_get('session.gc_maxlifetime'));
330
    }
331
332
    /**
333
     * @runInSeparateProcess
334
     * @preserveGlobalState disabled
335
     *
336
     * @expectedException \InvalidArgumentException
337
     * @expectedExceptionMessage Session lifetime must be at least 1
338
     */
339
    public function testSessionErrorTimeout()
340
    {
341
        $middleware = new SessionWare(['name' => 'SessionWareSession', 'lifetime' => 0]);
342
343
        $middleware($this->request, $this->response, $this->callback);
344
    }
345
346
    /**
347
     * @runInSeparateProcess
348
     * @preserveGlobalState disabled
349
     */
350
    public function testSessionDefaultParams()
0 ignored issues
show
testSessionDefaultParams uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
351
    {
352
        $middleware = new SessionWare(['name' => 'SessionWareSession'], ['parameter' => 'value']);
353
354
        $middleware($this->request, $this->response, $this->callback);
355
356
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
357
        self::assertEquals('value', $_SESSION['parameter']);
358
    }
359
360
    /**
361
     * @runInSeparateProcess
362
     * @preserveGlobalState disabled
363
     */
364
    public function testSessionCookieParams()
365
    {
366
        $middleware = new SessionWare([
367
            'name' => 'SessionWareSession',
368
            'lifetime' => 300,
369
            'domain' => 'http://example.com',
370
            'path' => 'path',
371
            'secure' => true,
372
            'httponly' => true,
373
        ]);
374
375
        /** @var Response $response */
376
        $response = $middleware($this->request, $this->response, $this->callback);
377
378
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
379
380
        $cookieHeader = $response->getHeaderLine('Set-Cookie');
381
        self::assertTrue(strpos($cookieHeader, 'SessionWareSession') !== false);
382
        self::assertTrue(strpos($cookieHeader, 'http://example.com') !== false);
383
        self::assertTrue(strpos($cookieHeader, 'path') !== false);
384
        self::assertTrue(strpos($cookieHeader, 'secure') !== false);
385
        self::assertTrue(strpos($cookieHeader, 'httponly') !== false);
386
    }
387
388
    /**
389
     * @runInSeparateProcess
390
     * @preserveGlobalState disabled
391
     */
392
    public function testSessionEndedCookieParams()
0 ignored issues
show
testSessionEndedCookieParams uses the super-global variable $_SESSION which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
393
    {
394
        $middleware = new SessionWare([
395
            'name' => 'SessionWareSession',
396
            'lifetime' => 300,
397
            'domain' => 'http://example.com',
398
        ]);
399
        $expiration = gmdate('D, d M Y H:i:s T', time() - 300);
400
401
        /** @var Response $response */
402
        $response = $middleware(
403
            $this->request,
404
            $this->response,
405
            function ($request, $response) {
406
                $_SESSION = [];
407
408
                // Serialization is not allowed in PHPUnit running on a separate process
409
                //session_unset();
410
                //session_destroy();
411
412
                return $response;
413
            }
414
        );
415
416
        self::assertEquals(PHP_SESSION_ACTIVE, session_status());
417
418
        $cookieHeader = $response->getHeaderLine('Set-Cookie');
419
        self::assertTrue(strpos($cookieHeader, 'SessionWareSession') !== false);
420
        self::assertTrue(strpos($cookieHeader, 'http://example.com') !== false);
421
        self::assertTrue(strpos($cookieHeader, $expiration) !== false);
422
    }
423
}
424