From 25c91e189d15ce8b39fd9e00c17fda1b88954d24 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 11 Sep 2025 13:55:18 -0300 Subject: [PATCH 1/7] Add oidc/session/whoami endpoint --- openstackid/_config/routes.yml | 1 + .../restfull_api/OIDCSessionWhoAmIApi.php | 155 ++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php diff --git a/openstackid/_config/routes.yml b/openstackid/_config/routes.yml index 9379bbb60..e67c6dd65 100644 --- a/openstackid/_config/routes.yml +++ b/openstackid/_config/routes.yml @@ -4,4 +4,5 @@ Name: openstackidroutes Director: rules: 'OpenStackIdAuthenticator': 'OpenStackIdAuthenticator' + 'oidc/session/whoami': 'OIDCSessionWhoAmIApi' diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php new file mode 100644 index 000000000..29a9decbe --- /dev/null +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -0,0 +1,155 @@ + 'index', + ]; + + /** + * @var array + */ + private static $allowed_actions = [ + 'index', + ]; + + /** + * @return bool + */ + protected function isApiCall() + { + $request = $this->getRequest(); + if (is_null($request)) + return false; + return true; + } + + /** + * @return bool + */ + protected function authorize() + { + return true; + } + + /** + * @return bool + */ + protected function authenticate() + { + return true; + } + + /** + * Bootstrap OIDC session + * @param SS_HTTPRequest $request + * @return SS_HTTPResponse + */ + public function index(SS_HTTPRequest $request) + { + try { + $response = $this->validateRequestData($request); + if ($response instanceof SS_HTTPResponse) { + return $response; + } + + $member = Member::currentUser(); + + $response = new SS_HTTPResponse(); + $response->addHeader('Content-Type', 'application/json'); + + if (!$member) { + $response->setStatusCode(404); + $response->setBody(json_encode(['message' => 'No authenticated user found'])); + } + else + { + $response->setStatusCode(200); + $response->setBody(json_encode([ + 'user_id' => $member->ID, + 'email' => $member->Email, + ])); + } + return $response; + + } catch (EntityValidationException $ex1) { + SS_Log::log($ex1, SS_Log::WARN); + return $this->validationError($ex1->getMessages()); + } catch (Exception $ex) { + SS_Log::log($ex, SS_Log::ERR); + return $this->serverError(); + } + } + + /** + * Validate request data + * @param SS_HTTPRequest $request + * @return bool|SS_HTTPResponse + */ + private function validateRequestData(SS_HTTPRequest $request) + { + // Check if request method is POST + if (!$request->isPOST()) { + return $this->methodNotAllowed(); + } + + // Check Content-Type header + $contentType = $request->getHeader('Content-Type'); + if (strpos($contentType, 'application/json') === false) { + return $this->validationError(['Content-Type must be application/json']); + } + + // Check X-CSRF-Token header + $csrfToken = $request->getHeader('X-CSRF-Token') ?: $request->getHeader('X-Csrf-Token'); + if (empty($csrfToken)) { + return $this->validationError(['X-CSRF-Token header is required', "headers" => $request->getHeaders()]); + } + + // Check X-CSRF-Token header value + if ($csrfToken !== $this->getSecurityToken()) { + return $this->badRequest('X-CSRF-Token header is invalid'); + } + + return true; + } + + /** + * Return method not allowed response + * @param string $message + * @return SS_HTTPResponse + */ + protected function methodNotAllowed() + { + return parent::methodNotAllowed() + ->setBody(json_encode("Only POST requests are allowed")) + ->addHeader('Allow', 'POST'); + } + + protected function getSecurityToken() + { + return SecurityToken::inst() ? SecurityToken::inst()->getValue() : null; + } +} \ No newline at end of file From 4ec99ba765ce2cb8e4e251f5a0d5be13e0663c89 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 11 Sep 2025 15:00:01 -0300 Subject: [PATCH 2/7] Add badRequest method --- .../restfull_api/OIDCSessionWhoAmIApi.php | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index 29a9decbe..52937d65d 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -76,24 +76,17 @@ public function index(SS_HTTPRequest $request) return $response; } - $member = Member::currentUser(); - - $response = new SS_HTTPResponse(); - $response->addHeader('Content-Type', 'application/json'); - - if (!$member) { - $response->setStatusCode(404); - $response->setBody(json_encode(['message' => 'No authenticated user found'])); - } - else - { - $response->setStatusCode(200); - $response->setBody(json_encode([ - 'user_id' => $member->ID, - 'email' => $member->Email, - ])); - } - return $response; + $member = Member::currentUser(); + + if (!$member) { + $response = $this->notFound('No authenticated user found'); + } else { + $response = $this->ok([ + 'user_id' => $member->ID, + 'email' => $member->Email, + ]); + } + return $response; } catch (EntityValidationException $ex1) { SS_Log::log($ex1, SS_Log::WARN); @@ -148,6 +141,21 @@ protected function methodNotAllowed() ->addHeader('Allow', 'POST'); } + + /** + * Return method bad request response + * @param string $error + * @return SS_HTTPResponse + */ + protected function badRequest(string $error) + { + $response = new SS_HTTPResponse(); + $response->setStatusCode(400); + $response->addHeader('Content-Type', 'application/json'); + $response->setBody(json_encode(["error" => $error])); + return $response; + } + protected function getSecurityToken() { return SecurityToken::inst() ? SecurityToken::inst()->getValue() : null; From 70bf743822a14b3aa9f953673a107556a7a440d9 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 11 Sep 2025 18:25:58 -0300 Subject: [PATCH 3/7] Add Session handler --- .../code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index 52937d65d..851386916 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -76,7 +76,8 @@ public function index(SS_HTTPRequest $request) return $response; } - $member = Member::currentUser(); + $memberID = Session::get('loggedInAs'); + $member = $memberID ? Member::get()->filter(['ID' => $memberID])->first() : null; if (!$member) { $response = $this->notFound('No authenticated user found'); @@ -122,7 +123,7 @@ private function validateRequestData(SS_HTTPRequest $request) } // Check X-CSRF-Token header value - if ($csrfToken !== $this->getSecurityToken()) { + if ($csrfToken !== Session::get('SecurityID')) { return $this->badRequest('X-CSRF-Token header is invalid'); } From daf7b2a307b221b2255c6239e3d12320f41f62be Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 11 Sep 2025 18:27:32 -0300 Subject: [PATCH 4/7] Simplify call --- .../code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index 851386916..067e7bc90 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -76,9 +76,7 @@ public function index(SS_HTTPRequest $request) return $response; } - $memberID = Session::get('loggedInAs'); - $member = $memberID ? Member::get()->filter(['ID' => $memberID])->first() : null; - + $member = Member::currentUser(); if (!$member) { $response = $this->notFound('No authenticated user found'); } else { From 47918ee54211f17900ea0de79728e9a8f8c178fa Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Fri, 12 Sep 2025 10:48:44 -0300 Subject: [PATCH 5/7] Switch allowed verb from POST to GET --- .../code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index 067e7bc90..15b84f3e5 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -104,7 +104,7 @@ public function index(SS_HTTPRequest $request) private function validateRequestData(SS_HTTPRequest $request) { // Check if request method is POST - if (!$request->isPOST()) { + if (!$request->isGET()) { return $this->methodNotAllowed(); } @@ -136,8 +136,8 @@ private function validateRequestData(SS_HTTPRequest $request) protected function methodNotAllowed() { return parent::methodNotAllowed() - ->setBody(json_encode("Only POST requests are allowed")) - ->addHeader('Allow', 'POST'); + ->setBody(json_encode("Only GET requests are allowed")) + ->addHeader('Allow', 'GET'); } From 6c5b3c762af8a266baf231fdef5dbd4c64367a05 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Fri, 12 Sep 2025 11:51:59 -0300 Subject: [PATCH 6/7] Remove check of content type header --- .../code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index 15b84f3e5..e5822f66d 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -108,12 +108,6 @@ private function validateRequestData(SS_HTTPRequest $request) return $this->methodNotAllowed(); } - // Check Content-Type header - $contentType = $request->getHeader('Content-Type'); - if (strpos($contentType, 'application/json') === false) { - return $this->validationError(['Content-Type must be application/json']); - } - // Check X-CSRF-Token header $csrfToken = $request->getHeader('X-CSRF-Token') ?: $request->getHeader('X-Csrf-Token'); if (empty($csrfToken)) { From ea4ed38f88d767e0e9c330d63c9a848ca17bc871 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 15 Sep 2025 15:03:56 -0300 Subject: [PATCH 7/7] Change verb from POST to GET in url_handlers attr. --- .../code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php index e5822f66d..46dcb5296 100644 --- a/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php +++ b/openstackid/code/interfaces/restfull_api/OIDCSessionWhoAmIApi.php @@ -26,7 +26,7 @@ final class OIDCSessionWhoAmIApi extends AbstractRestfulJsonApi * @var array */ private static $url_handlers = [ - 'POST ' => 'index', + 'GET ' => 'index', ]; /**