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

User::createSession()   B

Complexity

Conditions 6
Paths 35

Size

Total Lines 38
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 26
c 0
b 0
f 0
nc 35
nop 1
dl 0
loc 38
rs 8.439
1
<?php
2
3
/**
4
 * File containing the User controller class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 *
9
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\Core\REST\Server\Controller;
12
13
use eZ\Publish\Core\REST\Common\Message;
14
use eZ\Publish\Core\REST\Server\Values;
15
use eZ\Publish\Core\REST\Server\Exceptions;
16
use eZ\Publish\Core\REST\Server\Controller as RestController;
17
use eZ\Publish\API\Repository\UserService;
18
use eZ\Publish\API\Repository\ContentService;
19
use eZ\Publish\API\Repository\ContentTypeService;
20
use eZ\Publish\API\Repository\RoleService;
21
use eZ\Publish\API\Repository\LocationService;
22
use eZ\Publish\API\Repository\SectionService;
23
use eZ\Publish\API\Repository\Repository;
24
use eZ\Publish\API\Repository\Values\User\UserRoleAssignment;
25
use eZ\Publish\API\Repository\Values\User\UserGroupRoleAssignment;
26
use eZ\Publish\API\Repository\Values\User\User as RepositoryUser;
27
use eZ\Publish\API\Repository\Exceptions as ApiExceptions;
28
use eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException;
29
use eZ\Publish\Core\REST\Common\Exceptions\NotFoundException;
30
use eZ\Publish\Core\Base\Exceptions\UnauthorizedException;
31
use Symfony\Component\DependencyInjection\ContainerInterface;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
34
use Symfony\Component\Security\Core\Exception\AuthenticationException;
35
use Symfony\Component\Security\Csrf\CsrfToken;
36
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
37
38
/**
39
 * User controller.
40
 */
41
class User extends RestController
42
{
43
    /**
44
     * User service.
45
     *
46
     * @var \eZ\Publish\API\Repository\UserService
47
     */
48
    protected $userService;
49
50
    /**
51
     * Role service.
52
     *
53
     * @var \eZ\Publish\API\Repository\RoleService
54
     */
55
    protected $roleService;
56
57
    /**
58
     * Content service.
59
     *
60
     * @var \eZ\Publish\API\Repository\ContentService
61
     */
62
    protected $contentService;
63
64
    /**
65
     * Content service.
66
     *
67
     * @var \eZ\Publish\API\Repository\ContentTypeService
68
     */
69
    protected $contentTypeService;
70
71
    /**
72
     * Location service.
73
     *
74
     * @var \eZ\Publish\API\Repository\LocationService
75
     */
76
    protected $locationService;
77
78
    /**
79
     * Section service.
80
     *
81
     * @var \eZ\Publish\API\Repository\SectionService
82
     */
83
    protected $sectionService;
84
85
    /**
86
     * Repository.
87
     *
88
     * @var \eZ\Publish\API\Repository\Repository
89
     */
90
    protected $repository;
91
92
    /**
93
     * @var \Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface
94
     */
95
    private $csrfTokenStorage;
96
97
    /**
98
     * Construct controller.
99
     *
100
     * @param \eZ\Publish\API\Repository\UserService $userService
101
     * @param \eZ\Publish\API\Repository\RoleService $roleService
102
     * @param \eZ\Publish\API\Repository\ContentService $contentService
103
     * @param \eZ\Publish\API\Repository\LocationService $locationService
104
     * @param \eZ\Publish\API\Repository\SectionService $sectionService
105
     * @param \eZ\Publish\API\Repository\Repository $repository
106
     */
107
    public function __construct(
108
        UserService $userService,
109
        RoleService $roleService,
110
        ContentService $contentService,
111
        ContentTypeService $contentTypeService,
112
        LocationService $locationService,
113
        SectionService $sectionService,
114
        Repository $repository
115
    ) {
116
        $this->userService = $userService;
117
        $this->roleService = $roleService;
118
        $this->contentService = $contentService;
119
        $this->contentTypeService = $contentTypeService;
120
        $this->locationService = $locationService;
121
        $this->sectionService = $sectionService;
122
        $this->repository = $repository;
123
    }
124
125
    /**
126
     * Redirects to the root user group.
127
     *
128
     * @return \eZ\Publish\Core\REST\Server\Values\PermanentRedirect
129
     */
130
    public function loadRootUserGroup()
131
    {
132
        //@todo Replace hardcoded value with one loaded from settings
133
        return new Values\PermanentRedirect(
134
            $this->router->generate('ezpublish_rest_loadUserGroup', array('groupPath' => '/1/5'))
135
        );
136
    }
137
138
    /**
139
     * Loads a user group for the given path.
140
     *
141
     * @param $groupPath
142
     *
143
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
144
     */
145
    public function loadUserGroup($groupPath)
146
    {
147
        $userGroupLocation = $this->locationService->loadLocation(
148
            $this->extractLocationIdFromPath($groupPath)
149
        );
150
151
        if (trim($userGroupLocation->pathString, '/') != $groupPath) {
152
            throw new NotFoundException(
153
                "Could not find location with path string $groupPath"
154
            );
155
        }
156
157
        $userGroup = $this->userService->loadUserGroup(
158
            $userGroupLocation->contentId
159
        );
160
        $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
161
        $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
162
163
        return new Values\CachedValue(
164
            new Values\RestUserGroup(
165
                $userGroup,
166
                $contentType,
167
                $userGroupContentInfo,
168
                $userGroupLocation,
169
                $this->contentService->loadRelations($userGroup->getVersionInfo())
170
            ),
171
            array('locationId' => $userGroupLocation->id)
172
        );
173
    }
174
175
    /**
176
     * Loads a user for the given ID.
177
     *
178
     * @param $userId
179
     *
180
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser
181
     */
182
    public function loadUser($userId)
183
    {
184
        $user = $this->userService->loadUser($userId);
185
186
        $userContentInfo = $user->getVersionInfo()->getContentInfo();
187
        $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
188
189
        try {
190
            $userMainLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
191
            $relations = $this->contentService->loadRelations($user->getVersionInfo());
192
        } catch (UnauthorizedException $e) {
193
            // TODO: Hack for special case to allow current logged in user to load him/here self (but not relations)
194
            if ($user->id == $this->repository->getCurrentUser()->id) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
195
                $userMainLocation = $this->repository->sudo(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface eZ\Publish\API\Repository\Repository as the method sudo() does only exist in the following implementations of said interface: eZ\Publish\Core\Repository\Repository, eZ\Publish\Core\SignalSlot\Repository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
196
                    function () use ($userContentInfo) {
197
                        return $this->locationService->loadLocation($userContentInfo->mainLocationId);
198
                    }
199
                );
200
                // user may not have permissions to read related content, for security reasons do not use sudo().
201
                $relations = array();
202
            } else {
203
                throw $e;
204
            }
205
        }
206
207
        return new Values\CachedValue(
208
            new Values\RestUser(
209
                $user,
210
                $contentType,
211
                $userContentInfo,
212
                $userMainLocation,
213
                $relations
214
            ),
215
            array('locationId' => $userContentInfo->mainLocationId)
216
        );
217
    }
218
219
    /**
220
     * Create a new user group under the given parent
221
     * To create a top level group use /user/groups/1/5/subgroups.
222
     *
223
     * @param $groupPath
224
     *
225
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\BadRequestException
226
     *
227
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedUserGroup
228
     */
229
    public function createUserGroup($groupPath, Request $request)
230
    {
231
        $userGroupLocation = $this->locationService->loadLocation(
232
            $this->extractLocationIdFromPath($groupPath)
233
        );
234
235
        $createdUserGroup = $this->userService->createUserGroup(
236
            $this->inputDispatcher->parse(
0 ignored issues
show
Compatibility introduced by
$this->inputDispatcher->...request->getContent())) of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\UserGroupCreateStruct>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\ValueObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
237
                new Message(
238
                    array('Content-Type' => $request->headers->get('Content-Type')),
239
                    $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
240
                )
241
            ),
242
            $this->userService->loadUserGroup(
243
                $userGroupLocation->contentId
244
            )
245
        );
246
247
        $createdContentInfo = $createdUserGroup->getVersionInfo()->getContentInfo();
248
        $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
249
        $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
250
251
        return new Values\CreatedUserGroup(
252
            array(
253
                'userGroup' => new Values\RestUserGroup(
254
                    $createdUserGroup,
255
                    $contentType,
256
                    $createdContentInfo,
257
                    $createdLocation,
258
                    $this->contentService->loadRelations($createdUserGroup->getVersionInfo())
259
                ),
260
            )
261
        );
262
    }
263
264
    /**
265
     * Create a new user group in the given group.
266
     *
267
     * @param $groupPath
268
     *
269
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
270
     *
271
     * @return \eZ\Publish\Core\REST\Server\Values\CreatedUser
272
     */
273
    public function createUser($groupPath, Request $request)
274
    {
275
        $userGroupLocation = $this->locationService->loadLocation(
276
            $this->extractLocationIdFromPath($groupPath)
277
        );
278
        $userGroup = $this->userService->loadUserGroup($userGroupLocation->contentId);
279
280
        $userCreateStruct = $this->inputDispatcher->parse(
281
            new Message(
282
                array('Content-Type' => $request->headers->get('Content-Type')),
283
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
284
            )
285
        );
286
287
        try {
288
            $createdUser = $this->userService->createUser($userCreateStruct, array($userGroup));
0 ignored issues
show
Compatibility introduced by
$userCreateStruct of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not a sub-type of object<eZ\Publish\API\Re...\User\UserCreateStruct>. It seems like you assume a child class of the class eZ\Publish\API\Repository\Values\ValueObject to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
289
        } catch (ApiExceptions\InvalidArgumentException $e) {
290
            throw new ForbiddenException($e->getMessage());
291
        }
292
293
        $createdContentInfo = $createdUser->getVersionInfo()->getContentInfo();
294
        $createdLocation = $this->locationService->loadLocation($createdContentInfo->mainLocationId);
295
        $contentType = $this->contentTypeService->loadContentType($createdContentInfo->contentTypeId);
296
297
        return new Values\CreatedUser(
298
            array(
299
                'user' => new Values\RestUser(
300
                    $createdUser,
301
                    $contentType,
302
                    $createdContentInfo,
303
                    $createdLocation,
304
                    $this->contentService->loadRelations($createdUser->getVersionInfo())
305
                ),
306
            )
307
        );
308
    }
309
310
    /**
311
     * Updates a user group.
312
     *
313
     * @param $groupPath
314
     *
315
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
316
     */
317
    public function updateUserGroup($groupPath, Request $request)
318
    {
319
        $userGroupLocation = $this->locationService->loadLocation(
320
            $this->extractLocationIdFromPath($groupPath)
321
        );
322
323
        $userGroup = $this->userService->loadUserGroup(
324
            $userGroupLocation->contentId
325
        );
326
327
        $updateStruct = $this->inputDispatcher->parse(
328
            new Message(
329
                array(
330
                    'Content-Type' => $request->headers->get('Content-Type'),
331
                    // @todo Needs refactoring! Temporary solution so parser has access to URL
332
                    'Url' => $request->getPathInfo(),
333
                ),
334
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
335
            )
336
        );
337
338 View Code Duplication
        if ($updateStruct->sectionId !== null) {
0 ignored issues
show
Documentation introduced by
The property sectionId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
339
            $section = $this->sectionService->loadSection($updateStruct->sectionId);
0 ignored issues
show
Documentation introduced by
The property sectionId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
340
            $this->sectionService->assignSection(
341
                $userGroup->getVersionInfo()->getContentInfo(),
342
                $section
343
            );
344
        }
345
346
        $updatedGroup = $this->userService->updateUserGroup($userGroup, $updateStruct->userGroupUpdateStruct);
0 ignored issues
show
Documentation introduced by
The property userGroupUpdateStruct does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
347
        $contentType = $this->contentTypeService->loadContentType(
348
            $updatedGroup->getVersionInfo()->getContentInfo()->contentTypeId
349
        );
350
351
        return new Values\RestUserGroup(
352
            $updatedGroup,
353
            $contentType,
354
            $updatedGroup->getVersionInfo()->getContentInfo(),
355
            $userGroupLocation,
356
            $this->contentService->loadRelations($updatedGroup->getVersionInfo())
357
        );
358
    }
359
360
    /**
361
     * Updates a user.
362
     *
363
     * @param $userId
364
     *
365
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser
366
     */
367
    public function updateUser($userId, Request $request)
368
    {
369
        $user = $this->userService->loadUser($userId);
370
371
        $updateStruct = $this->inputDispatcher->parse(
372
            new Message(
373
                array(
374
                    'Content-Type' => $request->headers->get('Content-Type'),
375
                    // @todo Needs refactoring! Temporary solution so parser has access to URL
376
                    'Url' => $request->getPathInfo(),
377
                ),
378
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
379
            )
380
        );
381
382 View Code Duplication
        if ($updateStruct->sectionId !== null) {
0 ignored issues
show
Documentation introduced by
The property sectionId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
383
            $section = $this->sectionService->loadSection($updateStruct->sectionId);
0 ignored issues
show
Documentation introduced by
The property sectionId does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
384
            $this->sectionService->assignSection(
385
                $user->getVersionInfo()->getContentInfo(),
386
                $section
387
            );
388
        }
389
390
        $updatedUser = $this->userService->updateUser($user, $updateStruct->userUpdateStruct);
0 ignored issues
show
Documentation introduced by
The property userUpdateStruct does not exist on object<eZ\Publish\API\Re...ory\Values\ValueObject>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
391
        $updatedContentInfo = $updatedUser->getVersionInfo()->getContentInfo();
392
        $mainLocation = $this->locationService->loadLocation($updatedContentInfo->mainLocationId);
393
        $contentType = $this->contentTypeService->loadContentType($updatedContentInfo->contentTypeId);
394
395
        return new Values\RestUser(
396
            $updatedUser,
397
            $contentType,
398
            $updatedContentInfo,
399
            $mainLocation,
400
            $this->contentService->loadRelations($updatedUser->getVersionInfo())
401
        );
402
    }
403
404
    /**
405
     * Given user group is deleted.
406
     *
407
     * @param $groupPath
408
     *
409
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
410
     *
411
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
412
     */
413
    public function deleteUserGroup($groupPath)
414
    {
415
        $userGroupLocation = $this->locationService->loadLocation(
416
            $this->extractLocationIdFromPath($groupPath)
417
        );
418
419
        $userGroup = $this->userService->loadUserGroup(
420
            $userGroupLocation->contentId
421
        );
422
423
        // Load one user to see if user group is empty or not
424
        $users = $this->userService->loadUsersOfUserGroup($userGroup, 0, 1);
425
        if (!empty($users)) {
426
            throw new Exceptions\ForbiddenException('Non-empty user groups cannot be deleted');
427
        }
428
429
        $this->userService->deleteUserGroup($userGroup);
430
431
        return new Values\NoContent();
432
    }
433
434
    /**
435
     * Given user is deleted.
436
     *
437
     * @param $userId
438
     *
439
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
440
     *
441
     * @return \eZ\Publish\Core\REST\Server\Values\NoContent
442
     */
443
    public function deleteUser($userId)
444
    {
445
        $user = $this->userService->loadUser($userId);
446
447
        if ($user->id == $this->repository->getCurrentUser()->id) {
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
448
            throw new Exceptions\ForbiddenException('Currently authenticated user cannot be deleted');
449
        }
450
451
        $this->userService->deleteUser($user);
452
453
        return new Values\NoContent();
454
    }
455
456
    /**
457
     * Loads users.
458
     *
459
     * @return \eZ\Publish\Core\REST\Server\Values\UserList|\eZ\Publish\Core\REST\Server\Values\UserRefList
460
     */
461
    public function loadUsers(Request $request)
462
    {
463
        $restUsers = array();
464
465
        try {
466
            if ($request->query->has('roleId')) {
467
                $restUsers = $this->loadUsersAssignedToRole(
468
                    $this->requestParser->parseHref($request->query->get('roleId'), 'roleId')
469
                );
470
            } elseif ($request->query->has('remoteId')) {
471
                $restUsers = array(
472
                    $this->buildRestUserObject(
473
                        $this->userService->loadUser(
474
                            $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'))->id
475
                        )
476
                    ),
477
                );
478
            } elseif ($request->query->has('login')) {
479
                $restUsers = array(
480
                    $this->buildRestUserObject(
481
                        $this->userService->loadUserByLogin($request->query->get('login'))
482
                    ),
483
                );
484
            } elseif ($request->query->has('email')) {
485
                foreach ($this->userService->loadUsersByEmail($request->query->get('email')) as $user) {
486
                    $restUsers[] = $this->buildRestUserObject($user);
487
                }
488
            }
489
        } catch (ApiExceptions\UnauthorizedException $e) {
490
            $restUsers = [];
491
        }
492
493
        if (empty($restUsers)) {
494
            throw new NotFoundException('No users were found with the given filter');
495
        }
496
497
        if ($this->getMediaType($request) === 'application/vnd.ez.api.userlist') {
498
            return new Values\UserList($restUsers, $request->getPathInfo());
499
        }
500
501
        return new Values\UserRefList($restUsers, $request->getPathInfo());
502
    }
503
504
    public function verifyUsers(Request $request)
505
    {
506
        // We let the NotFoundException loadUsers throws if there are no results pass.
507
        $this->loadUsers($request)->users;
508
509
        return new Values\OK();
510
    }
511
512
    /**
513
     * Loads a list of users assigned to role.
514
     *
515
     * @param mixed $roleId
516
     *
517
     * @return \eZ\Publish\Core\REST\Server\Values\RestUser[]
518
     */
519
    public function loadUsersAssignedToRole($roleId)
520
    {
521
        $role = $this->roleService->loadRole($roleId);
522
        $roleAssignments = $this->roleService->getRoleAssignments($role);
523
524
        $restUsers = array();
525
526
        foreach ($roleAssignments as $roleAssignment) {
527
            if ($roleAssignment instanceof UserRoleAssignment) {
528
                $restUsers[] = $this->buildRestUserObject($roleAssignment->getUser());
529
            }
530
        }
531
532
        return $restUsers;
533
    }
534
535
    /**
536
     * @return Values\RestUser
537
     */
538
    private function buildRestUserObject(RepositoryUser $user)
539
    {
540
        return new Values\RestUser(
541
            $user,
542
            $this->contentTypeService->loadContentType($user->contentInfo->contentTypeId),
543
            $user->contentInfo,
544
            $this->locationService->loadLocation($user->contentInfo->mainLocationId),
545
            $this->contentService->loadRelations($user->getVersionInfo())
546
        );
547
    }
548
549
    /**
550
     * Loads user groups.
551
     *
552
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupList|\eZ\Publish\Core\REST\Server\Values\UserGroupRefList
553
     */
554
    public function loadUserGroups(Request $request)
555
    {
556
        $restUserGroups = array();
557
        if ($request->query->has('id')) {
558
            $userGroup = $this->userService->loadUserGroup($request->query->get('id'));
559
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
560
            $userGroupMainLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
561
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
562
563
            $restUserGroups = array(
564
                new Values\RestUserGroup(
565
                    $userGroup,
566
                    $contentType,
567
                    $userGroupContentInfo,
568
                    $userGroupMainLocation,
569
                    $this->contentService->loadRelations($userGroup->getVersionInfo())
570
                ),
571
            );
572
        } elseif ($request->query->has('roleId')) {
573
            $restUserGroups = $this->loadUserGroupsAssignedToRole($request->query->get('roleId'));
574
        } elseif ($request->query->has('remoteId')) {
575
            $restUserGroups = array(
576
                $this->loadUserGroupByRemoteId($request),
577
            );
578
        }
579
580
        if ($this->getMediaType($request) === 'application/vnd.ez.api.usergrouplist') {
581
            return new Values\UserGroupList($restUserGroups, $request->getPathInfo());
582
        }
583
584
        return new Values\UserGroupRefList($restUserGroups, $request->getPathInfo());
585
    }
586
587
    /**
588
     * Loads a user group by its remote ID.
589
     *
590
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup
591
     */
592
    public function loadUserGroupByRemoteId(Request $request)
593
    {
594
        $contentInfo = $this->contentService->loadContentInfoByRemoteId($request->query->get('remoteId'));
595
        $userGroup = $this->userService->loadUserGroup($contentInfo->id);
596
        $userGroupLocation = $this->locationService->loadLocation($contentInfo->mainLocationId);
597
        $contentType = $this->contentTypeService->loadContentType($contentInfo->contentTypeId);
598
599
        return new Values\RestUserGroup(
600
            $userGroup,
601
            $contentType,
602
            $contentInfo,
603
            $userGroupLocation,
604
            $this->contentService->loadRelations($userGroup->getVersionInfo())
605
        );
606
    }
607
608
    /**
609
     * Loads a list of user groups assigned to role.
610
     *
611
     * @param mixed $roleId
612
     *
613
     * @return \eZ\Publish\Core\REST\Server\Values\RestUserGroup[]
614
     */
615
    public function loadUserGroupsAssignedToRole($roleId)
616
    {
617
        $role = $this->roleService->loadRole($roleId);
618
        $roleAssignments = $this->roleService->getRoleAssignments($role);
619
620
        $restUserGroups = array();
621
622
        foreach ($roleAssignments as $roleAssignment) {
623
            if ($roleAssignment instanceof UserGroupRoleAssignment) {
624
                $userGroup = $roleAssignment->getUserGroup();
625
                $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
626
                $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
627
                $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
628
629
                $restUserGroups[] = new Values\RestUserGroup(
630
                    $userGroup,
631
                    $contentType,
632
                    $userGroupContentInfo,
633
                    $userGroupLocation,
634
                    $this->contentService->loadRelations($userGroup->getVersionInfo())
635
                );
636
            }
637
        }
638
639
        return $restUserGroups;
640
    }
641
642
    /**
643
     * Loads drafts assigned to user.
644
     *
645
     * @param $userId
646
     *
647
     * @return \eZ\Publish\Core\REST\Server\Values\VersionList
648
     */
649
    public function loadUserDrafts($userId, Request $request)
650
    {
651
        $contentDrafts = $this->contentService->loadContentDrafts(
652
            $this->userService->loadUser($userId)
653
        );
654
655
        return new Values\VersionList($contentDrafts, $request->getPathInfo());
656
    }
657
658
    /**
659
     * Moves the user group to another parent.
660
     *
661
     * @param $groupPath
662
     *
663
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
664
     *
665
     * @return \eZ\Publish\Core\REST\Server\Values\ResourceCreated
666
     */
667
    public function moveUserGroup($groupPath, Request $request)
668
    {
669
        $userGroupLocation = $this->locationService->loadLocation(
670
            $this->extractLocationIdFromPath($groupPath)
671
        );
672
673
        $userGroup = $this->userService->loadUserGroup(
674
            $userGroupLocation->contentId
675
        );
676
677
        $locationPath = $this->requestParser->parseHref(
678
            $request->headers->get('Destination'),
679
            'groupPath'
680
        );
681
682
        try {
683
            $destinationGroupLocation = $this->locationService->loadLocation(
684
                $this->extractLocationIdFromPath($locationPath)
685
            );
686
        } catch (ApiExceptions\NotFoundException $e) {
687
            throw new Exceptions\ForbiddenException($e->getMessage());
688
        }
689
690
        try {
691
            $destinationGroup = $this->userService->loadUserGroup($destinationGroupLocation->contentId);
692
        } catch (ApiExceptions\NotFoundException $e) {
693
            throw new Exceptions\ForbiddenException($e->getMessage());
694
        }
695
696
        $this->userService->moveUserGroup($userGroup, $destinationGroup);
697
698
        return new Values\ResourceCreated(
699
            $this->router->generate(
700
                'ezpublish_rest_loadUserGroup',
701
                array(
702
                    'groupPath' => trim($destinationGroupLocation->pathString, '/') . '/' . $userGroupLocation->id,
703
                )
704
            )
705
        );
706
    }
707
708
    /**
709
     * Returns a list of the sub groups.
710
     *
711
     * @param $groupPath
712
     *
713
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupList|\eZ\Publish\Core\REST\Server\Values\UserGroupRefList
714
     */
715 View Code Duplication
    public function loadSubUserGroups($groupPath, Request $request)
716
    {
717
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
718
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
719
720
        $userGroupLocation = $this->locationService->loadLocation(
721
            $this->extractLocationIdFromPath($groupPath)
722
        );
723
724
        $userGroup = $this->userService->loadUserGroup(
725
            $userGroupLocation->contentId
726
        );
727
728
        $subGroups = $this->userService->loadSubUserGroups(
729
            $userGroup,
730
            $offset >= 0 ? $offset : 0,
731
            $limit >= 0 ? $limit : 25
732
        );
733
734
        $restUserGroups = array();
735
        foreach ($subGroups as $subGroup) {
736
            $subGroupContentInfo = $subGroup->getVersionInfo()->getContentInfo();
737
            $subGroupLocation = $this->locationService->loadLocation($subGroupContentInfo->mainLocationId);
738
            $contentType = $this->contentTypeService->loadContentType($subGroupContentInfo->contentTypeId);
739
740
            $restUserGroups[] = new Values\RestUserGroup(
741
                $subGroup,
742
                $contentType,
743
                $subGroupContentInfo,
744
                $subGroupLocation,
745
                $this->contentService->loadRelations($subGroup->getVersionInfo())
746
            );
747
        }
748
749
        if ($this->getMediaType($request) === 'application/vnd.ez.api.usergrouplist') {
750
            return new Values\CachedValue(
751
                new Values\UserGroupList($restUserGroups, $request->getPathInfo()),
752
                array('locationId' => $userGroupLocation->id)
753
            );
754
        }
755
756
        return new Values\CachedValue(
757
            new Values\UserGroupRefList($restUserGroups, $request->getPathInfo()),
758
            array('locationId' => $userGroupLocation->id)
759
        );
760
    }
761
762
    /**
763
     * Returns a list of user groups the user belongs to.
764
     * The returned list includes the resources for unassigning
765
     * a user group if the user is in multiple groups.
766
     *
767
     * @param $userId
768
     *
769
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
770
     */
771
    public function loadUserGroupsOfUser($userId, Request $request)
772
    {
773
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
774
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
775
776
        $user = $this->userService->loadUser($userId);
777
        $userGroups = $this->userService->loadUserGroupsOfUser(
778
            $user,
779
            $offset >= 0 ? $offset : 0,
780
            $limit >= 0 ? $limit : 25
781
        );
782
783
        $restUserGroups = array();
784
        foreach ($userGroups as $userGroup) {
785
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
786
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
787
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
788
789
            $restUserGroups[] = new Values\RestUserGroup(
790
                $userGroup,
791
                $contentType,
792
                $userGroupContentInfo,
793
                $userGroupLocation,
794
                $this->contentService->loadRelations($userGroup->getVersionInfo())
795
            );
796
        }
797
798
        return new Values\CachedValue(
799
            new Values\UserGroupRefList($restUserGroups, $request->getPathInfo(), $userId),
800
            array('locationId' => $user->contentInfo->mainLocationId)
801
        );
802
    }
803
804
    /**
805
     * Loads the users of the group with the given path.
806
     *
807
     * @param $groupPath
808
     *
809
     * @return \eZ\Publish\Core\REST\Server\Values\UserList|\eZ\Publish\Core\REST\Server\Values\UserRefList
810
     */
811 View Code Duplication
    public function loadUsersFromGroup($groupPath, Request $request)
812
    {
813
        $userGroupLocation = $this->locationService->loadLocation(
814
            $this->extractLocationIdFromPath($groupPath)
815
        );
816
817
        $userGroup = $this->userService->loadUserGroup(
818
            $userGroupLocation->contentId
819
        );
820
821
        $offset = $request->query->has('offset') ? (int)$request->query->get('offset') : 0;
822
        $limit = $request->query->has('limit') ? (int)$request->query->get('limit') : 25;
823
824
        $users = $this->userService->loadUsersOfUserGroup(
825
            $userGroup,
826
            $offset >= 0 ? $offset : 0,
827
            $limit >= 0 ? $limit : 25
828
        );
829
830
        $restUsers = array();
831
        foreach ($users as $user) {
832
            $userContentInfo = $user->getVersionInfo()->getContentInfo();
833
            $userLocation = $this->locationService->loadLocation($userContentInfo->mainLocationId);
834
            $contentType = $this->contentTypeService->loadContentType($userContentInfo->contentTypeId);
835
836
            $restUsers[] = new Values\RestUser(
837
                $user,
838
                $contentType,
839
                $userContentInfo,
840
                $userLocation,
841
                $this->contentService->loadRelations($user->getVersionInfo())
842
            );
843
        }
844
845
        if ($this->getMediaType($request) === 'application/vnd.ez.api.userlist') {
846
            return new Values\CachedValue(
847
                new Values\UserList($restUsers, $request->getPathInfo()),
848
                array('locationId' => $userGroupLocation->id)
849
            );
850
        }
851
852
        return new Values\CachedValue(
853
            new Values\UserRefList($restUsers, $request->getPathInfo()),
854
            array('locationId' => $userGroupLocation->id)
855
        );
856
    }
857
858
    /**
859
     * Unassigns the user from a user group.
860
     *
861
     * @param $userId
862
     * @param $groupPath
863
     *
864
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
865
     *
866
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
867
     */
868
    public function unassignUserFromUserGroup($userId, $groupPath)
869
    {
870
        $user = $this->userService->loadUser($userId);
871
        $userGroupLocation = $this->locationService->loadLocation(trim($groupPath, '/'));
872
873
        $userGroup = $this->userService->loadUserGroup(
874
            $userGroupLocation->contentId
875
        );
876
877
        try {
878
            $this->userService->unAssignUserFromUserGroup($user, $userGroup);
879
        } catch (ApiExceptions\InvalidArgumentException $e) {
880
            // User is not in the group
881
            throw new Exceptions\ForbiddenException($e->getMessage());
882
        }
883
884
        $userGroups = $this->userService->loadUserGroupsOfUser($user);
885
        $restUserGroups = array();
886
        foreach ($userGroups as $userGroup) {
887
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
888
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
889
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
890
891
            $restUserGroups[] = new Values\RestUserGroup(
892
                $userGroup,
893
                $contentType,
894
                $userGroupContentInfo,
895
                $userGroupLocation,
896
                $this->contentService->loadRelations($userGroup->getVersionInfo())
897
            );
898
        }
899
900
        return new Values\UserGroupRefList(
901
            $restUserGroups,
902
            $this->router->generate(
903
                'ezpublish_rest_loadUserGroupsOfUser',
904
                array('userId' => $userId)
905
            ),
906
            $userId
907
        );
908
    }
909
910
    /**
911
     * Assigns the user to a user group.
912
     *
913
     * @param $userId
914
     *
915
     * @throws \eZ\Publish\Core\REST\Server\Exceptions\ForbiddenException
916
     *
917
     * @return \eZ\Publish\Core\REST\Server\Values\UserGroupRefList
918
     */
919
    public function assignUserToUserGroup($userId, Request $request)
920
    {
921
        $user = $this->userService->loadUser($userId);
922
923
        try {
924
            $userGroupLocation = $this->locationService->loadLocation(
925
                $this->extractLocationIdFromPath($request->query->get('group'))
926
            );
927
        } catch (ApiExceptions\NotFoundException $e) {
928
            throw new Exceptions\ForbiddenException($e->getMessage());
929
        }
930
931
        try {
932
            $userGroup = $this->userService->loadUserGroup(
933
                $userGroupLocation->contentId
934
            );
935
        } catch (ApiExceptions\NotFoundException $e) {
936
            throw new Exceptions\ForbiddenException($e->getMessage());
937
        }
938
939
        try {
940
            $this->userService->assignUserToUserGroup($user, $userGroup);
941
        } catch (ApiExceptions\NotFoundException $e) {
942
            throw new Exceptions\ForbiddenException($e->getMessage());
943
        }
944
945
        $userGroups = $this->userService->loadUserGroupsOfUser($user);
946
        $restUserGroups = array();
947
        foreach ($userGroups as $userGroup) {
948
            $userGroupContentInfo = $userGroup->getVersionInfo()->getContentInfo();
949
            $userGroupLocation = $this->locationService->loadLocation($userGroupContentInfo->mainLocationId);
950
            $contentType = $this->contentTypeService->loadContentType($userGroupContentInfo->contentTypeId);
951
952
            $restUserGroups[] = new Values\RestUserGroup(
953
                $userGroup,
954
                $contentType,
955
                $userGroupContentInfo,
956
                $userGroupLocation,
957
                $this->contentService->loadRelations($userGroup->getVersionInfo())
958
            );
959
        }
960
961
        return new Values\UserGroupRefList(
962
            $restUserGroups,
963
            $this->router->generate(
964
                'ezpublish_rest_loadUserGroupsOfUser',
965
                array('userId' => $userId)
966
            ),
967
            $userId
968
        );
969
    }
970
971
    /**
972
     * Creates a new session based on the credentials provided as POST parameters.
973
     *
974
     * @throws \eZ\Publish\Core\Base\Exceptions\UnauthorizedException If the login or password are incorrect or invalid CSRF
975
     *
976
     * @return Values\UserSession|Values\Conflict
977
     */
978
    public function createSession(Request $request)
979
    {
980
        /** @var $sessionInput \eZ\Publish\Core\REST\Server\Values\SessionInput */
981
        $sessionInput = $this->inputDispatcher->parse(
982
            new Message(
983
                array('Content-Type' => $request->headers->get('Content-Type')),
984
                $request->getContent()
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() targeting Symfony\Component\HttpFo...n\Request::getContent() can also be of type resource; however, eZ\Publish\Core\REST\Common\Message::__construct() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
985
            )
986
        );
987
        $request->attributes->set('username', $sessionInput->login);
988
        $request->attributes->set('password', $sessionInput->password);
989
990
        try {
991
            $session = $request->getSession();
992
            if ($session->isStarted() && $this->hasStoredCsrfToken()) {
993
                $this->checkCsrfToken($request);
994
            }
995
996
            $authenticator = $this->container->get('ezpublish_rest.session_authenticator');
997
            $token = $authenticator->authenticate($request);
998
            $csrfToken = $this->getCsrfToken();
999
1000
            return new Values\UserSession(
1001
                $token->getUser()->getAPIUser(),
1002
                $session->getName(),
1003
                $session->getId(),
1004
                $csrfToken,
1005
                !$token->hasAttribute('isFromSession')
1006
            );
1007
        } catch (Exceptions\UserConflictException $e) {
1008
            // Already logged in with another user, this will be converted to HTTP status 409
1009
            return new Values\Conflict();
1010
        } catch (AuthenticationException $e) {
1011
            throw new UnauthorizedException('Invalid login or password', $request->getPathInfo());
1012
        } catch (AccessDeniedException $e) {
1013
            throw new UnauthorizedException($e->getMessage(), $request->getPathInfo());
1014
        }
1015
    }
1016
1017
    /**
1018
     * Refresh given session.
1019
     *
1020
     * @param string $sessionId
1021
     *
1022
     * @throws \eZ\Publish\Core\Base\Exceptions\UnauthorizedException If the CSRF token is missing or invalid.
1023
     *
1024
     * @return \eZ\Publish\Core\REST\Server\Values\UserSession
1025
     */
1026
    public function refreshSession($sessionId, Request $request)
1027
    {
1028
        $session = $request->getSession();
1029
1030 View Code Duplication
        if ($session === null || !$session->isStarted() || $session->getId() != $sessionId || !$this->hasStoredCsrfToken()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1031
            $response = $this->container->get('ezpublish_rest.session_authenticator')->logout($request);
1032
            $response->setStatusCode(404);
1033
1034
            return $response;
1035
        }
1036
1037
        $this->checkCsrfToken($request);
1038
1039
        return new Values\UserSession(
1040
            $this->repository->getCurrentUser(),
0 ignored issues
show
Deprecated Code introduced by
The method eZ\Publish\API\Repositor...itory::getCurrentUser() has been deprecated with message: since 6.6, to be removed. Use PermissionResolver::getCurrentUserReference() instead. Get current user. Loads the full user object if not already loaded, if you only need to know user id use {@see getCurrentUserReference()}

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
1041
            $session->getName(),
1042
            $session->getId(),
1043
            $request->headers->get('X-CSRF-Token'),
1044
            false
1045
        );
1046
    }
1047
1048
    /**
1049
     * Deletes given session.
1050
     *
1051
     * @param string $sessionId
1052
     *
1053
     * @return Values\DeletedUserSession|\Symfony\Component\HttpFoundation\Response
1054
     *
1055
     * @throws \eZ\Publish\Core\Base\Exceptions\UnauthorizedException If the CSRF token is missing or invalid.
1056
     */
1057
    public function deleteSession($sessionId, Request $request)
1058
    {
1059
        $session = $request->getSession();
1060
1061 View Code Duplication
        if (!$session->isStarted() || $session->getId() != $sessionId || !$this->hasStoredCsrfToken()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1062
            $response = $this->container->get('ezpublish_rest.session_authenticator')->logout($request);
1063
            $response->setStatusCode(404);
1064
1065
            return $response;
1066
        }
1067
1068
        $this->checkCsrfToken($request);
1069
1070
        return new Values\DeletedUserSession(
1071
            $this->container->get('ezpublish_rest.session_authenticator')->logout($request)
1072
        );
1073
    }
1074
1075
    /**
1076
     * Extracts and returns an item id from a path, e.g. /1/2/58 => 58.
1077
     *
1078
     * @param string $path
1079
     *
1080
     * @return mixed
1081
     */
1082
    private function extractLocationIdFromPath($path)
1083
    {
1084
        $pathParts = explode('/', $path);
1085
1086
        return array_pop($pathParts);
1087
    }
1088
1089
    /**
1090
     * Tests if a CSRF token is stored.
1091
     *
1092
     * @return bool
1093
     */
1094
    private function hasStoredCsrfToken()
1095
    {
1096
        if (!isset($this->csrfTokenStorage)) {
1097
            return true;
1098
        }
1099
1100
        return $this->csrfTokenStorage->hasToken(
1101
            $this->container->getParameter('ezpublish_rest.csrf_token_intention')
1102
        );
1103
    }
1104
1105
    public function setTokenStorage(TokenStorageInterface $csrfTokenStorage)
1106
    {
1107
        $this->csrfTokenStorage = $csrfTokenStorage;
1108
    }
1109
1110
    /**
1111
     * Checks the presence / validity of the CSRF token.
1112
     *
1113
     * @param Request $request
1114
     *
1115
     * @throws UnauthorizedException if the token is missing or invalid.
1116
     */
1117
    private function checkCsrfToken(Request $request)
1118
    {
1119
        $csrfTokenManager = $this->container->get(
1120
            'security.csrf.token_manager',
1121
            ContainerInterface::NULL_ON_INVALID_REFERENCE
1122
        );
1123
1124
        if ($csrfTokenManager === null) {
1125
            return;
1126
        }
1127
1128
        $exception = new UnauthorizedException(
1129
            'Missing or invalid CSRF token',
1130
            $request->getMethod() . ' ' . $request->getPathInfo()
1131
        );
1132
1133
        if (!$request->headers->has('X-CSRF-Token')) {
1134
            throw $exception;
1135
        }
1136
1137
        $csrfToken = new CsrfToken(
1138
            $this->container->getParameter('ezpublish_rest.csrf_token_intention'),
1139
            $request->headers->get('X-CSRF-Token')
1140
        );
1141
1142
        if (!$csrfTokenManager->isTokenValid($csrfToken)) {
1143
            throw $exception;
1144
        }
1145
    }
1146
1147
    /**
1148
     * Returns the csrf token for REST. The token is generated if it doesn't exist.
1149
     *
1150
     * @return string The csrf token, or an empty string if csrf check is disabled.
1151
     */
1152
    private function getCsrfToken()
1153
    {
1154
        $csrfTokenManager = $this->container->get(
1155
            'security.csrf.token_manager',
1156
            ContainerInterface::NULL_ON_INVALID_REFERENCE
1157
        );
1158
1159
        if ($csrfTokenManager === null) {
1160
            return '';
1161
        }
1162
1163
        return $csrfTokenManager->getToken(
1164
            $this->container->getParameter('ezpublish_rest.csrf_token_intention')
1165
        )->getValue();
1166
    }
1167
}
1168