spid-php-lib
spid-php-lib copied to clipboard
Service provider logs
Hello. The technical regulation for the implementation of SPID by service providers, require the conservation of the AuthnRequest and the related Response in logs for 24 months
https://docs.italia.it/italia/spid/spid-regole-tecniche/it/stabile/log.html#service-provider
Unfortunately, in this library i can't find methos to easily obtain these information without hacking the original code (AuthRequest and BaseResponse classes)
Any suggestions about the best way to implement this functionality?
Thanks.
Hello @haunted2, thank you for reporting this. Unfortunately there is no method to directly get the data you need. You have 2 solutions at the moment:
- updating the code of the library
- manually doing all the operations that $sp->login(...) would normally do as a temporary fix. At the end of this post you can see an example of how that could look like, for reference.
I'll probably be able to send a proper fix and update in about a couple weeks. If you can't wait I suggest just hacking into the code and saving the data the moment it is generated. In case you wish to contribute we can discuss a more solid solution, just let me know.
//AUTHN REQUEST IS BUILT DURING THE LOGIN PROCESS
//THE XML IS GENERATED IN Idp.php METHOD authnRequest(...)
//ALL METHODS CALLED BY $sp->login(...) ARE PUBLIC, SO WE CAN
//CALL THEM MANUALLY AND INTERCEPT THE XML CREATION
function customLogin(
Sp $sp,
$binding,
$idpName,
$assertId,
$attrId,
$level = 1,
$redirectTo = null,
$shouldRedirect = true
) {
if ($sp->isAuthenticated()) {
return false;
}
if (!array_key_exists($assertId, $sp->settings['sp_assertionconsumerservice'])) {
throw new \Exception("Invalid Assertion Consumer Service ID");
}
if (isset($sp->settings['sp_attributeconsumingservice'])) {
if (!isset($sp->settings['sp_attributeconsumingservice'][$attrId])) {
throw new \Exception("Invalid Attribute Consuming Service ID");
}
} else {
$attrId = null;
}
$idp = $sp->loadIdpFromFile($idpName);
$idp->assertID = $assertId;
$idp->attrID = $attrId;
$idp->level = $level;
$authn = new AuthnRequest($idp);
$url = $binding == Settings::BINDING_REDIRECT ?
$authn->redirectUrl($redirectTo) :
$authn->httpPost($redirectTo);
/*==================
ACCESS THE AUTHNREQUEST XML HERE WITH
$authn->xml
THEN CONTINUE WITH THE REQUEST
==================*/
$_SESSION['RequestID'] = $authn->id;
$_SESSION['idpName'] = $idp->idpFileName;
$_SESSION['idpEntityId'] = $idp->metadata['idpEntityId'];
$_SESSION['acsUrl'] = $idp->sp->settings['sp_assertionconsumerservice'][$ass];
if (!$shouldRedirect || $binding == Settings::BINDING_POST) {
return $url;
}
header('Pragma: no-cache');
header('Cache-Control: no-cache, must-revalidate');
header('Location: ' . $url);
exit("");
}
//THE RESPONSE IS NORMALLY BUILT FROM EITHER $_POST OR $_GET DATA IN $sp->isAuthenticated()
//$_POST AND $_GET ARE NOT CLEARED SO YOU CAN REBUILD THE RESPONSE XML FROM THE DATA AFTER VERIFYING THE
//RESPONSE IS CORRECT WITH $sp->isAuthenticated()
function getResponseXML(): ?string {
if ((!isset($_POST) || !isset($_POST['SAMLResponse'])) &&
(!isset($_GET) || !isset($_GET['SAMLResponse']))
) {
return null;
}
$xmlString = isset($_GET['SAMLResponse']) ?
gzinflate(base64_decode($_GET['SAMLResponse'])) :
base64_decode($_POST['SAMLResponse']);
$xml = new \DOMDocument();
$xml->loadXML($xmlString);
$ns_samlp = 'urn:oasis:names:tc:SAML:2.0:protocol';
$root = $xml->getElementsByTagNameNS($ns_samlp, '*')->item(0)->localName;
if ($root != 'Response') return null;
if (isset($_SESSION['spidSession'])) {
return null;
}
return $xml;
}
Thank you very much! Looking at your example, i managed to log the data i need.