From df8753378bb5e44749bad138ccde9c1b9ae61788 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli <36352093+GuySartorelli@users.noreply.github.com> Date: Wed, 2 Oct 2024 14:40:08 +1300 Subject: [PATCH] ENH Use symfony/validation logic (#167) --- src/RealMeService.php | 9 +++++--- src/Task/RealMeSetupTask.php | 45 +++++++++++++++--------------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/src/RealMeService.php b/src/RealMeService.php index 54178d6..c874625 100644 --- a/src/RealMeService.php +++ b/src/RealMeService.php @@ -18,12 +18,15 @@ use SilverStripe\Core\Environment; use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injector; +use SilverStripe\Core\Validation\ConstraintValidator; use SilverStripe\RealMe\Exception as RealMeException; use SilverStripe\RealMe\Model\FederatedIdentity; use SilverStripe\RealMe\Model\User; use SilverStripe\Security\Member; use SilverStripe\Security\Security; use SilverStripe\View\TemplateGlobalProvider; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\Url; class RealMeService implements TemplateGlobalProvider { @@ -458,11 +461,11 @@ public function enforceLogin(HTTPRequest $request, $backUrl = null) } $backUrl = $this->validSiteURL($backUrl); - + if (!$backUrl) { $backUrl = Director::absoluteBaseURL(); } - + // If not, attempt to retrieve authentication data from OneLogin (in case this is called during SAML assertion) try { if (!$session->get("RealMeErrorBackURL") && Controller::has_curr()) { @@ -800,7 +803,7 @@ public function getAssertionConsumerServiceUrlForEnvironment($env) } $domain = $this->getMetadataAssertionServiceDomainForEnvironment($env); - if (filter_var($domain, FILTER_VALIDATE_URL) === false) { + if (!ConstraintValidator::validate($domain, [new Url(), new NotBlank()])->isValid()) { return null; } diff --git a/src/Task/RealMeSetupTask.php b/src/Task/RealMeSetupTask.php index 5aa0f20..9c7363f 100644 --- a/src/Task/RealMeSetupTask.php +++ b/src/Task/RealMeSetupTask.php @@ -8,11 +8,14 @@ use SilverStripe\RealMe\RealMeService; use SilverStripe\Control\Director; use SilverStripe\Control\Controller; +use SilverStripe\Core\Validation\ConstraintValidator; use SilverStripe\Dev\BuildTask; use SilverStripe\PolyExecution\PolyOutput; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\Url; /** * Class RealMeSetupTask @@ -275,45 +278,33 @@ private function validateEntityID($forEnv) ); } - // make sure the entityID is a valid URL - $entityId = filter_var($entityId, FILTER_VALIDATE_URL); - if ($entityId === false) { - $this->errors[] = _t( - RealMeSetupTask::class . '.ERR_CONFIG_ENTITYID', - 'The Entity ID (\'{entityId}\') must be https, not be \'localhost\', and must contain a valid ' . - 'service name and privacy realm e.g. https://my-realme-integration.govt.nz/p-realm/s-name', - array( - 'entityId' => $entityId - ) - ); - + $validationMessage = _t( + RealMeSetupTask::class . '.ERR_CONFIG_ENTITYID', + 'The Entity ID (\'{entityId}\') must be https, not be \'localhost\', and must contain a valid ' . + 'service name and privacy realm e.g. https://my-realme-integration.govt.nz/p-realm/s-name', + ['entityId' => $entityId] + ); + // make sure the entityID is a valid URL with HTTPS protocol + if (!ConstraintValidator::validate($entityId, [new Url(protocols: ['https']), new NotBlank()])->isValid()) { + $this->errors[] = $validationMessage; // invalid entity id, no point continuing. return; } - // check it's not localhost and HTTPS. and make sure we have a host / scheme + // check it's not localhost $urlParts = parse_url($entityId ?? ''); - if ($urlParts['host'] === 'localhost' || $urlParts['scheme'] === 'http') { - $this->errors[] = _t( - RealMeSetupTask::class . '.ERR_CONFIG_ENTITYID', - 'The Entity ID (\'{entityId}\') must be https, not be \'localhost\', and must contain a valid ' . - 'service name and privacy realm e.g. https://my-realme-integration.govt.nz/p-realm/s-name', - array( - 'entityId' => $entityId - ) - ); - + if ($urlParts['host'] === 'localhost') { + $this->errors[] = $validationMessage; // if there's this much wrong, we want them to fix it first. return; } $path = ltrim($urlParts['path'] ?? ''); - $urlParts = preg_split("/\\//", $path ?? ''); - + $pathParts = preg_split("/\\//", $path ?? ''); // A valid Entity ID is in the form of "https://www.domain.govt.nz//" // Validate Service Name - $serviceName = array_pop($urlParts); + $serviceName = array_pop($pathParts); if (mb_strlen($serviceName ?? '') > 20 || 0 === mb_strlen($serviceName ?? '')) { $this->errors[] = _t( RealMeSetupTask::class . '.ERR_CONFIG_ENTITYID_SERVICE_NAME', @@ -327,7 +318,7 @@ private function validateEntityID($forEnv) } // Validate Privacy Realm - $privacyRealm = array_pop($urlParts); + $privacyRealm = array_pop($pathParts); if (null === $privacyRealm || 0 === mb_strlen($privacyRealm ?? '')) { $this->errors[] = _t( RealMeSetupTask::class . '.ERR_CONFIG_ENTITYID_PRIVACY_REALM',