public function getAttributes() { $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler(); $md = $metadata->getMetadata($this->getIssuer(), 'shib13-idp-remote'); $base64 = isset($md['base64attributes']) ? $md['base64attributes'] : false; if (!$this->dom instanceof DOMDocument) { return array(); } $attributes = array(); $assertions = $this->doXPathQuery('/shibp:Response/shib:Assertion'); foreach ($assertions as $assertion) { if (!$this->isNodeValidated($assertion)) { throw new Exception('Shib13 AuthnResponse contained an unsigned assertion.'); } $conditions = $this->doXPathQuery('shib:Conditions', $assertion); if ($conditions && $conditions->length > 0) { $condition = $conditions->item(0); $start = $condition->getAttribute('NotBefore'); $end = $condition->getAttribute('NotOnOrAfter'); if ($start && $end) { if (!SimpleSAML_Utilities::checkDateConditions($start, $end)) { error_log('Date check failed ... (from ' . $start . ' to ' . $end . ')'); continue; } } } $attribute_nodes = $this->doXPathQuery('shib:AttributeStatement/shib:Attribute/shib:AttributeValue', $assertion); foreach ($attribute_nodes as $attribute) { $value = $attribute->textContent; $name = $attribute->parentNode->getAttribute('AttributeName'); if ($attribute->hasAttribute('Scope')) { $scopePart = '@' . $attribute->getAttribute('Scope'); } else { $scopePart = ''; } if (!is_string($name)) { throw new Exception('Shib13 Attribute node without an AttributeName.'); } if (!array_key_exists($name, $attributes)) { $attributes[$name] = array(); } if ($base64) { $encodedvalues = explode('_', $value); foreach ($encodedvalues as $v) { $attributes[$name][] = base64_decode($v) . $scopePart; } } else { $attributes[$name][] = $value . $scopePart; } } } return $attributes; }
} /* Load the certificate. */ $certData = file_get_contents($certFile); if ($certData === FALSE) { throw new Exception('Unable to load certificate file \'' . $certFile . '\' for wsfed-idp \'' . $idpEntityId . '\'.'); } /* Verify that the assertion is signed by the issuer. */ $validator = new SimpleSAML_XML_Validator($assertion, 'AssertionID', $certData); if (!$validator->isNodeValidated($assertion)) { throw new Exception('The assertion was not correctly signed by the WS-Fed IdP \'' . $idpEntityId . '\'.'); } /* Check time constraints of contitions (if present). */ foreach ($xpath->query('./saml:Conditions', $assertion) as $condition) { $notBefore = $condition->getAttribute('NotBefore'); $notOnOrAfter = $condition->getAttribute('NotOnOrAfter'); if (!SimpleSAML_Utilities::checkDateConditions($notBefore, $notOnOrAfter)) { throw new Exception('The response has expired.'); } } /* Extract the name identifier from the response. */ $nameid = $xpath->query('./saml:AuthenticationStatement/saml:Subject/saml:NameIdentifier', $assertion); if ($nameid->length === 0) { throw new Exception('Could not find the name identifier in the response from the WS-Fed IdP \'' . $idpEntityId . '\'.'); } $nameid = array('Format' => $nameid->item(0)->getAttribute('Format'), 'Value' => $nameid->item(0)->textContent); /* Extract the attributes from the response. */ $attributes = array(); $attributeValues = $xpath->query('./saml:AttributeStatement/saml:Attribute/saml:AttributeValue', $assertion); foreach ($attributeValues as $attribute) { $name = $attribute->parentNode->getAttribute('AttributeName'); $value = $attribute->textContent;
/** * This function processes a Conditions node. It will throw an exception if any of the conditions * are invalid. */ private function processConditions($conditions) { /* First verify the NotBefore and NotOnOrAfter attributes if they are present. */ $notBefore = $conditions->getAttribute("NotBefore"); $notOnOrAfter = $conditions->getAttribute("NotOnOrAfter"); if (!SimpleSAML_Utilities::checkDateConditions($notBefore, $notOnOrAfter)) { throw new Exception('Date check failed (between ' . $notBefore . ' and ' . $notOnOrAfter . ').' . ' Check if the clocks on the SP and IdP are synchronized. Alternatively' . ' you can get this message, when you move back in history or refresh an old page.'); } if ($this->doXPathQuery('Condition', $conditions)->length > 0) { if (!$this->isValidationRelaxed('unknowncondition')) { throw new Exception('A Conditions node in a SAML2 AuthnResponse contained a' . ' Condition node. This is unsupported by simpleSAMLphp. To disable this' . ' check, add \'unknowncondition\' to the \'saml2.relaxvalidation\' list in' . ' \'saml2-idp-remote\'.'); } } $spEntityId = $this->metadata->getMetaDataCurrentEntityID('saml20-sp-hosted'); /* The specification says that every AudienceRestriction element must be valid, but only one * Audience element in each AudienceRestriction element must be valid. */ foreach ($this->doXPathQuery('AudienceRestriction', $conditions) as $ar) { $validAudience = false; foreach ($this->doXPathQuery('Audience', $ar) as $a) { if ($a->textContent === $spEntityId) { $validAudience = true; } } if (!$validAudience) { throw new Exception('Could not verify audience of SAML2 AuthnResponse.'); } } /* We ignore OneTimeUse and ProxyRestriction conditions. */ }