$requestid, 'Issuer' => $issuer, 'RelayState' => $requestid ); $spEntityId = $requestcache['Issuer']; $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'adfs-sp-remote'); SimpleSAML_Logger::info('ADFS - IdP.prp: Incoming Authentication request: '.$issuer.' id '.$requestid); } catch(Exception $exception) { throw new SimpleSAML_Error_Error('PROCESSAUTHNREQUEST', $exception); } $sessionLostURL = NULL; // TODO? $forceAuthn = FALSE; $isPassive = FALSE; $state = array( 'Responder' => array('sspmod_adfs_IdP_ADFS', 'sendResponse'), // SimpleSAML_Auth_State::EXCEPTION_HANDLER_FUNC => array('sspmod_adfs_IdP', 'handleAuthError'), // SimpleSAML_Auth_State::RESTART => $sessionLostURL, 'SPMetadata' => $spMetadata->toArray(), 'ForceAuthn' => $forceAuthn, 'isPassive' => $isPassive, 'adfs:wctx' => $wctx, ); $idp->handleAuthenticationRequest($state); } public static function ADFS_GenerateResponse($issuer, $target, $nameid, $attributes) { #$nameid = 'hans@surfnet.nl'; $issueInstant = SimpleSAML_Utilities::generateTimestamp(); $notBefore = SimpleSAML_Utilities::generateTimestamp(time() - 30); $assertionExpire = SimpleSAML_Utilities::generateTimestamp(time() + 60 * 5); $assertionID = SimpleSAML_Utilities::generateID(); $nameidFormat = 'http://schemas.xmlsoap.org/claims/UPN'; $result = ' ' . $target .' ' . htmlspecialchars($nameid) . ' ' . htmlspecialchars($nameid) . ' '; foreach ($attributes as $name => $values) { if ((!is_array($values)) || (count($values) == 0)) continue; $hasValue = FALSE; $r = ''; foreach ($values as $value) { if ( (!isset($value)) or ($value === '')) continue; $r .= '' . htmlspecialchars($value) . ''; $hasValue = TRUE; } $r .= ''; if ($hasValue) $result .= $r; } $result .= ' ' . $target . ' '; return $result; } public static function ADFS_SignResponse($response, $key, $cert) { $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->idKeys = array('AssertionID'); $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); $responsedom = new DOMDocument(); $responsedom->loadXML(str_replace ("\r", "", $response)); $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0); $objXMLSecDSig->addReferenceList(array($firstassertionroot), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), array('id_name' => 'AssertionID')); $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); $objKey->loadKey($key, TRUE); $objXMLSecDSig->sign($objKey); if ($cert) { $public_cert = file_get_contents($cert); $objXMLSecDSig->add509Cert($public_cert, TRUE); } $newSig = $responsedom->importNode($objXMLSecDSig->sigNode, TRUE); $firstassertionroot->appendChild($newSig); return $responsedom->saveXML(); } public static function ADFS_PostResponse($url, $wresult, $wctx) { print '
'; exit; } public static function sendResponse(array $state) { $spMetadata = $state["SPMetadata"]; $spEntityId = $spMetadata['entityid']; $spMetadata = SimpleSAML_Configuration::loadFromArray($spMetadata, '$metadata[' . var_export($spEntityId, TRUE) . ']'); $attributes = $state['Attributes']; $nameidattribute = $spMetadata->getValue('simplesaml.nameidattribute'); if (!empty($nameidattribute)) { if (!array_key_exists($nameidattribute, $attributes)) { throw new Exception('simplesaml.nameidattribute does not exist in resulting attribute set'); } $nameid = $attributes[$nameidattribute][0]; } else { $nameid = SimpleSAML_Utilities::generateID(); } $idp = SimpleSAML_IdP::getByState($state); $idpMetadata = $idp->getConfig(); $idpEntityId = $idpMetadata->getString('entityid'); $idp->addAssociation(array( 'id' => 'adfs:' . $spEntityId, 'Handler' => 'sspmod_adfs_IdP_ADFS', 'adfs:entityID' => $spEntityId, )); $response = sspmod_adfs_IdP_ADFS::ADFS_GenerateResponse($idpEntityId, $spEntityId, $nameid, $attributes); $privateKeyFile = SimpleSAML_Utilities::resolveCert($idpMetadata->getString('privatekey')); $certificateFile = SimpleSAML_Utilities::resolveCert($idpMetadata->getString('certificate')); $wresult = sspmod_adfs_IdP_ADFS::ADFS_SignResponse($response, $privateKeyFile, $certificateFile); $wctx = $state['adfs:wctx']; sspmod_adfs_IdP_ADFS::ADFS_PostResponse($spMetadata->getValue('prp'), $wresult, $wctx); } /* public static function handleAuthError(SimpleSAML_Error_Exception $exception, array $state) { } */ public static function sendLogoutResponse(SimpleSAML_IdP $idp, array $state) { // NB:: we don't know from which SP the logout request came from $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $idpMetadata = $idp->getConfig(); SimpleSAML_Utilities::redirectTrustedURL($idpMetadata->getValue('redirect-after-logout', SimpleSAML_Utilities::getBaseURL())); } public static function receiveLogoutMessage(SimpleSAML_IdP $idp) { // if a redirect is to occur based on wreply, we will redirect to url as // this implies an override to normal sp notification. if(isset($_GET['wreply']) && !empty($_GET['wreply'])) { $idp->doLogoutRedirect(SimpleSAML_Utilities::checkURLAllowed($_GET['wreply'])); assert(FALSE); } $state = array( 'Responder' => array('sspmod_adfs_IdP_ADFS', 'sendLogoutResponse'), ); //$spEntityId = NULL; //$assocId = 'adfs:' . $spEntityId; $assocId = NULL; // TODO: verify that this is really no problem for: // a) SSP, because there's no caller SP... // b) ADFS SP because caller will be called back... $idp->handleLogoutRequest($state, $assocId); } // accepts an association array, and returns a URL that can be accessed to terminate the association. public static function getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState) { $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $idpMetadata = $idp->getConfig(); $spMetadata = $metadata->getMetaDataConfig($association['adfs:entityID'], 'adfs-sp-remote'); // 'https://adfs-test.showcase.surfnet.nl/adfs/ls/?wa=wsignoutcleanup1.0&wreply=https%3A%2F%2Flocalhost%2Fsimplesaml'); $returnTo = SimpleSAML_Module::getModuleURL('adfs/idp/prp.php?assocId=' . urlencode($association["id"]) . '&relayState=' . urlencode($relayState)); return $spMetadata->getValue('prp') . '?' . 'wa=wsignoutcleanup1.0&wreply=' . urlencode($returnTo); } }