Skip to content

Commit

Permalink
Implement custom serializable to exclude DOMDocuments
Browse files Browse the repository at this point in the history
  • Loading branch information
Stephan Kok committed Dec 13, 2024
1 parent 5eefda3 commit 5207581
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 12 deletions.
Empty file modified app/logs/.gitkeep
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public function serve($serviceName, Request $httpRequest)
}

if ($receivedRequest->isDebugRequest()) {
$_SESSION['debugIdpResponse'] = $receivedResponse;
$_SESSION['debugIdpResponse'] = serialize($receivedResponse);
$requestId = $receivedResponse->getInResponseTo();

// Authentication state needs to be registered here as the debug flow differs from the regular flow,
Expand Down
2 changes: 1 addition & 1 deletion library/EngineBlock/Corto/Module/Service/SingleSignOn.php
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ private function _displayDebugResponse($serviceName)
}

/** @var Response|EngineBlock_Saml2_ResponseAnnotationDecorator $response */
$response = $_SESSION['debugIdpResponse'];
$response = unserialize($_SESSION['debugIdpResponse']);

$log = $this->_server->getLogger();
$log->info(
Expand Down
46 changes: 43 additions & 3 deletions library/EngineBlock/Saml2/AuthnRequestAnnotationDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@

use OpenConext\EngineBlock\Metadata\Loa;
use SAML2\AuthnRequest;
use SAML2\DOMDocumentFactory;

/**
* @method getProxyCount()
* @method getIsPassive()
* @method getForceAuthn()
* @method toUnsignedXML()
*/
class EngineBlock_Saml2_AuthnRequestAnnotationDecorator extends EngineBlock_Saml2_MessageAnnotationDecorator
class EngineBlock_Saml2_AuthnRequestAnnotationDecorator extends EngineBlock_Saml2_MessageAnnotationDecorator implements Serializable
{
/**
* @var AuthnRequest
Expand Down Expand Up @@ -60,9 +61,9 @@ class EngineBlock_Saml2_AuthnRequestAnnotationDecorator extends EngineBlock_Saml
/**
* @param AuthnRequest $request
*/
public function __construct(AuthnRequest $request)
public function __construct(AuthnRequest $sspMessage)
{
$this->sspMessage = $request;
$this->sspMessage = $sspMessage;
}

/**
Expand Down Expand Up @@ -184,4 +185,43 @@ public function setForceAuthn(bool $isForceAuthn)
{
$this->sspMessage->setForceAuthn($isForceAuthn);
}

/**
* Since php 8 serialisation of the DOMDocument is no longer supported. This means that the sspMessage (AuthnRequest)
* is no longer serializable. However since the AuthnRequest is a xml request converted to a php object we can save
* the object by converted it back to its XML message, save it in cache and rebuild the object.
*
* Do note that any newly added fields to the decorator class (this class) will have to be added to the data array
* to be saved in session storage.
*/
public function serialize()
{
$requestXML = $this->sspMessage->toUnsignedXML();
$requestStringXML = $requestXML->ownerDocument->saveXML();
$data = array(
"sspMessage" => $requestStringXML,
"keyId" => $this->keyId,
"wasSigned" => $this->wasSigned,
"debug" => $this->debug,
"unsolicited" => $this->unsolicited,
"transparent" => $this->transparent,

"deliverByBinding" => $this->deliverByBinding, // from extended wrapper
);
return serialize($data);
}

public function unserialize(string $data)
{
$data = unserialize($data);
$dom = DOMDocumentFactory::fromString($data['sspMessage']);
$this->sspMessage = new AuthnRequest($dom->firstChild);
$this->keyId = $data['keyId'];
$this->wasSigned = $data['wasSigned'];
$this->debug = $data['debug'];
$this->unsolicited = $data['unsolicited'];
$this->transparent = $data['transparent'];

$this->deliverByBinding = $data['deliverByBinding'];
}
}
5 changes: 3 additions & 2 deletions library/EngineBlock/Saml2/AuthnRequestSessionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public function findRequestById($requestId)
return null;
}

return $this->requestStorage[$requestId];
$serializedRequest = $this->requestStorage[$requestId];
return unserialize($serializedRequest);
}

/**
Expand All @@ -90,7 +91,7 @@ public function store(
EngineBlock_Saml2_AuthnRequestAnnotationDecorator $spRequest
) {
// Store the original Request
$this->requestStorage[$spRequest->getId()] = $spRequest;
$this->requestStorage[$spRequest->getId()] = serialize($spRequest);
return $this;
}

Expand Down
68 changes: 64 additions & 4 deletions library/EngineBlock/Saml2/ResponseAnnotationDecorator.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

use SAML2\Assertion;
use SAML2\DOMDocumentFactory;
use SAML2\EncryptedAssertion;
use SAML2\Response;
use SAML2\XML\saml\NameID;
Expand All @@ -28,7 +29,7 @@
* @method void setAssertions(array)
* @method void setIssuer(string)
*/
class EngineBlock_Saml2_ResponseAnnotationDecorator extends EngineBlock_Saml2_MessageAnnotationDecorator
class EngineBlock_Saml2_ResponseAnnotationDecorator extends EngineBlock_Saml2_MessageAnnotationDecorator implements Serializable
{
/**
* @var Response
Expand Down Expand Up @@ -83,11 +84,11 @@ class EngineBlock_Saml2_ResponseAnnotationDecorator extends EngineBlock_Saml2_Me
protected $isTransparentErrorResponse = false;

/**
* @param Response $response
* @param Response $sspMessage
*/
function __construct(Response $response)
function __construct(Response $sspMessage)
{
$this->sspMessage = $response;
$this->sspMessage = $sspMessage;
}

/**
Expand Down Expand Up @@ -308,4 +309,63 @@ public function setIsTransparentErrorResponse(bool $isTransparentErrorResponse):
{
$this->isTransparentErrorResponse = $isTransparentErrorResponse;
}

public function getSspMessage(): Response
{
return $this->sspMessage;
}

public function setSspMessage(Response $sspMessage): void
{
$this->sspMessage = $sspMessage;
}

/**
* Since php 8 serialisation of the DOMDocument is no longer supported. This means that the sspMessage (AuthnRequest)
* is no longer serializable. However since the AuthnRequest is a xml request converted to a php object we can save
* the object by converted it back to its XML message, save it in cache and rebuild the object.
*
* Do note that any newly added fields to the decorator class (this class) will have to be added to the data array
* to be saved in session storage.
*/
public function serialize()
{
$requestXML = $this->sspMessage->toUnsignedXML();
$requestStringXML = $requestXML->ownerDocument->saveXML();
$data = array(
"sspMessage" => $requestStringXML,
"return" => $this->return,
"originalIssuer" => $this->originalIssuer,
"originalNameId" => $this->originalNameId,
"originalBinding" => $this->originalBinding,
"originalResponse" => $this->originalResponse,
"collabPersonId" => $this->collabPersonId,
"customNameId" => $this->customNameId,
"intendedNameId" => $this->intendedNameId,
"pdpRequestedLoas" => $this->pdpRequestedLoas,
"isTransparentErrorResponse" => $this->isTransparentErrorResponse,

"deliverByBinding" => $this->deliverByBinding, // from extended wrapper
);
return serialize($data);
}

public function unserialize(string $data)
{
$data = unserialize($data);
$dom = DOMDocumentFactory::fromString($data['sspMessage']);
$this->sspMessage = new Response($dom->firstChild);
$this->return = $data['return'];
$this->originalIssuer = $data['originalIssuer'];
$this->originalNameId = $data['originalNameId'];
$this->originalBinding = $data['originalBinding'];
$this->originalResponse = $data['originalResponse'];
$this->collabPersonId = $data['collabPersonId'];
$this->customNameId = $data['customNameId'];
$this->intendedNameId = $data['intendedNameId'];
$this->pdpRequestedLoas = $data['pdpRequestedLoas'];
$this->isTransparentErrorResponse = $data['isTransparentErrorResponse'];

$this->deliverByBinding = $data['deliverByBinding'];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use OpenConext\EngineBlock\Validator\RequestValidator;
use OpenConext\EngineBlockBridge\ResponseFactory;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;

class ServiceProviderController implements AuthenticationLoopThrottlingController
{
Expand Down

1 comment on commit 5207581

@Stephan-Kok
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do note that impact on performance should be tested

Please sign in to comment.