protected static function retrieveMetadata($mdspec)
 {
     $type = 'public';
     $format = 'xml';
     if (is_array($mdspec)) {
         $type = 'private';
         $format = 'array';
     } elseif (preg_match("/^(private|public|remote):(xml|php|json|array):(.*)/", $mdspec, $dollar)) {
         list($dummy, $type, $format, $source) = $dollar;
     }
     print "Importing {$mdspec}\n";
     switch ($format) {
         case 'xml':
             $res = Corto_XmlToArray::xml2array(file_get_contents($source), true);
             break;
         case 'php':
             // the included file must return an array
             $res = (include $source);
             break;
         case 'json':
             $res = json_decode(file_get_contents($source), 1);
             break;
         case 'array':
             $res = $mdspec;
             break;
     }
     return array($type, $res);
 }
 protected static function _xml2array(&$elements, $level = 1, $namespaceMapping = array())
 {
     static $defaultNs;
     if ($level == 1) {
         self::$i = 0;
         $defaultNs = '';
     }
     $newElement = array();
     while (isset($elements[self::$i]) && ($value = $elements[self::$i++])) {
         if ($value['type'] == 'close') {
             return $newElement;
         } elseif ($value['type'] == 'cdata') {
             continue;
         }
         $hashedAttributes = array();
         $tagName = $value['tag'];
         if (isset($value['attributes']) && ($attributes = $value['attributes'])) {
             foreach ($attributes as $attributeKey => $attributeValue) {
                 unset($attributes[$attributeKey]);
                 if (preg_match("/^xmlns:(.+)\$/", $attributeKey, $namespacePrefixAndTag)) {
                     if (empty(self::$_namespaces[$attributeValue])) {
                         self::$_namespaces[$attributeValue] = $namespacePrefixAndTag[1];
                     }
                     $namespaceMapping[$namespacePrefixAndTag[1]] = self::$_namespaces[$attributeValue];
                     $hashedAttributes['_xmlns:' . self::$_namespaces[$attributeValue]] = $attributeValue;
                 } elseif (preg_match("/^xmlns\$/", $attributeKey)) {
                     $defaultNs = self::$_namespaces[$attributeValue];
                     $hashedAttributes['_xmlns:' . $defaultNs] = $attributeValue;
                 } else {
                     $hashedAttributes[self::ATTRIBUTE_KEY_PREFIX . $attributeKey] = $attributeValue;
                 }
             }
         }
         $complete = array();
         if (preg_match("/^(.+):(.+)\$/", $tagName, $namespacePrefixAndTag)) {
             if (!isset($namespaceMapping[$namespacePrefixAndTag[1]])) {
                 throw new Exception('No namespace defined for: ' . $tagName . ' currently defined are: ' . print_r($namespaceMapping, 1));
             }
             $tagName = $namespaceMapping[$namespacePrefixAndTag[1]] . ":" . $namespacePrefixAndTag[2];
         } else {
             $tagName = $defaultNs . ":" . $tagName;
         }
         $complete[self::TAG_NAME_KEY] = $tagName;
         if ($hashedAttributes) {
             $complete = array_merge($complete, $hashedAttributes);
         }
         if (isset($value['value'])) {
             $complete[self::VALUE_KEY] = $attributeValue = trim($value['value']);
         }
         if ($value['type'] == 'open') {
             $cs = self::_xml2array($elements, $level + 1, $namespaceMapping);
             foreach ($cs as $c) {
                 $tagName = $c[self::TAG_NAME_KEY];
                 unset($c[self::TAG_NAME_KEY]);
                 if (!isset(self::$_singulars[$tagName])) {
                     $complete[$tagName][] = $c;
                 } else {
                     $complete[$tagName] = $c;
                     unset($complete[$tagName][self::TAG_NAME_KEY]);
                 }
             }
         }
         #elseif ($value['type'] == 'complete') {
         #            }
         $newElement[] = $complete;
     }
     return $newElement;
 }
 /**
  * Sends metadata for the current entity;
  * Currently ignores the binding, as it its always URI
  * @return void
  */
 public function metadataservice()
 {
     header('Content-type: application/samlmetadata+xml');
     $entity = $this->_server->getCurrentMD('entityID');
     $md = $this->_server->getPublicMetadata($entity);
     print Corto_XmlToArray::array2xml($md, 'md:EntityDescriptor');
 }
 protected static function _xml2array(&$elements, $level = 1, $namespaceMapping = array())
 {
     static $defaultNs;
     $newElement = array();
     while (isset($elements[self::$counter])) {
         $value = $elements[self::$counter];
         self::$counter++;
         if ($value['type'] == 'close') {
             return $newElement;
         } elseif ($value['type'] == 'cdata') {
             continue;
         }
         $hashedAttributes = array();
         $tagName = $value['tag'];
         if (isset($value['attributes']) && ($attributes = $value['attributes'])) {
             foreach ($attributes as $attributeKey => $attributeValue) {
                 unset($attributes[$attributeKey]);
                 if (preg_match("/^xmlns:(.+)\$/", $attributeKey, $namespacePrefixAndTag)) {
                     if (!self::$_namespaces[$attributeValue]) {
                         self::$_namespaces[$attributeValue] = $namespacePrefixAndTag[1];
                     }
                     $namespaceMapping[$namespacePrefixAndTag[1]] = self::$_namespaces[$attributeValue];
                     $hashedAttributes['_xmlns:' . self::$_namespaces[$attributeValue]] = $attributeValue;
                 } elseif (preg_match("/^xmlns\$/", $attributeKey)) {
                     $defaultNs = self::$_namespaces[$attributeValue];
                 } else {
                     $hashedAttributes[self::ATTRIBUTE_PFX . $attributeKey] = $attributeValue;
                 }
             }
         }
         $complete = array();
         if (preg_match("/^(.+):(.+)\$/", $tagName, $namespacePrefixAndTag) && ($prefix = $namespaceMapping[$namespacePrefixAndTag[1]])) {
             $tagName = $prefix . ":" . $namespacePrefixAndTag[2];
         } else {
             $tagName = $defaultNs . ":" . $tagName;
         }
         $complete[self::TAG_NAME_PFX] = $tagName;
         if ($hashedAttributes) {
             $complete = array_merge($complete, $hashedAttributes);
         }
         if (isset($value['value']) && ($attributeValue = trim($value['value']))) {
             $complete[self::VALUE_PFX] = $attributeValue;
         }
         if ($value['type'] == 'open') {
             $cs = self::_xml2array($elements, $level + 1, $namespaceMapping);
             foreach ($cs as $c) {
                 $tagName = $c[self::TAG_NAME_PFX];
                 unset($c[self::TAG_NAME_PFX]);
                 if (!isset(self::$_singulars[$tagName])) {
                     $complete[$tagName][] = $c;
                 } else {
                     $complete[$tagName] = $c;
                     unset($complete[$tagName][self::TAG_NAME_PFX]);
                 }
             }
         }
         $newElement[] = $complete;
     }
     self::$counter = 0;
     return $newElement;
 }
 public function createNewResponse($request, $attributes = array())
 {
     $response = $this->_createBaseResponse($request);
     $soon = $this->timeStamp($this->getCurrentMD('NotOnOrAfter', null, null, 300));
     $sessionEnd = $this->timeStamp($this->getCurrentMD('SessionEnd', null, null, 60 * 60 * 12));
     $response['saml:Assertion'] = array('_xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance', '_xmlns:xs' => 'http://www.w3.org/2001/XMLSchema', '_xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol', '_xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion', '_ID' => $this->getNewId(), '_Version' => '2.0', '_IssueInstant' => $response['_IssueInstant'], 'saml:Issuer' => array('__v' => $response['saml:Issuer']['__v']), 'saml:Subject' => array('saml:NameID' => array('_SPNameQualifier' => $this->getCurrentMD('entityID'), '_Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient', '__v' => $this->getNewId()), 'saml:SubjectConfirmation' => array('_Method' => 'urn:oasis:names:tc:SAML:2.0:cm:bearer', 'saml:SubjectConfirmationData' => array('_NotOnOrAfter' => $soon, '_Recipient' => $response['_Destination'], '_InResponseTo' => $request['_ID']))), 'saml:Conditions' => array('_NotBefore' => $response['_IssueInstant'], '_NotOnOrAfter' => $soon, 'saml:AudienceRestriction' => array('saml:Audience' => array('__v' => $request['saml:Issuer']['__v']))), 'saml:AuthnStatement' => array('_AuthnInstant' => $response['_IssueInstant'], '_SessionNotOnOrAfter' => $sessionEnd, 'saml:SubjectLocality' => array('_Address' => $_SERVER['REMOTE_ADDR'], '_DNSName' => $_SERVER['REMOTE_HOST']), 'saml:AuthnContext' => array('saml:AuthnContextClassRef' => array('__v' => 'urn:oasis:names:tc:SAML:2.0:ac:classes:Password'))));
     if (!isset($attributes['binding'])) {
         $attributes['binding'] = array();
     }
     $attributes['binding'][] = $response['__']['ProtocolBinding'];
     foreach ((array) $attributes as $key => $vs) {
         foreach ($vs as $v) {
             $attributeStatement[$key][] = $v;
         }
     }
     $attributeConsumingServiceIndex = $request['_AttributeConsumingServiceIndex'];
     if ($attributeConsumingServiceIndex) {
         $attributeStatement['AttributeConsumingServiceIndex'] = "AttributeConsumingServiceIndex: {$attributeConsumingServiceIndex}";
     } else {
         $attributeStatement['AttributeConsumingServiceIndex'] = '-no AttributeConsumingServiceIndex given-';
     }
     $response['saml:Assertion']['saml:AttributeStatement'][0]['saml:Attribute'] = Corto_XmlToArray::array2attributes($attributeStatement);
     return $response;
 }
<?php

/**
 * Created by PhpStorm.
 * User: freek
 * Date: Nov 24, 2010
 * Time: 5:05:45 PM
 * To change this template use File | Settings | File Templates.
 */
include "../library/Corto/XmlToArray.php";
if ($xml = $_POST['msg']) {
    $xml = stripslashes($xml);
    $element = Corto_XmlToArray::xml2array($xml);
    print "<pre>";
    print_r($element);
    $signatureValue = base64_decode($element['ds:Signature']['ds:SignatureValue']['__v']);
    $digestValue = $element['ds:Signature']['ds:SignedInfo']['ds:Reference'][0]['ds:DigestValue']['__v'];
    $certificate = $element['ds:Signature']['ds:KeyInfo']['ds:X509Data']['ds:X509Certificate']['__v'];
    $publicKey = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certificate, 64) . "-----END CERTIFICATE-----";
    #print_r($publicKey);
    $document = DOMDocument::loadXML($xml);
    $xp = new DomXPath($document);
    $xp->registerNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
    $id = $element['_ID'];
    $signedElement = $xp->query("//*[@ID = '{$id}']")->item(0);
    $signature = $xp->query(".//ds:Signature", $signedElement)->item(0);
    $signedInfo = $xp->query(".//ds:SignedInfo", $signature)->item(0)->C14N(true, false);
    $signature->parentNode->removeChild($signature);
    $canonicalXml = $signedElement->C14N(true, false);
    print_r(htmlspecialchars($xml));
    print "\n";
 /**
  * Sign an element using $key
  * @param  $key
  * @param  $element
  * @return
  */
 protected function _sign($privatekey, $certificate, $element)
 {
     $signature = array('__t' => 'ds:Signature', '_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'ds:SignedInfo' => array('__t' => 'ds:SignedInfo', '_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'ds:CanonicalizationMethod' => array('_Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#'), 'ds:SignatureMethod' => array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'), 'ds:Reference' => array('_URI' => '__placeholder__', 'ds:Transforms' => array('ds:Transform' => array(array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'), array('_Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#'))), 'ds:DigestMethod' => array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#sha1'), 'ds:DigestValue' => array('__v' => '__placeholder__'))));
     $canonicalXml = DOMDocument::loadXML(Corto_XmlToArray::array2xml($element))->firstChild->C14N(true, false);
     $signature['ds:SignedInfo']['ds:Reference']['ds:DigestValue']['__v'] = base64_encode(sha1($canonicalXml, TRUE));
     $signature['ds:SignedInfo']['ds:Reference']['_URI'] = "#" . $element['_ID'];
     $canonicalXml2 = DOMDocument::loadXML(Corto_XmlToArray::array2xml($signature['ds:SignedInfo']))->firstChild->C14N(true, false);
     $privatekey = file_get_contents(dirname(__FILE__) . '/../../../privatekeys/' . $privatekey);
     $key = openssl_pkey_get_private($privatekey);
     openssl_sign($canonicalXml2, $signatureValue, $key);
     openssl_free_key($key);
     $signature['ds:SignatureValue']['__v'] = base64_encode($signatureValue);
     $signature['ds:KeyInfo']['ds:X509Data']['ds:X509Certificate']['__v'] = $certificate;
     $element['ds:Signature'] = $signature;
     foreach ($element as $tag => $item) {
         if ($tag == 'ds:Signature') {
             continue;
         }
         $newelement[$tag] = $item;
         if ($tag == 'saml:Issuer') {
             $newelement['ds:Signature'] = $signature;
         }
     }
     #print_r($newelement); exit;
     return $newelement;
 }
 /**
  * Ask the user for consent over all of the attributes being sent to the SP.
  *
  * Note this is part 1/2 of the Corto Consent Internal Response Processing service.
  *
  * @return void
  */
 public function provideConsentService()
 {
     $response = $this->_server->getBindingsModule()->receiveResponse();
     $_SESSION['consent'][$response['_ID']]['response'] = $response;
     $attributes = Corto_XmlToArray::attributes2array($response['saml:Assertion']['saml:AttributeStatement'][0]['saml:Attribute']);
     $serviceProviderEntityId = $attributes['ServiceProvider'][0];
     unset($attributes['ServiceProvider']);
     $spEntityMetadata = $this->_server->getRemoteEntity($serviceProviderEntityId);
     $identityProviderEntityId = $response['__']['OriginalIssuer'];
     $idpEntityMetadata = $this->_server->getRemoteEntity($identityProviderEntityId);
     $commonName = $attributes['urn:mace:dir:attribute-def:cn'][0];
     // Apply ARP
     $arpFilter = new EngineBlock_Corto_Filter_Command_AttributeReleasePolicy();
     $arpFilter->setIdpMetadata($idpEntityMetadata);
     $arpFilter->setSpMetadata($spEntityMetadata);
     $arpFilter->setResponseAttributes($attributes);
     $arpFilter->execute();
     $attributes = $arpFilter->getResponseAttributes();
     $priorConsent = $this->_hasStoredConsent($serviceProviderEntityId, $response, $attributes);
     if ($priorConsent) {
         $response['_Consent'] = 'urn:oasis:names:tc:SAML:2.0:consent:prior';
         $response['_Destination'] = $response['__']['Return'];
         $response['__']['ProtocolBinding'] = 'INTERNAL';
         $this->_server->getBindingsModule()->send($response, $spEntityMetadata);
         return;
     }
     if (isset($spEntityMetadata['NoConsentRequired']) && $spEntityMetadata['NoConsentRequired']) {
         $response['_Consent'] = 'urn:oasis:names:tc:SAML:2.0:consent:inapplicable';
         $response['_Destination'] = $response['__']['Return'];
         $response['__']['ProtocolBinding'] = 'INTERNAL';
         $this->_server->getBindingsModule()->send($response, $spEntityMetadata);
         return;
     }
     $html = $this->_server->renderTemplate('consent', array('action' => $this->_server->getCurrentEntityUrl('processConsentService'), 'ID' => $response['_ID'], 'attributes' => $attributes, 'sp' => $spEntityMetadata, 'idp' => $idpEntityMetadata, 'commonName' => $commonName));
     $this->_server->sendOutput($html);
 }
 protected function _sign($key, $element)
 {
     $signature = array('__t' => 'ds:Signature', '_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'ds:SignedInfo' => array('__t' => 'ds:SignedInfo', '_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', 'ds:CanonicalizationMethod' => array('_Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#'), 'ds:SignatureMethod' => array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'), 'ds:Reference' => array(0 => array('_URI' => '__placeholder__', 'ds:Transforms' => array('ds:Transform' => array(array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'), array('_Algorithm' => 'http://www.w3.org/2001/10/xml-exc-c14n#')))), 'ds:DigestMethod' => array('_Algorithm' => 'http://www.w3.org/2000/09/xmldsig#sha1'), 'ds:DigestValue' => array('__v' => '__placeholder__'))), 'ds:SignatureValue' => array('__v' => '__placeholder__'));
     $canonicalXml = DOMDocument::loadXML(Corto_XmlToArray::array2xml($element))->firstChild->C14N(true, false);
     $signature['ds:SignedInfo']['ds:Reference'][0]['ds:DigestValue']['__v'] = base64_encode(sha1($canonicalXml, TRUE));
     $signature['ds:SignedInfo']['ds:Reference'][0]['_URI'] = "#" . $element['_ID'];
     $canonicalXml2 = DOMDocument::loadXML(Corto_XmlToArray::array2xml($signature['ds:SignedInfo']))->firstChild->C14N(true, false);
     openssl_sign($canonicalXml2, $signatureValue, $key);
     openssl_free_key($key);
     $signature['ds:SignatureValue']['__v'] = base64_encode($signatureValue);
     $newElement = $element;
     foreach ($element as $tag => $item) {
         if ($tag == 'ds:Signature') {
             continue;
         }
         $newElement[$tag] = $item;
         if ($tag == 'saml:Issuer') {
             $newElement['ds:Signature'] = $signature;
         }
     }
     return $newElement;
 }
 public function artifactResolutionService()
 {
     $postData = Corto_XmlToArray::xml2array(file_get_contents("php://input"));
     $artifact = $postData['SOAP-ENV:Body']['samlp:ArtifactResolve']['saml:Artifact'][Corto_XmlToArray::VALUE_PFX];
     $this->_server->restartSession(sha1($artifact), 'artifact');
     $message = $_SESSION['message'];
     session_destroy();
     $element = $message[Corto_XmlToArray::TAG_NAME_PFX];
     $artifactResponse = array('samlp:ArtifactResponse' => array('xmlns:samlp' => 'urn:oasis:names:tc:SAML:2.0:protocol', 'xmlns:saml' => 'urn:oasis:names:tc:SAML:2.0:assertion', 'ID' => $this->_server->getNewId(), 'Version' => '2.0', 'IssueInstant' => $this->_server->timeStamp(), 'InResponseTo' => $postData['SOAP-ENV:Body']['samlp:ArtifactResolve'][Corto_XmlToArray::ATTRIBUTE_PFX . 'ID'], 'saml:Issuer' => array(Corto_XmlToArray::VALUE_PFX => $this->_server->getCurrentEntityUrl()), $element => $message));
     $this->_server->getBindingsModule()->soapResponse($artifactResponse);
 }