Skip to content

Commit

Permalink
WIP: Create ResponseValidator + necessary helper-classes
Browse files Browse the repository at this point in the history
  • Loading branch information
tvdijen committed Jul 26, 2024
1 parent 79edba7 commit 7d53fda
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/SAML2/Exception/ConstraintValidationFailedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Exception;

/**
* Exception to be raised when validation of a constraint fails.
*/
class ConstraintViolationFailedException extends RuntimeException
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process\ConstraintValidation;

use SimpleSAML\XML\SerializableElementInterface;

interface ConstraintValidatorInterface
{
/**
* Runs the validation.
*
* If this function returns, the validation has been succesful.
*
* @throws \SimpleSAML\SAML2\Exception\ConstraintViolationFailedException when the condition fails.
*/
public function validate(SerializableElementInterface $element): void;
}
43 changes: 43 additions & 0 deletions src/SAML2/Process/ConstraintValidation/DestinationMatches.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process\ConstraintValidation\Response;

use SimpleSAML\SAML2\{Binding, Metadata};
use SimpleSAML\SAML2\Exception\Protocol\ResourceNotRecognizedException;
use SimpleSAML\SAML2\Process\{ServiceProviderAwareInterface, ServiceProviderAwareTrait};
use SimpleSAML\SAML2\Process\ConstraintValidation\ConstraintValidatorInterface;
use SimpleSAML\XML\SerializableElementInterface;

final class DestinationMatches implements ConstraintValidatorInterface
{
/**
* DestinationMatches constructor.
*
* @param \SimpleSAML\SAML2\Metadata\ServiceProvider $spMetadata
* @param \SimpleSAML\SAML2\Binding $binding
*/
public function __construct(
private Metadata\ServiceProvider $spMetadata,
private Binding $binding,
) {
}


/**
* @param \SimpleSAML\XML\SerializableElementInterface $response
*/
public function validate(SerializableElementInterface $response): void
{
// Validate that the destination matches the appropriate endpoint from the SP-metadata
foreach ($this->spMetadata->getAssertionConsumerService() as $assertionConsumerService) {
if ($assertionConsumerService->getLocation() === $response->getDestination()) {
if (Binding::getBinding($assertionConsumerService->getBinding()) instanceof $this->binding) {
return;
}
}
}
throw new ResourceNotRecognizedException();
}
}
15 changes: 15 additions & 0 deletions src/SAML2/Process/IdentityProviderAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process;

use SimpleSAML\SAML2\Metadata;

interface IdentityProviderAwareInterface
{
/**
* Set the IdP metadata.
*/
public function setIdPMetadata(Metadata\IdentityProvider $idpMetadata): void;
}
20 changes: 20 additions & 0 deletions src/SAML2/Process/IdentityProviderAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process;

use SimpleSAML\SAML2\Metadata;

trait IdentityProviderAwareTrait
{
protected Metadata\IdentityProvider $idpMetadata;

/**
* Set the IdP metadata.
*/
public function setIdPMetadata(Metadata\IdentityProvider $idpMetadata): void
{
$this->idpMetadata = $idpMetadata;
}
}
15 changes: 15 additions & 0 deletions src/SAML2/Process/ServiceProviderAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process;

use SimpleSAML\SAML2\Metadata;

interface ServiceProviderAwareInterface
{
/**
* Set the SP metadata.
*/
public function setSPMetadata(Metadata\ServiceProvider $spMetadata): void;
}
20 changes: 20 additions & 0 deletions src/SAML2/Process/ServiceProviderAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process;

use SimpleSAML\SAML2\Metadata;

trait ServiceProviderAwareTrait
{
protected Metadata\ServiceProvider $spMetadata;

/**
* Set the SP metadata.
*/
public function setSPMetadata(Metadata\ServiceProvider $spMetadata): void
{
$this->spMetadata = $spMetadata;
}
}
42 changes: 42 additions & 0 deletions src/SAML2/Process/Validator/ResponseValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process\Validator;

use SimpleSAML\SAML2\{Binding, Metadata};
use SimpleSAML\SAML2\Process\ConstraintValidation\Response\{DestinationMatches, IsSuccessful};

class ResponseValidator implements ValidatorInterface
{
use ValidatorTrait;

/**
* @param \SimpleSAML\SAML2\Metadata\IdentityProvider The IdP-metadata
* @param \SimpleSAML\SAML2\Metadata\ServiceProvider The SP-metadata
*/
private function __construct(
protected ?Metadata\IdentityProvider $idpMetadata,
protected Metadata\ServiceProvider $spMetadata,
) {
}


/**
* @param \SimpleSAML\SAML2\Metadata\IdentityProvider|null $idpMetadata
* @param \SimpleSAML\SAML2\Metadata\ServiceProvider $spMetadata
* @param string $binding
* @return \SimpleSAML\SAML2\Validator\ResponseValidator
*/
public static function createResponseValidator(
?Metadata\IdentityProvider $idpMetadata,
Metadata\ServiceProvider $spMetadata,
Binding $binding,
): ResponseValidator {
$validator = new self($idpMetadata, $spMetadata);
// $validator->addConstraintValidator(new DestinationMatches($spMetadata, $binding));
// $validator->addConstraintValidator(new IsSuccesful());

return $validator;
}
}
26 changes: 26 additions & 0 deletions src/SAML2/Process/Validator/ValidatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process\Validator;

use SimpleSAML\SAML2\Process\ConstraintValidation\ConstraintValidatorInterface;
use SimpleSAML\XML\SerializableElementInterface;

interface ValidatorInterface
{
/**
* Runs all the validations in the validation chain.
*
* If this function returns, all validations have been succesful.
*
* @throws \SimpleSAML\SAML2\Exception\ConstraintValidationFailedException when one of the conditions fail.
*/
public function validate(SerializableElementInterface $element): void;


/**
* Add a validation to the chain.
*/
public function addConstraintValidator(ConstraintValidatorInterface $validation);
}
49 changes: 49 additions & 0 deletions src/SAML2/Process/Validator/ValidatorTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

namespace SimpleSAML\SAML2\Process\Validator;

use SimpleSAML\SAML2\Process\{IdentityProviderAwareInterface, ServiceProviderAwareInterface};
use SimpleSAML\SAML2\Process\ConstraintValidation\ConstraintValidatorInterface;
use SimpleSAML\XML\SerializableElementInterface;

trait ValidatorTrait
{
/** @var array<\SimpleSAML\SAML2\Process\ConstraintValidation\ConstraintValidatorInterface> */
protected array $validators;


/**
* Add a validation to the chain.
*
* @param \SimpleSAML\SAML2\Process\ConstraintValidation\ConstraintValidatorInterface $validation
*/
public function addConstraintValidator(ConstraintValidatorInterface $validator)
{
if ($validator instanceof IdentityProviderAwareInterface) {
$validator->setIdentityProvider($this->idpMetadata);
}

if ($validator instanceof ServiceProviderAwareInterface) {
$validator->setServiceProvider($this->spMetadata);
}

$this->validators[] = $validator;
}


/**
* Runs all the validations in the validation chain.
*
* If this function returns, all validations have been succesful.
*
* @throws \SimpleSAML\SAML2\Exception\ConstraintViolationFailedException when one of the conditions fail.
*/
public function validate(SerializableElementInterface $element): void
{
foreach ($this->validators as $validator) {
$validator->validate($element);
}
}
}

0 comments on commit 7d53fda

Please sign in to comment.