/** * 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); }