Пример #1
0
 /**
  * Extract the response element from the SOAP response.
  *
  * @param string $soapResponse  The SOAP response.
  * @return string  The <saml1p:Response> element, as a string.
  */
 private static function extractResponse($soapResponse)
 {
     assert('is_string($soapResponse)');
     try {
         $doc = SAML2_DOMDocumentFactory::fromString($soapResponse);
     } catch (\Exception $e) {
         throw new SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.');
     }
     $soapEnvelope = $doc->firstChild;
     if (!SimpleSAML\Utils\XML::isDOMElementOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) {
         throw new SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.');
     }
     $soapBody = SimpleSAML\Utils\XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/');
     if (count($soapBody) === 0) {
         throw new SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.');
     }
     $soapBody = $soapBody[0];
     $responseElement = SimpleSAML\Utils\XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol');
     if (count($responseElement) === 0) {
         throw new SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.');
     }
     $responseElement = $responseElement[0];
     /*
      * Save the <saml1p:Response> element. Note that we need to import it
      * into a new document, in order to preserve namespace declarations.
      */
     $newDoc = SAML2_DOMDocumentFactory::create();
     $newDoc->appendChild($newDoc->importNode($responseElement, TRUE));
     $responseXML = $newDoc->saveXML();
     return $responseXML;
 }
Пример #2
0
 /**
  * Send an authenticationResponse using HTTP-POST.
  *
  * @param string                   $response The response which should be sent.
  * @param SimpleSAML_Configuration $idpmd The metadata of the IdP which is sending the response.
  * @param SimpleSAML_Configuration $spmd The metadata of the SP which is receiving the response.
  * @param string|null              $relayState The relaystate for the SP.
  * @param string                   $shire The shire which should receive the response.
  */
 public function sendResponse($response, SimpleSAML_Configuration $idpmd, SimpleSAML_Configuration $spmd, $relayState, $shire)
 {
     \SimpleSAML\Utils\XML::checkSAMLMessage($response, 'saml11');
     $privatekey = SimpleSAML\Utils\Crypto::loadPrivateKey($idpmd, true);
     $publickey = SimpleSAML\Utils\Crypto::loadPublicKey($idpmd, true);
     $responsedom = new DOMDocument();
     $responsedom->loadXML(str_replace("\r", "", $response));
     $responseroot = $responsedom->getElementsByTagName('Response')->item(0);
     $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
     /* Determine what we should sign - either the Response element or the Assertion. The default is to sign the
      * Assertion, but that can be overridden by the 'signresponse' option in the SP metadata or
      * 'saml20.signresponse' in the global configuration.
      *
      * TODO: neither 'signresponse' nor 'shib13.signresponse' are valid options any longer. Remove!
      */
     if ($spmd->hasValue('signresponse')) {
         $signResponse = $spmd->getBoolean('signresponse');
     } else {
         $signResponse = $this->configuration->getBoolean('shib13.signresponse', true);
     }
     // check if we have an assertion to sign. Force to sign the response if not
     if ($firstassertionroot === null) {
         $signResponse = true;
     }
     $signer = new SimpleSAML_XML_Signer(array('privatekey_array' => $privatekey, 'publickey_array' => $publickey, 'id' => $signResponse ? 'ResponseID' : 'AssertionID'));
     if ($idpmd->hasValue('certificatechain')) {
         $signer->addCertificate($idpmd->getString('certificatechain'));
     }
     if ($signResponse) {
         // sign the response - this must be done after encrypting the assertion
         // we insert the signature before the saml2p:Status element
         $statusElements = SimpleSAML\Utils\XML::getDOMChildren($responseroot, 'Status', '@saml1p');
         assert('count($statusElements) === 1');
         $signer->sign($responseroot, $responseroot, $statusElements[0]);
     } else {
         /* Sign the assertion */
         $signer->sign($firstassertionroot, $firstassertionroot);
     }
     $response = $responsedom->saveXML();
     \SimpleSAML\Utils\XML::debugSAMLMessage($response, 'out');
     \SimpleSAML\Utils\HTTP::submitPOSTData($shire, array('TARGET' => $relayState, 'SAMLResponse' => base64_encode($response)));
 }
Пример #3
0
 /**
  * Parse an Extensions element.
  *
  * @param mixed $element The element which contains the Extensions element.
  *
  * @return array An associative array with the extensions parsed.
  */
 private static function processExtensions($element)
 {
     $ret = array('scope' => array(), 'tags' => array(), 'EntityAttributes' => array(), 'UIInfo' => array(), 'DiscoHints' => array());
     foreach ($element->Extensions as $e) {
         if ($e instanceof SAML2_XML_shibmd_Scope) {
             $ret['scope'][] = $e->scope;
             continue;
         }
         // Entity Attributes are only allowed at entity level extensions and not at RoleDescriptor level
         if ($element instanceof SAML2_XML_md_EntityDescriptor) {
             if ($e instanceof SAML2_XML_mdattr_EntityAttributes && !empty($e->children)) {
                 foreach ($e->children as $attr) {
                     // only saml:Attribute are currently supported here. The specifications also allows
                     // saml:Assertions, which more complex processing.
                     if ($attr instanceof SAML2_XML_saml_Attribute) {
                         if (empty($attr->Name) || empty($attr->AttributeValue)) {
                             continue;
                         }
                         // attribute names that is not URI is prefixed as this: '{nameformat}name'
                         $name = $attr->Name;
                         if (empty($attr->NameFormat)) {
                             $name = '{' . SAML2_Const::NAMEFORMAT_UNSPECIFIED . '}' . $attr->Name;
                         } elseif ($attr->NameFormat !== 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri') {
                             $name = '{' . $attr->NameFormat . '}' . $attr->Name;
                         }
                         $values = array();
                         foreach ($attr->AttributeValue as $attrvalue) {
                             $values[] = $attrvalue->getString();
                         }
                         $ret['EntityAttributes'][$name] = $values;
                     }
                 }
             }
         }
         // UIInfo elements are only allowed at RoleDescriptor level extensions
         if ($element instanceof SAML2_XML_md_RoleDescriptor) {
             if ($e instanceof SAML2_XML_mdui_UIInfo) {
                 $ret['UIInfo']['DisplayName'] = $e->DisplayName;
                 $ret['UIInfo']['Description'] = $e->Description;
                 $ret['UIInfo']['InformationURL'] = $e->InformationURL;
                 $ret['UIInfo']['PrivacyStatementURL'] = $e->PrivacyStatementURL;
                 foreach ($e->Keywords as $uiItem) {
                     if (!$uiItem instanceof SAML2_XML_mdui_Keywords || empty($uiItem->Keywords) || empty($uiItem->lang)) {
                         continue;
                     }
                     $ret['UIInfo']['Keywords'][$uiItem->lang] = $uiItem->Keywords;
                 }
                 foreach ($e->Logo as $uiItem) {
                     if (!$uiItem instanceof SAML2_XML_mdui_Logo || empty($uiItem->url) || empty($uiItem->height) || empty($uiItem->width)) {
                         continue;
                     }
                     $logo = array('url' => $uiItem->url, 'height' => $uiItem->height, 'width' => $uiItem->width);
                     if (!empty($uiItem->lang)) {
                         $logo['lang'] = $uiItem->lang;
                     }
                     $ret['UIInfo']['Logo'][] = $logo;
                 }
             }
         }
         // DiscoHints elements are only allowed at IDPSSODescriptor level extensions
         if ($element instanceof SAML2_XML_md_IDPSSODescriptor) {
             if ($e instanceof SAML2_XML_mdui_DiscoHints) {
                 $ret['DiscoHints']['IPHint'] = $e->IPHint;
                 $ret['DiscoHints']['DomainHint'] = $e->DomainHint;
                 $ret['DiscoHints']['GeolocationHint'] = $e->GeolocationHint;
             }
         }
         if (!$e instanceof SAML2_XML_Chunk) {
             continue;
         }
         if ($e->localName === 'Attribute' && $e->namespaceURI === SAML2_Const::NS_SAML) {
             $attribute = $e->getXML();
             $name = $attribute->getAttribute('Name');
             $values = array_map(array('SimpleSAML\\Utils\\XML', 'getDOMText'), SimpleSAML\Utils\XML::getDOMChildren($attribute, 'AttributeValue', '@saml2'));
             if ($name === 'tags') {
                 foreach ($values as $tagname) {
                     if (!empty($tagname)) {
                         $ret['tags'][] = $tagname;
                     }
                 }
             }
         }
     }
     return $ret;
 }
Пример #4
0
 /**
  * Parse an Extensions element. Extensions may appear in multiple elements and certain extension may get inherited
  * from a parent element.
  *
  * @param mixed $element The element which contains the Extensions element.
  * @param array $parentExtensions An optional array of extensions from the parent element.
  *
  * @return array An associative array with the extensions parsed.
  */
 private static function processExtensions($element, $parentExtensions = array())
 {
     $ret = array('scope' => array(), 'tags' => array(), 'EntityAttributes' => array(), 'RegistrationInfo' => array(), 'UIInfo' => array(), 'DiscoHints' => array());
     // Some extensions may get inherited from a parent element
     if (($element instanceof \SAML2\XML\md\EntityDescriptor || $element instanceof \SAML2\XML\md\EntitiesDescriptor) && !empty($parentExtensions['RegistrationInfo'])) {
         $ret['RegistrationInfo'] = $parentExtensions['RegistrationInfo'];
     }
     foreach ($element->Extensions as $e) {
         if ($e instanceof \SAML2\XML\shibmd\Scope) {
             $ret['scope'][] = $e->scope;
             continue;
         }
         // Entity Attributes are only allowed at entity level extensions and not at RoleDescriptor level
         if ($element instanceof \SAML2\XML\md\EntityDescriptor || $element instanceof \SAML2\XML\md\EntitiesDescriptor) {
             if ($e instanceof \SAML2\XML\mdrpi\RegistrationInfo) {
                 // Registration Authority cannot be overridden (warn only if override attempts to change the value)
                 if (isset($ret['RegistrationInfo']['registrationAuthority']) && $ret['RegistrationInfo']['registrationAuthority'] !== $e->registrationAuthority) {
                     SimpleSAML\Logger::warning('Invalid attempt to override registrationAuthority \'' . $ret['RegistrationInfo']['registrationAuthority'] . "' with '{$e->registrationAuthority}'");
                 } else {
                     $ret['RegistrationInfo']['registrationAuthority'] = $e->registrationAuthority;
                 }
             }
             if ($e instanceof \SAML2\XML\mdattr\EntityAttributes && !empty($e->children)) {
                 foreach ($e->children as $attr) {
                     // only saml:Attribute are currently supported here. The specifications also allows
                     // saml:Assertions, which more complex processing
                     if ($attr instanceof \SAML2\XML\saml\Attribute) {
                         if (empty($attr->Name) || empty($attr->AttributeValue)) {
                             continue;
                         }
                         // attribute names that is not URI is prefixed as this: '{nameformat}name'
                         $name = $attr->Name;
                         if (empty($attr->NameFormat)) {
                             $name = '{' . \SAML2\Constants::NAMEFORMAT_UNSPECIFIED . '}' . $attr->Name;
                         } elseif ($attr->NameFormat !== 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri') {
                             $name = '{' . $attr->NameFormat . '}' . $attr->Name;
                         }
                         $values = array();
                         foreach ($attr->AttributeValue as $attrvalue) {
                             $values[] = $attrvalue->getString();
                         }
                         $ret['EntityAttributes'][$name] = $values;
                     }
                 }
             }
         }
         // UIInfo elements are only allowed at RoleDescriptor level extensions
         if ($element instanceof \SAML2\XML\md\RoleDescriptor) {
             if ($e instanceof \SAML2\XML\mdui\UIInfo) {
                 $ret['UIInfo']['DisplayName'] = $e->DisplayName;
                 $ret['UIInfo']['Description'] = $e->Description;
                 $ret['UIInfo']['InformationURL'] = $e->InformationURL;
                 $ret['UIInfo']['PrivacyStatementURL'] = $e->PrivacyStatementURL;
                 foreach ($e->Keywords as $uiItem) {
                     if (!$uiItem instanceof \SAML2\XML\mdui\Keywords || empty($uiItem->Keywords) || empty($uiItem->lang)) {
                         continue;
                     }
                     $ret['UIInfo']['Keywords'][$uiItem->lang] = $uiItem->Keywords;
                 }
                 foreach ($e->Logo as $uiItem) {
                     if (!$uiItem instanceof \SAML2\XML\mdui\Logo || empty($uiItem->url) || empty($uiItem->height) || empty($uiItem->width)) {
                         continue;
                     }
                     $logo = array('url' => $uiItem->url, 'height' => $uiItem->height, 'width' => $uiItem->width);
                     if (!empty($uiItem->lang)) {
                         $logo['lang'] = $uiItem->lang;
                     }
                     $ret['UIInfo']['Logo'][] = $logo;
                 }
             }
         }
         // DiscoHints elements are only allowed at IDPSSODescriptor level extensions
         if ($element instanceof \SAML2\XML\md\IDPSSODescriptor) {
             if ($e instanceof \SAML2\XML\mdui\DiscoHints) {
                 $ret['DiscoHints']['IPHint'] = $e->IPHint;
                 $ret['DiscoHints']['DomainHint'] = $e->DomainHint;
                 $ret['DiscoHints']['GeolocationHint'] = $e->GeolocationHint;
             }
         }
         if (!$e instanceof \SAML2\XML\Chunk) {
             continue;
         }
         if ($e->localName === 'Attribute' && $e->namespaceURI === \SAML2\Constants::NS_SAML) {
             $attribute = $e->getXML();
             $name = $attribute->getAttribute('Name');
             $values = array_map(array('SimpleSAML\\Utils\\XML', 'getDOMText'), SimpleSAML\Utils\XML::getDOMChildren($attribute, 'AttributeValue', '@saml2'));
             if ($name === 'tags') {
                 foreach ($values as $tagname) {
                     if (!empty($tagname)) {
                         $ret['tags'][] = $tagname;
                     }
                 }
             }
         }
     }
     return $ret;
 }
Пример #5
0
 /**
  * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\XML::getDOMChildren() instead.
  */
 public static function getDOMChildren(DOMElement $element, $localName, $namespaceURI)
 {
     return SimpleSAML\Utils\XML::getDOMChildren($element, $localName, $namespaceURI);
 }