/**
  * 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');
 }
 /**
  * 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;
 }
 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 idPsMetadataService()
 {
     $entitiesDescriptor = array(Corto_XmlToArray::TAG_NAME_PFX => 'md:EntitiesDescriptor', '_xmlns:md' => 'urn:oasis:names:tc:SAML:2.0:metadata', '_xmlns:mdui' => 'urn:oasis:names:tc:SAML:metadata:ui', '_ID' => $this->_server->getNewId(), 'ds:Signature' => '__placeholder__', 'md:EntityDescriptor' => array());
     // Fetch SP Entity Descriptor for the SP Entity ID that is fetched from the request
     $request = EngineBlock_ApplicationSingleton::getInstance()->getHttpRequest();
     $spEntityId = $request->getQueryParameter('sp-entity-id');
     if ($spEntityId) {
         $spEntityDescriptor = $this->_getSpEntityDescriptor($spEntityId);
         $spEntity = $this->_server->getRemoteEntity($spEntityId);
         if ($spEntityDescriptor) {
             $entitiesDescriptor['md:EntityDescriptor'][] = $spEntityDescriptor;
         }
     }
     foreach ($this->_server->getRemoteEntities() as $entityID => $entity) {
         if (!isset($entity['SingleSignOnService'])) {
             continue;
         }
         $entityDescriptor = array('_validUntil' => $this->_server->timeStamp($this->_server->getCurrentEntitySetting('idpMetadataValidUntilSeconds', 86400)), '_entityID' => $entityID, 'md:IDPSSODescriptor' => array('_protocolSupportEnumeration' => "urn:oasis:names:tc:SAML:2.0:protocol"));
         if (isset($entity['DisplayName'])) {
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions'] = array();
             }
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'] = array(0 => array());
             }
             foreach ($entity['DisplayName'] as $lang => $name) {
                 if (trim($name) === '') {
                     continue;
                 }
                 if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:DisplayName'])) {
                     $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:DisplayName'] = array();
                 }
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:DisplayName'][] = array('_xml:lang' => $lang, '__v' => $name);
             }
         }
         if (isset($entity['Description'])) {
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions'] = array();
             }
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'] = array(0 => array());
             }
             foreach ($entity['Description'] as $lang => $name) {
                 if (trim($name) === '') {
                     continue;
                 }
                 if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:Description'])) {
                     $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:Description'] = array();
                 }
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:Description'][] = array('_xml:lang' => $lang, '__v' => $name);
             }
         }
         $hasLogoHeight = isset($entity['Logo']['Height']) && $entity['Logo']['Height'];
         $hasLogoWidth = isset($entity['Logo']['Width']) && $entity['Logo']['Width'];
         if (isset($entity['Logo']) && $hasLogoHeight && $hasLogoWidth) {
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions'] = array();
             }
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'] = array(0 => array());
             }
             $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0]['mdui:Logo'] = array(array('_height' => $entity['Logo']['Height'], '_width' => $entity['Logo']['Width'], '__v' => $entity['Logo']['URL']));
         }
         if (isset($entity['GeoLocation']) && !empty($entity['GeoLocation'])) {
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions'] = array();
             }
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:DiscoHints'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:DiscoHints'] = array(0 => array());
             }
             $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:DiscoHints'][0]['mdui:GeolocationHint'] = array(array('__v' => $entity['GeoLocation']));
         }
         if (isset($entity['Keywords'])) {
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions'] = array();
             }
             if (!isset($entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'])) {
                 $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'] = array(0 => array());
             }
             $uiInfo =& $entityDescriptor['md:IDPSSODescriptor']['md:Extensions']['mdui:UIInfo'][0];
             foreach ($entity['Keywords'] as $lang => $name) {
                 if (trim($name) === '') {
                     continue;
                 }
                 if (!isset($uiInfo['mdui:Keywords'])) {
                     $uiInfo['mdui:Keywords'] = array();
                 }
                 $uiInfo['mdui:Keywords'][] = array(array('_xml:lang' => $lang, '__v' => $name));
             }
         }
         // Check if an alternative Public & Private key have been set for a SP
         // If yes, use these in the metadata of Engineblock
         if (isset($spEntity) && $spEntity['AlternatePrivateKey'] && $spEntity['AlternatePublicKey']) {
             $publicCertificate = $spEntity['AlternatePublicKey'];
         } else {
             $certificates = $this->_server->getCurrentEntitySetting('certificates', array());
             $publicCertificate = $certificates['public'];
         }
         if (isset($publicCertificate)) {
             $entityDescriptor['md:IDPSSODescriptor']['md:KeyDescriptor'] = array(array('_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', '_use' => 'signing', 'ds:KeyInfo' => array('ds:X509Data' => array('ds:X509Certificate' => array('__v' => $this->_server->getCertDataFromPem($publicCertificate))))), array('_xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', '_use' => 'encryption', 'ds:KeyInfo' => array('ds:X509Data' => array('ds:X509Certificate' => array('__v' => $this->_server->getCertDataFromPem($publicCertificate))))));
         }
         $entityDescriptor['md:IDPSSODescriptor']['md:NameIDFormat'] = array('__v' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient');
         $entityDescriptor['md:IDPSSODescriptor']['md:SingleSignOnService'] = array('_Binding' => self::DEFAULT_REQUEST_BINDING, '_Location' => $this->_server->getCurrentEntityUrl('singleSignOnService', $entityID));
         $entitiesDescriptor['md:EntityDescriptor'][] = $entityDescriptor;
     }
     $alternatePublicKey = isset($spEntity['AlternatePublicKey']) ? $spEntity['AlternatePublicKey'] : null;
     $alternatePrivateKey = isset($spEntity['AlternatePublicKey']) ? $spEntity['AlternatePublicKey'] : null;
     $entitiesDescriptor = $this->_server->sign($entitiesDescriptor, $alternatePublicKey, $alternatePrivateKey);
     $xml = Corto_XmlToArray::array2xml($entitiesDescriptor);
     $schemaUrl = 'http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd';
     if ($this->_server->getConfig('debug', false) && ini_get('allow_url_fopen') && file_exists($schemaUrl)) {
         $dom = new DOMDocument();
         $dom->loadXML($xml);
         if (!$dom->schemaValidate($schemaUrl)) {
             echo '<pre>' . htmlentities(Corto_XmlToArray::formatXml($xml)) . '</pre>';
             throw new Exception('Metadata XML doesnt validate against XSD at Oasis-open.org?!');
         }
     }
     $this->_server->sendHeader('Content-Type', 'application/xml');
     //$this->_server->sendHeader('Content-Type', 'application/samlmetadata+xml');
     $this->_server->sendOutput($xml);
 }
 /**
  * Describes Corto as an SP to IdPs
  *
  * @throws Exception
  * @return void
  */
 public function sPMetadataService()
 {
     $spEntityId = $this->_server->getCurrentEntityUrl('sPMetadataService');
     $entityDescriptor = array(Corto_XmlToArray::TAG_NAME_PFX => 'md:EntityDescriptor', Corto_XmlToArray::COMMENT_PFX => self::META_TOU_COMMENT, Corto_XmlToArray::ATTRIBUTE_PFX . 'xmlns:md' => 'urn:oasis:names:tc:SAML:2.0:metadata', Corto_XmlToArray::ATTRIBUTE_PFX . 'xmlns:mdui' => 'urn:oasis:names:tc:SAML:metadata:ui', Corto_XmlToArray::ATTRIBUTE_PFX . 'validUntil' => $this->_server->timeStamp($this->_server->getCurrentEntitySetting('idpMetadataValidUntilSeconds', 86400)), Corto_XmlToArray::ATTRIBUTE_PFX . 'entityID' => $spEntityId, Corto_XmlToArray::ATTRIBUTE_PFX . 'ID' => $this->_server->getNewId(), 'ds:Signature' => Corto_XmlToArray::PLACEHOLDER_VALUE, 'md:SPSSODescriptor' => array(Corto_XmlToArray::ATTRIBUTE_PFX . 'protocolSupportEnumeration' => "urn:oasis:names:tc:SAML:2.0:protocol"));
     $voContext = $this->_server->getVirtualOrganisationContext();
     $this->_server->setVirtualOrganisationContext(null);
     $canonicalSpEntityId = $this->_server->getCurrentEntityUrl('sPMetadataService');
     $this->_server->setVirtualOrganisationContext($voContext);
     $entityDetails = $this->_server->getRemoteEntity($canonicalSpEntityId);
     $this->_addContactPersonsToEntityDescriptor($entityDescriptor, $entityDetails);
     $this->_addDisplayNamesToEntityDescriptor($entityDescriptor['md:SPSSODescriptor'], $entityDetails);
     $certificates = $this->_server->getCurrentEntitySetting('certificates', array());
     if (isset($certificates['public'])) {
         $entityDescriptor['md:SPSSODescriptor']['md:KeyDescriptor'] = array(array(Corto_XmlToArray::ATTRIBUTE_PFX . 'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', Corto_XmlToArray::ATTRIBUTE_PFX . 'use' => 'signing', 'ds:KeyInfo' => array('ds:X509Data' => array('ds:X509Certificate' => array(Corto_XmlToArray::VALUE_PFX => $this->_server->getCertDataFromPem($certificates['public']))))), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'xmlns:ds' => 'http://www.w3.org/2000/09/xmldsig#', Corto_XmlToArray::ATTRIBUTE_PFX . 'use' => 'encryption', 'ds:KeyInfo' => array('ds:X509Data' => array('ds:X509Certificate' => array(Corto_XmlToArray::VALUE_PFX => $this->_server->getCertDataFromPem($certificates['public'])))), 'md:EncryptionMethod' => array(array('_Algorithm' => 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'))));
     }
     $entityDescriptor['md:SPSSODescriptor']['md:NameIDFormat'] = array(Corto_XmlToArray::VALUE_PFX => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient');
     $entityDescriptor['md:SPSSODescriptor']['md:AssertionConsumerService'] = array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Binding' => self::DEFAULT_RESPONSE_BINDING, Corto_XmlToArray::ATTRIBUTE_PFX . 'Location' => $this->_server->getCurrentEntityUrl('assertionConsumerService'), Corto_XmlToArray::ATTRIBUTE_PFX . 'index' => '1');
     $entityDescriptor['md:SPSSODescriptor']['md:AttributeConsumingService'] = array(Corto_XmlToArray::ATTRIBUTE_PFX . 'index' => 1);
     $this->_addServiceNamesToAttributeConsumingService($entityDescriptor['md:SPSSODescriptor']['md:AttributeConsumingService'], $entityDetails);
     $this->_addServiceDescriptionsToAttributeConsumingService($entityDescriptor['md:SPSSODescriptor']['md:AttributeConsumingService'], $entityDetails);
     $entityDescriptor['md:SPSSODescriptor']['md:AttributeConsumingService']['md:RequestedAttribute'] = array(array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:dir:attribute-def:mail'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:0.9.2342.19200300.100.1.3', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:dir:attribute-def:displayName'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:2.16.840.1.113730.3.1.241', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:dir:attribute-def:sn'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:2.5.4.4', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:dir:attribute-def:givenName'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:2.5.4.42', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:terena.org:attribute-def:schacHomeOrganization'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:1.3.6.1.4.1.25178.1.2.9', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:mace:dir:attribute-def:uid'), array(Corto_XmlToArray::ATTRIBUTE_PFX . 'Name' => 'urn:oid:0.9.2342.19200300.100.1.1', Corto_XmlToArray::ATTRIBUTE_PFX . 'NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', Corto_XmlToArray::ATTRIBUTE_PFX . 'isRequired' => 'true'));
     $entityDescriptor = $this->_server->sign($entityDescriptor);
     $xml = Corto_XmlToArray::array2xml($entityDescriptor);
     $this->_validateXml($xml);
     $this->_server->sendHeader('Content-Type', 'application/xml');
     //$this->_server->sendHeader('Content-Type', 'application/samlmetadata+xml');
     $this->_server->sendOutput($xml);
 }