/**
  * @param array $legacyResponse
  * @return EngineBlock_Saml2_ResponseAnnotationDecorator
  */
 public function fromOldFormat(array $legacyResponse)
 {
     $legacyResponse = EngineBlock_Corto_XmlToArray::registerNamespaces($legacyResponse);
     $xml = EngineBlock_Corto_XmlToArray::array2xml($legacyResponse);
     $document = new DOMDocument();
     $document->loadXML($xml);
     $response = new SAML2_Response($document->firstChild);
     $annotatedResponse = new EngineBlock_Saml2_ResponseAnnotationDecorator($response);
     return $this->addPrivateVars($annotatedResponse, $legacyResponse);
 }
 public function serve($serviceName)
 {
     // Get the configuration for EngineBlock in it's IdP role.
     $engineIdpEntityId = $this->_server->getUrl('idpMetadataService');
     $engineIdpEntity = $this->_server->getRepository()->fetchIdentityProviderByEntityId($engineIdpEntityId);
     $edugainEntities = array();
     $ssoServiceReplacer = new ServiceReplacer($engineIdpEntity, 'SingleSignOnService', ServiceReplacer::REQUIRED);
     $slServiceReplacer = new ServiceReplacer($engineIdpEntity, 'SingleLogoutService', ServiceReplacer::OPTIONAL);
     $remoteEntities = $this->_server->getRepository()->findEntitiesPublishableInEdugain();
     foreach ($remoteEntities as $entity) {
         // Use EngineBlock certificates
         $entity->certificates = $engineIdpEntity->certificates;
         // Ignore the NameIDFormats the IdP supports, any requests made on this endpoint will use EngineBlock
         // NameIDs, so advertise that.
         unset($entity->nameIdFormat);
         $entity->supportedNameIdFormats = $engineIdpEntity->supportedNameIdFormats;
         // For IdP's replace the SingleSignService with the one from EB
         if ($entity instanceof IdentityProvider) {
             // Replace service locations and bindings with those of EB
             $transparentSsoUrl = $this->_server->getUrl('singleSignOnService', $entity->entityId);
             $ssoServiceReplacer->replace($entity, $transparentSsoUrl);
             $transparentSlUrl = $this->_server->getUrl('singleLogoutService');
             $slServiceReplacer->replace($entity, $transparentSlUrl);
         }
         $entity->contactPersons = $engineIdpEntity->contactPersons;
         $entity = $this->_addRequestAttributes($entity);
         $edugainEntities[] = $entity;
     }
     // Map the IdP configuration to a Corto XMLToArray structured document array
     $mapper = new EngineBlock_Corto_Mapper_Metadata_EdugainDocument($this->_server->getNewId(\OpenConext\Component\EngineBlockFixtures\IdFrame::ID_USAGE_SAML2_METADATA), $this->_server->timeStamp($this->_server->getConfig('metadataValidUntilSeconds', 86400)), true);
     $document = $mapper->setEntities($edugainEntities)->map();
     // Sign the document
     $document = $this->_server->sign($document);
     // Convert the document to XML
     $xml = EngineBlock_Corto_XmlToArray::array2xml($document);
     // If debugging is enabled then validate it according to the schema
     if ($this->_server->getConfig('debug', false)) {
         $validator = new EngineBlock_Xml_Validator('http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd');
         $validator->validate($xml);
     }
     // The spec dictates we use a custom mimetype, but debugging is easier with a normal mimetype
     // also no single SP / IdP complains over this.
     //$this->_server->sendHeader('Content-Type', 'application/samlmetadata+xml');
     $this->_server->sendHeader('Content-Type', 'application/xml');
     $this->_server->sendOutput($xml);
 }
Пример #3
0
 public function serve($serviceName)
 {
     // Get the configuration for EngineBlock in it's IdP / SP role without the VO.
     $this->_server->setProcessingMode();
     $engineEntityId = $this->_server->getUrl($serviceName);
     $this->_server->unsetProcessingMode();
     $engineEntity = $this->_server->getRepository()->fetchEntityByEntityId($engineEntityId);
     // Override the EntityID and SSO location to optionally append VO id
     $externalEngineEntityId = $this->_server->getUrl($serviceName);
     $engineEntity->entityId = $externalEngineEntityId;
     if ($serviceName === 'idpMetadataService') {
         $ssoServiceReplacer = new ServiceReplacer($engineEntity, 'SingleSignOnService', ServiceReplacer::REQUIRED);
         $ssoLocation = $this->_server->getUrl('singleSignOnService');
         $ssoServiceReplacer->replace($engineEntity, $ssoLocation);
     }
     // Override Single Logout Service Location with generated url
     $slServiceReplacer = new ServiceReplacer($engineEntity, 'SingleLogoutService', ServiceReplacer::OPTIONAL);
     $slLocation = $this->_server->getUrl('singleLogoutService');
     $slServiceReplacer->replace($engineEntity, $slLocation);
     // Map the IdP configuration to a Corto XMLToArray structured document array
     $mapper = new EngineBlock_Corto_Mapper_Metadata_EdugainDocument($this->_server->getNewId(IdFrame::ID_USAGE_SAML2_METADATA), $this->_server->timeStamp($this->_server->getConfig('metadataValidUntilSeconds', 86400)), false);
     $document = $mapper->setEntity($engineEntity)->map();
     // Sign the document
     $document = $this->_server->sign($document);
     // Convert the document to XML
     $xml = EngineBlock_Corto_XmlToArray::array2xml($document);
     // If debugging is enabled then validate it according to the schema
     if ($this->_server->getConfig('debug', false)) {
         $validator = new EngineBlock_Xml_Validator('http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd');
         $validator->validate($xml);
     }
     // The spec dictates we use a custom mimetype, but debugging is easier with a normal mimetype
     // also no single SP / IdP complains over this.
     //$this->_server->sendHeader('Content-Type', 'application/samlmetadata+xml');
     $this->_server->sendHeader('Content-Type', 'application/xml');
     $this->_server->sendOutput($xml);
 }
 /**
  * @dataProvider xmlOutputProvider
  */
 public function testArrayToXml($phpFile, $xmlFile)
 {
     $phpInput = (require $phpFile);
     $expectedXmlOutput = file_get_contents($xmlFile);
     $this->assertEquals($expectedXmlOutput, EngineBlock_Corto_XmlToArray::array2xml($phpInput));
 }
 /**
  * Sign a Corto_XmlToArray array with XML.
  *
  * @param  $element    Element to sign
  * @return array Signed element
  */
 public function sign(array $element)
 {
     $signingKeyPair = $this->getSigningCertificates();
     $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__'), 'ds:KeyInfo' => array('ds:X509Data' => array('ds:X509Certificate' => array('__v' => $signingKeyPair->getCertificate()->toCertData()))));
     // Convert the XMl object to actual XML and get a reference to what we're about to sign
     $canonicalXmlDom = new DOMDocument();
     $canonicalXmlDom->loadXML(EngineBlock_Corto_XmlToArray::array2xml($element));
     // Note that the current element may not be the first or last, because we might include comments, so look for
     // the actual XML element
     $xpath = new DOMXPath($canonicalXmlDom);
     $nodes = $xpath->query('/*[@ID="' . $element['_ID'] . '"]');
     if ($nodes->length < 1) {
         throw new EngineBlock_Corto_ProxyServer_Exception("Unable to sign message can't find element with id to sign?", EngineBlock_Corto_ProxyServer_Exception::CODE_NOTICE);
     }
     $canonicalXmlDom = $nodes->item(0);
     // Now do 'exclusive no-comments' XML cannonicalization
     $canonicalXml = $canonicalXmlDom->C14N(true, false);
     // Hash it, encode it in Base64 and include that as the 'Reference'
     $signature['ds:SignedInfo']['ds:Reference'][0]['ds:DigestValue']['__v'] = base64_encode(sha1($canonicalXml, true));
     $signature['ds:SignedInfo']['ds:Reference'][0]['_URI'] = "#" . $element['_ID'];
     // Now we start the actual signing, instead of signing the entire (possibly large) document,
     // we only sign the 'SignedInfo' which includes the 'Reference' hash
     $canonicalXml2Dom = new DOMDocument();
     $canonicalXml2Dom->loadXML(EngineBlock_Corto_XmlToArray::array2xml($signature['ds:SignedInfo']));
     $canonicalXml2 = $canonicalXml2Dom->firstChild->C14N(true, false);
     $signatureValue = null;
     $signatureValue = $signingKeyPair->getPrivateKey()->sign($canonicalXml2);
     $signature['ds:SignatureValue']['__v'] = base64_encode($signatureValue);
     $element['ds:Signature'] = $signature;
     $element[EngineBlock_Corto_XmlToArray::PRIVATE_PFX]['Signed'] = true;
     return $element;
 }
 public function serve($serviceName)
 {
     // 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) {
         // See if an sp-entity-id was specified for which we need to use sp specific metadata
         $spEntity = $this->_server->getRepository()->fetchServiceProviderByEntityId($spEntityId);
     }
     // Get the configuration for EngineBlock in it's IdP role.
     $engineIdpEntityId = $this->_server->getUrl('idpMetadataService');
     $engineIdentityProvider = $this->_server->getRepository()->fetchIdentityProviderByEntityId($engineIdpEntityId);
     $idpEntities = array();
     // Note that Shibboleth likes to see it's self in the metadata, so if an sp-entity-id was passed along
     // we make sure the first thing is the Service Provider
     if (isset($spEntity)) {
         $idpEntities[] = $spEntity;
     }
     $ssoServiceReplacer = new ServiceReplacer($engineIdentityProvider, 'SingleSignOnService', ServiceReplacer::REQUIRED);
     $slServiceReplacer = new ServiceReplacer($engineIdentityProvider, 'SingleLogoutService', ServiceReplacer::OPTIONAL);
     if (isset($spEntity)) {
         $identityProviders = $this->_server->getRepository()->findIdentityProvidersByEntityId($this->_server->getRepository()->findAllowedIdpEntityIdsForSp($spEntity));
     } else {
         $identityProviders = $this->_server->getRepository()->findIdentityProviders();
     }
     foreach ($identityProviders as $entity) {
         // Don't add ourselves
         if ($entity->entityId === $engineIdentityProvider->entityId) {
             continue;
         }
         if ($entity->hidden) {
             continue;
         }
         // Use EngineBlock certificates
         $entity->certificates = $engineIdentityProvider->certificates;
         // Ignore the NameIDFormats the IdP supports, any requests made on this endpoint will use EngineBlock
         // NameIDs, so advertise that.
         unset($entity->nameIdFormat);
         $entity->supportedNameIdFormats = $engineIdentityProvider->supportedNameIdFormats;
         // Replace service locations and bindings with those of EB
         $transparentSsoUrl = $this->_server->getUrl('singleSignOnService', $entity->entityId);
         $ssoServiceReplacer->replace($entity, $transparentSsoUrl);
         $transparentSlUrl = $this->_server->getUrl('singleLogoutService');
         $slServiceReplacer->replace($entity, $transparentSlUrl);
         $entity->contactPersons = $engineIdentityProvider->contactPersons;
         $idpEntities[] = $entity;
     }
     // Map the IdP configuration to a Corto XMLToArray structured document array
     $mapper = new EngineBlock_Corto_Mapper_Metadata_EdugainDocument($this->_server->getNewId(\OpenConext\Component\EngineBlockFixtures\IdFrame::ID_USAGE_SAML2_METADATA), $this->_server->timeStamp($this->_server->getConfig('metadataValidUntilSeconds', 86400)), false);
     $document = $mapper->setEntities($idpEntities)->map();
     // Sign the document
     $document = $this->_server->sign($document);
     // Convert the document to XML
     $xml = EngineBlock_Corto_XmlToArray::array2xml($document);
     // If debugging is enabled then validate it according to the schema
     if ($this->_server->getConfig('debug', false)) {
         $validator = new EngineBlock_Xml_Validator('http://docs.oasis-open.org/security/saml/v2.0/saml-schema-metadata-2.0.xsd');
         $validator->validate($xml);
     }
     // The spec dictates we use a custom mimetype, but debugging is easier with a normal mimetype
     // also no single SP / IdP complains over this.
     //$this->_server->sendHeader('Content-Type', 'application/samlmetadata+xml');
     $this->_server->sendHeader('Content-Type', 'application/xml');
     $this->_server->sendOutput($xml);
 }