Skip to content

Commit 308911c

Browse files
tischsoicbarw4
authored andcommitted
split controllers - one action per controller: Session without services
1 parent 4f0e722 commit 308911c

File tree

6 files changed

+641
-1
lines changed

6 files changed

+641
-1
lines changed

src/bundle/Resources/config/routing.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ ibexa.rest.create_session:
11311131

11321132
ibexa.rest.check_session:
11331133
path: /user/sessions/current
1134-
controller: Ibexa\Rest\Server\Controller\SessionController::checkSessionAction
1134+
controller: Ibexa\Rest\Server\Controller\Session\SessionCheckController::checkSessionAction
11351135
methods: [GET]
11361136
defaults:
11371137
csrf_protection: false
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Rest\Server\Controller\Session;
10+
11+
use ApiPlatform\Metadata\Delete;
12+
use ApiPlatform\Metadata\Get;
13+
use ApiPlatform\Metadata\Post;
14+
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
15+
use ApiPlatform\OpenApi\Model;
16+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
17+
use Ibexa\Contracts\Core\Repository\UserService;
18+
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
19+
use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException;
20+
use Ibexa\Rest\Server\Controller;
21+
use Ibexa\Rest\Server\Exceptions;
22+
use Ibexa\Rest\Server\Security\CsrfTokenManager;
23+
use Ibexa\Rest\Server\Values;
24+
use Ibexa\Rest\Value as RestValue;
25+
use Symfony\Component\HttpFoundation\Request;
26+
use Symfony\Component\HttpFoundation\Response;
27+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface as SecurityTokenStorageInterface;
28+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
29+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
30+
use Symfony\Component\Security\Csrf\CsrfToken;
31+
32+
class SessionBaseController extends Controller
33+
{
34+
public function __construct(
35+
protected readonly PermissionResolver $permissionResolver,
36+
protected readonly UserService $userService,
37+
protected readonly CsrfTokenManager $csrfTokenManager,
38+
protected readonly SecurityTokenStorageInterface $securityTokenStorage,
39+
protected readonly string $csrfTokenIntention,
40+
protected readonly ConfigResolverInterface $configResolver,
41+
) {
42+
}
43+
44+
protected function hasStoredCsrfToken(): bool
45+
{
46+
return $this->csrfTokenManager->hasToken($this->csrfTokenIntention);
47+
}
48+
49+
/**
50+
* Checks the presence / validity of the CSRF token.
51+
*
52+
* @throws \Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException if the token is missing or invalid
53+
*/
54+
protected function checkCsrfToken(Request $request): void
55+
{
56+
if (!$request->headers->has('X-CSRF-Token')) {
57+
throw $this->createInvalidCsrfTokenException($request);
58+
}
59+
60+
$csrfToken = new CsrfToken(
61+
$this->csrfTokenIntention,
62+
$request->headers->get('X-CSRF-Token')
63+
);
64+
65+
if (!$this->csrfTokenManager->isTokenValid($csrfToken)) {
66+
throw $this->createInvalidCsrfTokenException($request);
67+
}
68+
}
69+
70+
protected function getCsrfToken(): string
71+
{
72+
return $this->csrfTokenManager->getToken($this->csrfTokenIntention)->getValue();
73+
}
74+
75+
protected function createInvalidCsrfTokenException(Request $request): UnauthorizedException
76+
{
77+
return new UnauthorizedException('Missing or invalid CSRF token');
78+
}
79+
80+
protected function logout(Request $request): Response
81+
{
82+
$path = '/';
83+
$domain = null;
84+
85+
$session = $this->configResolver->getParameter('session');
86+
if (array_key_exists('cookie_domain', $session)) {
87+
$domain = $session['cookie_domain'];
88+
}
89+
90+
if (array_key_exists('cookie_path', $session)) {
91+
$path = $session['cookie_path'];
92+
}
93+
94+
$response = new Response();
95+
$requestSession = $request->getSession();
96+
97+
$response->headers->clearCookie(
98+
$requestSession->getName(),
99+
$path,
100+
$domain
101+
);
102+
103+
$response->setStatusCode(404);
104+
$requestSession->clear();
105+
106+
return $response;
107+
}
108+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
/**
4+
* @copyright Copyright (C) Ibexa AS. All rights reserved.
5+
* @license For full copyright and license information view LICENSE file distributed with this source code.
6+
*/
7+
declare(strict_types=1);
8+
9+
namespace Ibexa\Rest\Server\Controller\Session;
10+
11+
use ApiPlatform\Metadata\Delete;
12+
use ApiPlatform\Metadata\Get;
13+
use ApiPlatform\Metadata\Post;
14+
use ApiPlatform\OpenApi\Factory\OpenApiFactory;
15+
use ApiPlatform\OpenApi\Model;
16+
use Ibexa\Contracts\Core\Repository\PermissionResolver;
17+
use Ibexa\Contracts\Core\Repository\UserService;
18+
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
19+
use Ibexa\Contracts\Rest\Exceptions\UnauthorizedException;
20+
use Ibexa\Rest\Server\Controller;
21+
use Ibexa\Rest\Server\Exceptions;
22+
use Ibexa\Rest\Server\Security\CsrfTokenManager;
23+
use Ibexa\Rest\Server\Values;
24+
use Ibexa\Rest\Value as RestValue;
25+
use Symfony\Component\HttpFoundation\Request;
26+
use Symfony\Component\HttpFoundation\Response;
27+
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface as SecurityTokenStorageInterface;
28+
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
29+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
30+
use Symfony\Component\Security\Csrf\CsrfToken;
31+
32+
#[Get(
33+
uriTemplate: '/user/sessions/current',
34+
name: 'Get current session',
35+
openapi: new Model\Operation(
36+
summary: 'Get current user session, if any.',
37+
tags: [
38+
'User Session',
39+
],
40+
parameters: [
41+
new Model\Parameter(
42+
name: 'Cookie',
43+
in: 'header',
44+
required: true,
45+
description: 'Only needed for session\'s checking {sessionName}={sessionID}.',
46+
schema: [
47+
'type' => 'string',
48+
],
49+
),
50+
new Model\Parameter(
51+
name: 'Accept',
52+
in: 'header',
53+
required: true,
54+
description: 'If set, the session is returned in XML or JSON format.',
55+
schema: [
56+
'type' => 'string',
57+
],
58+
),
59+
],
60+
responses: [
61+
Response::HTTP_OK => [
62+
'description' => 'User is currently logged in and has a valid session.',
63+
'content' => [
64+
'application/vnd.ibexa.api.Session+xml' => [
65+
'schema' => [
66+
'$ref' => '#/components/schemas/Session',
67+
],
68+
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/POST/Session.xml.example',
69+
],
70+
'application/vnd.ibexa.api.Session+json' => [
71+
'schema' => [
72+
'$ref' => '#/components/schemas/SessionWrapper',
73+
],
74+
'x-ibexa-example-file' => '@IbexaRestBundle/Resources/api_platform/examples/user/sessions/session_id/refresh/POST/Session.json.example',
75+
],
76+
],
77+
],
78+
Response::HTTP_NOT_FOUND => [
79+
'description' => 'User does not have a valid session, or it has expired.',
80+
],
81+
],
82+
),
83+
)]
84+
/**
85+
* @internal
86+
*/
87+
final class SessionCheckController extends SessionBaseController
88+
{
89+
/**
90+
* @return \Ibexa\Rest\Server\Values\UserSession|\Symfony\Component\HttpFoundation\Response
91+
*/
92+
public function checkSessionAction(Request $request)
93+
{
94+
$session = $request->getSession();
95+
if ($session === null || !$session->isStarted()) {
96+
return $this->logout($request);
97+
}
98+
99+
$currentUser = $this->userService->loadUser(
100+
$this->permissionResolver->getCurrentUserReference()->getUserId()
101+
);
102+
103+
return new Values\UserSession(
104+
$currentUser,
105+
$session->getName(),
106+
$session->getId(),
107+
$this->getCsrfToken(),
108+
false
109+
);
110+
}
111+
}

0 commit comments

Comments
 (0)