Completed
Push — EZP-26146-location-swap-urlali... ( 334d77...8d4853 )
by
unknown
63:56 queued 37:49
created

SessionTest::testDeleteSession()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 9
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
c 0
b 0
f 0
nc 1
nop 0
dl 9
loc 9
rs 9.6666
1
<?php
2
/**
3
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
4
 * @license For full copyright and license information view LICENSE file distributed with this source code.
5
 */
6
namespace eZ\Bundle\EzPublishRestBundle\Tests\Functional;
7
8
use Buzz\Message\Form\FormRequest;
9
use Buzz\Message\Response;
10
use Buzz\Message\Request;
11
use stdClass;
12
13
class SessionTest extends TestCase
14
{
15
    public function setUp()
16
    {
17
        $this->autoLogin = false;
18
        parent::setUp();
19
    }
20
21 View Code Duplication
    public function testCreateSessionBadCredentials()
22
    {
23
        $request = $this->createHttpRequest('POST', '/api/ezp/v2/user/sessions', 'SessionInput+json', 'Session+json');
24
        $this->setSessionInput($request, 'badpassword');
25
        $response = $this->sendHttpRequest($request);
26
        self::assertHttpResponseCodeEquals($response, 401);
27
    }
28
29
    /**
30
     * @return \stdClass The login request's response
31
     */
32
    public function testCreateSession()
33
    {
34
        return $this->login();
35
    }
36
37
    /**
38
     * @depends testCreateSession
39
     */
40
    public function testRefreshSession(stdClass $session)
41
    {
42
        $response = $this->sendHttpRequest($this->createRefreshRequest($session));
43
        self::assertHttpResponseCodeEquals($response, 200);
44
    }
45
46
    public function testRefreshSessionExpired()
47
    {
48
        $session = $this->login();
49
50
        $response = $this->sendHttpRequest($this->createDeleteRequest($session));
51
        self::assertHttpResponseCodeEquals($response, 204);
52
53
        $response = $this->sendHttpRequest($this->createRefreshRequest($session));
54
        self::assertHttpResponseCodeEquals($response, 404);
55
56
        self::assertHttpResponseDeletesSessionCookie($session, $response);
57
    }
58
59 View Code Duplication
    public function testRefreshSessionMissingCsrfToken()
60
    {
61
        $session = $this->login();
62
63
        $refreshRequest = $this->createRefreshRequest($session);
64
        $this->removeCsrfHeader($refreshRequest);
65
        $response = $this->sendHttpRequest($refreshRequest);
66
        self::assertHttpResponseCodeEquals($response, 401);
67
    }
68
69 View Code Duplication
    public function testDeleteSession()
70
    {
71
        $session = $this->login();
72
        $response = $this->sendHttpRequest($this->createDeleteRequest($session));
73
        self::assertHttpResponseCodeEquals($response, 204);
74
        self::assertHttpResponseDeletesSessionCookie($session, $response);
75
76
        return $session;
77
    }
78
79
    /**
80
     * CSRF needs to be tested as session handling bypasses the CsrfListener.
81
     */
82 View Code Duplication
    public function testDeleteSessionMissingCsrfToken()
83
    {
84
        $session = $this->login();
85
        $request = $this->createDeleteRequest($session);
86
        $this->removeCsrfHeader($request);
87
        $response = $this->sendHttpRequest($request);
88
        self::assertHttpResponseCodeEquals($response, 401);
89
    }
90
91
    public function testLoginWithExistingFrontendSession()
92
    {
93
        $loginFormResponse = $this->sendHttpRequest(new Request('GET', '/login', $this->getHttpHost()));
94
        $domDocument = $loginFormResponse->toDomDocument();
95
        $xpath = new \DOMXPath($domDocument);
96
97
        $csrfDomElements = $xpath->query("//input[@name='_csrf_token']/@value");
98
        self::assertGreaterThan(0, $csrfDomElements->length);
99
        $csrfTokenValue = $csrfDomElements->item(0)->nodeValue;
100
101
        $loginPostRequest = new FormRequest('POST', '/login', $this->getHttpHost());
102
        $loginPostRequest->addFields([
103
            '_username' => $this->getLoginUsername(),
104
            '_password' => $this->getLoginPassword(),
105
            '_csrf_token' => $csrfTokenValue,
106
        ]);
107
        $loginResponse = $this->sendHttpRequest($loginPostRequest);
108
        if (!$sessionCookieHeader = $loginResponse->getHeader('set-cookie')) {
109
            self::fail('No cookie in login response');
110
        }
111
112
        list($sessionCookie) = explode(';', $sessionCookieHeader);
113
114
        $request = $this->createHttpRequest('POST', '/api/ezp/v2/user/sessions', 'SessionInput+json', 'Session+json');
115
        $this->setSessionInput($request);
116
        $request->addHeader("Cookie: $sessionCookie");
117
        $response = $this->sendHttpRequest($request);
118
        self::assertHttpResponseCodeEquals($response, 201);
119
    }
120
121
    /**
122
     * @depends testDeleteSession
123
     */
124
    public function testDeleteSessionExpired($session)
125
    {
126
        $response = $this->sendHttpRequest($this->createDeleteRequest($session));
127
        self::assertHttpResponseCodeEquals($response, 404);
128
        self::assertHttpResponseDeletesSessionCookie($session, $response);
129
    }
130
131
    /**
132
     * @param stdClass $session
133
     * @return \Buzz\Message\Request
134
     */
135
    protected function createRefreshRequest(stdClass $session)
136
    {
137
        $request = $this->createHttpRequest('POST',
138
            sprintf('/api/ezp/v2/user/sessions/%s/refresh', $session->identifier), '', 'Session+json');
139
        $request->addHeaders([
140
            sprintf('Cookie: %s=%s', $session->name, $session->identifier),
141
            sprintf('X-CSRF-Token: %s', $session->csrfToken),
142
        ]);
143
144
        return $request;
145
    }
146
147
    /**
148
     * @param $session
149
     * @return \Buzz\Message\Request
150
     */
151
    protected function createDeleteRequest($session)
152
    {
153
        $deleteRequest = $this->createHttpRequest('DELETE', $session->_href);
154
        $deleteRequest->addHeaders([
155
            sprintf('Cookie: %s=%s', $session->name, $session->identifier),
156
            sprintf('X-CSRF-Token: %s', $session->csrfToken),
157
        ]);
158
159
        return $deleteRequest;
160
    }
161
162
    private static function assertHttpResponseDeletesSessionCookie($session, Response $response)
163
    {
164
        self::assertStringStartsWith("{$session->name}=deleted;", $response->getHeader('set-cookie'));
165
    }
166
167
    /**
168
     * Removes the CSRF token header from a $request.
169
     *
170
     * @param Request $request
171
     */
172
    private function removeCsrfHeader(Request $request)
173
    {
174
        foreach ($request->getHeaders() as $headerString) {
175
            list($headerName) = explode(': ', $headerString);
176
            if (strtolower($headerName) !== 'x-csrf-token') {
177
                $headers[] = $headerString;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$headers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $headers = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
178
            }
179
        }
180
181
        $request->setHeaders($headers);
0 ignored issues
show
Bug introduced by
The variable $headers does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
182
    }
183
}
184