Skip to content

Commit 45c5a77

Browse files
authored
IBX-4043: Added API current user / session routes
2 parents 1186c8b + d791210 commit 45c5a77

File tree

8 files changed

+135
-10
lines changed

8 files changed

+135
-10
lines changed

src/bundle/Resources/config/routing.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,11 @@ ibexa.rest.load_user:
915915
requirements:
916916
userId: \d+
917917

918+
ibexa.rest.current_user:
919+
path: /user/current
920+
controller: Ibexa\Rest\Server\Controller\User::redirectToCurrentUser
921+
methods: [GET]
922+
918923
ibexa.rest.update_user:
919924
path: /user/users/{userId}
920925
defaults:
@@ -1121,6 +1126,13 @@ ibexa.rest.create_session:
11211126
csrf_protection: false
11221127
methods: [POST]
11231128

1129+
ibexa.rest.check_session:
1130+
path: /user/sessions/current
1131+
controller: Ibexa\Rest\Server\Controller\SessionController::checkSessionAction
1132+
methods: [GET]
1133+
defaults:
1134+
csrf_protection: false
1135+
11241136
ibexa.rest.delete_session:
11251137
path: /user/sessions/{sessionId}
11261138
defaults:

src/lib/Server/Controller/SessionController.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,33 @@ public function refreshSessionAction($sessionId, Request $request)
138138
);
139139
}
140140

141+
/**
142+
* @return \Ibexa\Rest\Server\Values\UserSession|\Symfony\Component\HttpFoundation\Response
143+
*/
144+
public function checkSessionAction(Request $request)
145+
{
146+
$session = $request->getSession();
147+
148+
if ($session === null || !$session->isStarted()) {
149+
$response = $this->getAuthenticator()->logout($request);
150+
$response->setStatusCode(404);
151+
152+
return $response;
153+
}
154+
155+
$currentUser = $this->userService->loadUser(
156+
$this->permissionResolver->getCurrentUserReference()->getUserId()
157+
);
158+
159+
return new Values\UserSession(
160+
$currentUser,
161+
$session->getName(),
162+
$session->getId(),
163+
$request->headers->get('X-CSRF-Token'),
164+
false
165+
);
166+
}
167+
141168
/**
142169
* Deletes given session.
143170
*

src/lib/Server/Controller/User.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
use Ibexa\Rest\Server\Exceptions\ForbiddenException;
2828
use Ibexa\Rest\Server\Values;
2929
use Symfony\Component\HttpFoundation\Request;
30+
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
31+
use Symfony\Component\Security\Core\User\UserInterface;
3032
use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface;
3133

3234
/**
@@ -215,6 +217,22 @@ function () use ($userContentInfo) {
215217
);
216218
}
217219

220+
/**
221+
* @see \Symfony\Component\Security\Http\Controller\UserValueResolver
222+
*/
223+
public function redirectToCurrentUser(?UserInterface $user): Values\TemporaryRedirect
224+
{
225+
if ($user === null) {
226+
throw new UnauthorizedHttpException('', 'Not logged in.');
227+
}
228+
229+
$userReference = $this->permissionResolver->getCurrentUserReference();
230+
231+
return new Values\TemporaryRedirect(
232+
$this->router->generate('ibexa.rest.load_user', ['userId' => $userReference->getUserId()])
233+
);
234+
}
235+
218236
/**
219237
* Create a new user group under the given parent
220238
* To create a top level group use /user/groups/1/5/subgroups.

src/lib/Server/Values/UserSession.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class UserSession extends RestValue
4949
*/
5050
public $exists;
5151

52+
public bool $created;
53+
5254
/**
5355
* @param \Ibexa\Contracts\Core\Repository\Values\User\User $user
5456
* @param string $sessionName

tests/bundle/Functional/HttpOptionsTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ public function testHttpOptions(string $route, array $expectedMethods): void
3434

3535
self::assertHttpResponseHasHeader($response, 'Allow');
3636
$actualMethods = explode(',', $response->getHeader('Allow')[0]);
37-
self::assertEquals($expectedMethods, $actualMethods);
37+
self::assertEqualsCanonicalizing($expectedMethods, $actualMethods);
3838
}
3939

4040
/**
4141
* Data provider for testHttpOptions.
4242
*
4343
* @see testHttpOptions
4444
*
45-
* @return array Data Provider sets
45+
* @return array<array{non-empty-string, array<non-empty-string>}> Data Provider sets
4646
*/
4747
public function providerForTestHttpOptions(): array
4848
{
@@ -96,6 +96,7 @@ public function providerForTestHttpOptions(): array
9696
['/user/roles/1/draft', ['GET', 'PATCH', 'PUBLISH', 'DELETE']],
9797
['/user/roles/1/policies', ['GET', 'POST', 'DELETE']],
9898
['/user/roles/1/policies/328', ['GET', 'PATCH', 'DELETE']],
99+
['/user/current', ['GET']],
99100
['/user/users', ['HEAD', 'GET']],
100101
['/user/users/10', ['GET', 'PATCH', 'DELETE']],
101102
['/user/users/10/groups', ['GET', 'POST']],

tests/bundle/Functional/SessionTest.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,47 @@ public function testDeleteSessionExpired($session)
145145
self::assertHttpResponseDeletesSessionCookie($session, $response);
146146
}
147147

148+
/**
149+
* @depends testCreateSession
150+
*/
151+
public function testCheckSession(): void
152+
{
153+
$session = $this->login();
154+
$request = $this->createHttpRequest(
155+
'GET',
156+
'/api/ibexa/v2/user/sessions/current',
157+
'',
158+
'Session+json',
159+
'',
160+
[
161+
'Cookie' => sprintf('%s=%s', $session->name, $session->identifier),
162+
'X-CSRF-Token' => $session->csrfToken,
163+
]
164+
);
165+
$response = $this->sendHttpRequest($request);
166+
self::assertHttpResponseCodeEquals($response, 200);
167+
$contents = $response->getBody()->getContents();
168+
$data = json_decode($contents, true, JSON_THROW_ON_ERROR);
169+
self::assertArrayHasKey('Session', $data);
170+
}
171+
172+
/**
173+
* @depends testCreateSession
174+
*/
175+
public function testCheckSessionWithoutOne(): void
176+
{
177+
$request = $this->createHttpRequest(
178+
'GET',
179+
'/api/ibexa/v2/user/sessions/current',
180+
'',
181+
'Session+json'
182+
);
183+
$response = $this->sendHttpRequest($request);
184+
self::assertHttpResponseCodeEquals($response, 404);
185+
$contents = $response->getBody()->getContents();
186+
self::assertEmpty($contents);
187+
}
188+
148189
/**
149190
* @param \stdClass $session
150191
*

tests/bundle/Functional/TestCase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,13 +394,13 @@ protected function addTestSuffix($string)
394394
*
395395
* @return \stdClass an object with the name, identifier, csrftoken properties
396396
*/
397-
protected function login()
397+
protected function login(): \stdClass
398398
{
399399
$request = $this->createAuthenticationHttpRequest($this->getLoginUsername(), $this->getLoginPassword());
400400
$response = $this->sendHttpRequest($request);
401401
self::assertHttpResponseCodeEquals($response, 201);
402402

403-
return json_decode($response->getBody())->Session;
403+
return json_decode($response->getBody()->getContents(), false, JSON_THROW_ON_ERROR)->Session;
404404
}
405405

406406
/**

tests/bundle/Functional/UserTest.php

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
class UserTest extends RESTFunctionalTestCase
1212
{
13+
private const HEADER_LOCATION = 'Location';
14+
1315
/**
1416
* Covers GET /user/groups/root.
1517
*/
@@ -59,9 +61,9 @@ public function testCreateUserGroup()
5961
$response = $this->sendHttpRequest($request);
6062

6163
self::assertHttpResponseCodeEquals($response, 201);
62-
self::assertHttpResponseHasHeader($response, 'Location');
64+
self::assertHttpResponseHasHeader($response, self::HEADER_LOCATION);
6365

64-
$href = $response->getHeader('Location')[0];
66+
$href = $response->getHeader(self::HEADER_LOCATION)[0];
6567
$this->addCreatedElement($href);
6668

6769
return $href;
@@ -153,9 +155,9 @@ public function testCreateUser($userGroupHref)
153155
$response = $this->sendHttpRequest($request);
154156

155157
self::assertHttpResponseCodeEquals($response, 201);
156-
self::assertHttpResponseHasHeader($response, 'Location');
158+
self::assertHttpResponseHasHeader($response, self::HEADER_LOCATION);
157159

158-
$href = $response->getHeader('Location')[0];
160+
$href = $response->getHeader(self::HEADER_LOCATION)[0];
159161
$this->addCreatedElement($href);
160162

161163
return $href;
@@ -174,6 +176,28 @@ public function testLoadUser($userHref)
174176
self::assertHttpResponseCodeEquals($response, 200);
175177
}
176178

179+
public function testRedirectToCurrentUser(): void
180+
{
181+
$request = $this->createHttpRequest('GET', '/api/ibexa/v2/user/current');
182+
183+
$response = $this->sendHttpRequest($request);
184+
185+
self::assertHttpResponseCodeEquals($response, 307);
186+
self::assertHttpResponseHasHeader($response, self::HEADER_LOCATION, '/api/ibexa/v2/user/users/14');
187+
}
188+
189+
public function testRedirectToCurrentUserWhenNotLoggedIn(): void
190+
{
191+
$request = $this
192+
->createHttpRequest('GET', '/api/ibexa/v2/user/current')
193+
->withoutHeader('Cookie');
194+
195+
$response = $this->sendHttpRequest($request);
196+
197+
self::assertHttpResponseCodeEquals($response, 401);
198+
self::assertFalse($response->hasHeader(self::HEADER_LOCATION));
199+
}
200+
177201
/**
178202
* @depends testCreateUser
179203
* Covers PATCH /user/users/{userId}
@@ -394,9 +418,9 @@ public function testCreateSession()
394418
$response = $this->sendHttpRequest($request);
395419

396420
self::assertHttpResponseCodeEquals($response, 201);
397-
self::assertHttpResponseHasHeader($response, 'Location');
421+
self::assertHttpResponseHasHeader($response, self::HEADER_LOCATION);
398422

399-
$href = $response->getHeader('Location')[0];
423+
$href = $response->getHeader(self::HEADER_LOCATION)[0];
400424
$this->addCreatedElement($href);
401425

402426
return $href;

0 commit comments

Comments
 (0)