From 6fd3c287f5348df1be015e4b2b0b970b4769c5ad Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 11 Jul 2022 22:38:01 +0200 Subject: [PATCH] Add controller for validate-endpoint --- public/validate.php | 121 --------------------------- routing/routes/routes.yml | 3 + src/Controller/Cas10.php | 167 ++++++++++++++++++++++++++++++++++++++ src/Utils/Url.php | 58 +++++++++++++ 4 files changed, 228 insertions(+), 121 deletions(-) delete mode 100644 public/validate.php create mode 100644 routing/routes/routes.yml create mode 100644 src/Controller/Cas10.php create mode 100644 src/Utils/Url.php diff --git a/public/validate.php b/public/validate.php deleted file mode 100644 index 3f85721..0000000 --- a/public/validate.php +++ /dev/null @@ -1,121 +0,0 @@ -getOptionalValue( - 'ticketstore', - ['class' => 'casserver:FileSystemTicketStore'] - ); - $ticketStoreClass = \SimpleSAML\Module::resolveClass($ticketStoreConfig['class'], 'Cas\Ticket'); - /** @psalm-suppress InvalidStringClass */ - $ticketStore = new $ticketStoreClass($casconfig); - - $ticketFactoryClass = \SimpleSAML\Module::resolveClass('casserver:TicketFactory', 'Cas\Ticket'); - /** @psalm-suppress InvalidStringClass */ - $ticketFactory = new $ticketFactoryClass($casconfig); - - $serviceTicket = $ticketStore->getTicket($_GET['ticket']); - - if (!is_null($serviceTicket) && $ticketFactory->isServiceTicket($serviceTicket)) { - $ticketStore->deleteTicket($_GET['ticket']); - - $usernameField = $casconfig->getOptionalValue('attrname', 'eduPersonPrincipalName'); - - if ( - !$ticketFactory->isExpired($serviceTicket) && - sanitize($serviceTicket['service']) == sanitize($_GET['service']) && - (!$forceAuthn || $serviceTicket['forceAuthn']) && - array_key_exists($usernameField, $serviceTicket['attributes']) - ) { - echo $protocol->getValidateSuccessResponse($serviceTicket['attributes'][$usernameField][0]); - } else { - if (!array_key_exists($usernameField, $serviceTicket['attributes'])) { - \SimpleSAML\Logger::error(sprintf( - 'casserver:validate: internal server error. Missing user name attribute: %s', - var_export($usernameField, true) - )); - - echo $protocol->getValidateFailureResponse(); - } else { - if ($ticketFactory->isExpired($serviceTicket)) { - $message = 'Ticket has ' . var_export($_GET['ticket'], true) . ' expired'; - } else { - if (sanitize($serviceTicket['service']) == sanitize($_GET['service'])) { - $message = 'Mismatching service parameters: expected ' . - var_export($serviceTicket['service'], true) . - ' but was: ' . var_export($_GET['service'], true); - } else { - $message = 'Ticket was issue from single sign on session'; - } - } - \SimpleSAML\Logger::debug('casserver:' . $message); - - echo $protocol->getValidateFailureResponse(); - } - } - } else { - if (is_null($serviceTicket)) { - $message = 'ticket: ' . var_export($_GET['ticket'], true) . ' not recognized'; - } else { - $message = 'ticket: ' . var_export($_GET['ticket'], true) . ' is not a service ticket'; - } - - \SimpleSAML\Logger::debug('casserver:' . $message); - - echo $protocol->getValidateFailureResponse(); - } - } catch (\Exception $e) { - \SimpleSAML\Logger::error('casserver:validate: internal server error. ' . var_export($e->getMessage(), true)); - - echo $protocol->getValidateFailureResponse(); - } -} else { - if (!array_key_exists('service', $_GET)) { - $message = 'Missing service parameter: [service]'; - } else { - $message = 'Missing ticket parameter: [ticket]'; - } - - SimpleSAML\Logger::debug('casserver:' . $message); - - echo $protocol->getValidateFailureResponse(); -} diff --git a/routing/routes/routes.yml b/routing/routes/routes.yml new file mode 100644 index 0000000..9ce9b3c --- /dev/null +++ b/routing/routes/routes.yml @@ -0,0 +1,3 @@ +casserver-cas10-validate: + path: /validate + defaults: { _controller: 'SimpleSAML\Module\casserver\Controller\Cas10::validate' } diff --git a/src/Controller/Cas10.php b/src/Controller/Cas10.php new file mode 100644 index 0000000..0e1c76f --- /dev/null +++ b/src/Controller/Cas10.php @@ -0,0 +1,167 @@ +config = $config; + $this->urlUtils = new UrlUtils(); + } + + + /** + * @param \Symfony\Component\HttpFoundation\Request $request + * @return \Symfony\Component\HttpFoundation\StreamedResponse + */ + public function validate(Request $request): StreamedResponse + { + /* Load simpleSAMLphp, configuration and metadata */ + $casconfig = Configuration::getConfig('module_casserver.php'); + + /* Instantiate protocol handler */ + $protocolClass = Module::resolveClass('casserver:Cas10', 'Cas\Protocol'); + + /** @psalm-suppress InvalidStringClass */ + $protocol = new $protocolClass($casconfig); + + $response = new StreamedResponse(); + if ($request->query->has('service') && $request->query->has('ticket')) { + $forceAuthn = $request->query->has('renew') && !!$request->query->get('renew'); + + try { + /* Instantiate ticket store */ + $ticketStoreConfig = $casconfig->getOptionalValue( + 'ticketstore', + ['class' => 'casserver:FileSystemTicketStore'] + ); + + $ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas\Ticket'); + + /** @psalm-suppress InvalidStringClass */ + $ticketStore = new $ticketStoreClass($casconfig); + + $ticketFactoryClass = Module::resolveClass('casserver:TicketFactory', 'Cas\Ticket'); + + /** @psalm-suppress InvalidStringClass */ + $ticketFactory = new $ticketFactoryClass($casconfig); + + $ticket = $request->query->get('ticket'); + $serviceTicket = $ticketStore->getTicket($ticket); + + if (!is_null($serviceTicket) && $ticketFactory->isServiceTicket($serviceTicket)) { + $service = $request->query->get('service'); + $ticketStore->deleteTicket($ticket); + $usernameField = $casconfig->getOptionalValue('attrname', 'eduPersonPrincipalName'); + + if ( + !$ticketFactory->isExpired($serviceTicket) && + $this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service) && + (!$forceAuthn || $serviceTicket['forceAuthn']) && + array_key_exists($usernameField, $serviceTicket['attributes']) + ) { + $response->setCallback(function() use ($protocol, $serviceTicket, $usernameField) { + echo $protocol->getValidateSuccessResponse($serviceTicket['attributes'][$usernameField][0]); + }); + } else { + if (!array_key_exists($usernameField, $serviceTicket['attributes'])) { + Logger::error(sprintf( + 'casserver:validate: internal server error. Missing user name attribute: %s', + var_export($usernameField, true) + )); + + $response->setCallback(function() use ($protocol) { + echo $protocol->getValidateFailureResponse(); + }); + } else { + if ($ticketFactory->isExpired($serviceTicket)) { + $message = 'Ticket has ' . var_export($ticket, true) . ' expired'; + } else { + if ($this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service)) { + $message = 'Mismatching service parameters: expected ' . + var_export($serviceTicket['service'], true) . + ' but was: ' . var_export($service, true); + } else { + $message = 'Ticket was issue from single sign on session'; + } + } + Logger::debug('casserver:' . $message); + + $response->setCallback(function() use ($protocol) { + echo $protocol->getValidateFailureResponse(); + }); + } + } + } else { + if (is_null($serviceTicket)) { + $message = 'ticket: ' . var_export($ticket, true) . ' not recognized'; + } else { + $message = 'ticket: ' . var_export($ticket, true) . ' is not a service ticket'; + } + + Logger::debug('casserver:' . $message); + + $response->setCallback(function() use ($protocol) { + echo $protocol->getValidateFailureResponse(); + }); + } + } catch (Exception $e) { + Logger::error('casserver:validate: internal server error. ' . var_export($e->getMessage(), true)); + + $response->setCallback(function() use ($protocol) { + echo $protocol->getValidateFailureResponse(); + }); + } + } else { + if (!$request->query->has('service')) { + $message = 'Missing service parameter: [service]'; + } else { + $message = 'Missing ticket parameter: [ticket]'; + } + + Logger::debug('casserver:' . $message); + $response->setCallback(function() use ($protocol) { + echo $protocol->getValidateFailureResponse(); + }); + } + + return $response; + } +} diff --git a/src/Utils/Url.php b/src/Utils/Url.php new file mode 100644 index 0000000..401d5b3 --- /dev/null +++ b/src/Utils/Url.php @@ -0,0 +1,58 @@ + $legal_service_urls]); + $serviceValidator = new ServiceValidator($config); + return $serviceValidator->checkServiceURL($service) !== null; + } + + + /** + * @param string $parameter + * @return string + */ + public function sanitize(string $parameter): string + { + return TicketValidator::sanitize($parameter); + } +}