예제 #1
0
파일: Message.php 프로젝트: SysBind/saml2
 /**
  * Initialize a message.
  *
  * This constructor takes an optional parameter with a \DOMElement. If this
  * parameter is given, the message will be initialized with data from that
  * XML element.
  *
  * If no XML element is given, the message is initialized with suitable
  * default values.
  *
  * @param string          $tagName The tag name of the root element.
  * @param \DOMElement|null $xml     The input message.
  * @throws \Exception
  */
 protected function __construct($tagName, \DOMElement $xml = null)
 {
     assert('is_string($tagName)');
     $this->tagName = $tagName;
     $this->id = Utils::getContainer()->generateId();
     $this->issueInstant = Temporal::getTime();
     $this->certificates = array();
     $this->validators = array();
     if ($xml === null) {
         return;
     }
     if (!$xml->hasAttribute('ID')) {
         throw new \Exception('Missing ID attribute on SAML message.');
     }
     $this->id = $xml->getAttribute('ID');
     if ($xml->getAttribute('Version') !== '2.0') {
         /* Currently a very strict check. */
         throw new \Exception('Unsupported version: ' . $xml->getAttribute('Version'));
     }
     $this->issueInstant = Utils::xsDateTimeToTimestamp($xml->getAttribute('IssueInstant'));
     if ($xml->hasAttribute('Destination')) {
         $this->destination = $xml->getAttribute('Destination');
     }
     if ($xml->hasAttribute('Consent')) {
         $this->consent = $xml->getAttribute('Consent');
     }
     $issuer = Utils::xpQuery($xml, './saml_assertion:Issuer');
     if (!empty($issuer)) {
         $this->issuer = trim($issuer[0]->textContent);
     }
     /* Validate the signature element of the message. */
     try {
         $sig = Utils::validateElement($xml);
         if ($sig !== false) {
             $this->messageContainedSignatureUponConstruction = true;
             $this->certificates = $sig['Certificates'];
             $this->validators[] = array('Function' => array('\\SAML2\\Utils', 'validateSignature'), 'Data' => $sig);
         }
     } catch (\Exception $e) {
         /* Ignore signature validation errors. */
     }
     $this->extensions = Extensions::getList($xml);
 }
예제 #2
0
 /**
  * Decrypt the NameId of the subject in the assertion.
  *
  * @param XMLSecurityKey $key       The decryption key.
  * @param array          $blacklist Blacklisted decryption algorithms.
  */
 public function decryptNameId(XMLSecurityKey $key, array $blacklist = array())
 {
     if ($this->encryptedNameId === null) {
         /* No NameID to decrypt. */
         return;
     }
     $nameId = Utils::decryptElement($this->encryptedNameId, $key, $blacklist);
     Utils::getContainer()->debugMessage($nameId, 'decrypt');
     $this->nameId = Utils::parseNameId($nameId);
     $this->encryptedNameId = null;
 }
예제 #3
0
 /**
  * Initialize a message.
  *
  * This constructor takes an optional parameter with a \DOMElement. If this
  * parameter is given, the message will be initialized with data from that
  * XML element.
  *
  * If no XML element is given, the message is initialized with suitable
  * default values.
  *
  * @param string           $tagName The tag name of the root element
  * @param \DOMElement|null $xml     The input message
  *
  * @throws \Exception
  */
 protected function __construct($tagName, \DOMElement $xml = null)
 {
     assert('is_string($tagName)');
     $this->tagName = $tagName;
     $this->id = Utils::getContainer()->generateId();
     $this->issueInstant = Temporal::getTime();
     $this->certificates = array();
     $this->validators = array();
     if ($xml === null) {
         return;
     }
     if (!$xml->hasAttribute('ID')) {
         throw new \Exception('Missing ID attribute on SAML message.');
     }
     $this->id = $xml->getAttribute('ID');
     if ($xml->getAttribute('Version') !== '2.0') {
         /* Currently a very strict check. */
         throw new \Exception('Unsupported version: ' . $xml->getAttribute('Version'));
     }
     $this->issueInstant = Utils::xsDateTimeToTimestamp($xml->getAttribute('IssueInstant'));
     if ($xml->hasAttribute('Destination')) {
         $this->destination = $xml->getAttribute('Destination');
     }
     if ($xml->hasAttribute('Consent')) {
         $this->consent = $xml->getAttribute('Consent');
     }
     $issuer = Utils::xpQuery($xml, './saml_assertion:Issuer');
     if (!empty($issuer)) {
         $this->issuer = new XML\saml\Issuer($issuer[0]);
         if ($this->issuer->Format === Constants::NAMEID_ENTITY) {
             $this->issuer = $this->issuer->value;
         }
     }
     $this->validateSignature($xml);
     $this->extensions = Extensions::getList($xml);
 }
예제 #4
0
 /**
  * Retrieve the assertion.
  *
  * @param  XMLSecurityKey  $inputKey  The key we should use to decrypt the assertion.
  * @param  array           $blacklist Blacklisted decryption algorithms.
  * @return \SAML2\Assertion The decrypted assertion.
  */
 public function getAssertion(XMLSecurityKey $inputKey, array $blacklist = array())
 {
     $assertionXML = Utils::decryptElement($this->encryptedData, $inputKey, $blacklist);
     Utils::getContainer()->debugMessage($assertionXML, 'decrypt');
     return new Assertion($assertionXML);
 }
예제 #5
0
파일: Utils.php 프로젝트: SysBind/saml2
 /**
  * Decrypt an encrypted element.
  *
  * @param  \DOMElement     $encryptedData The encrypted data.
  * @param  XMLSecurityKey $inputKey      The decryption key.
  * @param  array          $blacklist     Blacklisted decryption algorithms.
  * @return \DOMElement     The decrypted element.
  * @throws \Exception
  */
 public static function decryptElement(\DOMElement $encryptedData, XMLSecurityKey $inputKey, array $blacklist = array())
 {
     try {
         return self::doDecryptElement($encryptedData, $inputKey, $blacklist);
     } catch (\Exception $e) {
         /*
          * Something went wrong during decryption, but for security
          * reasons we cannot tell the user what failed.
          */
         Utils::getContainer()->getLogger()->error('Decryption failed: ' . $e->getMessage());
         throw new \Exception('Failed to decrypt XML element.', 0, $e);
     }
 }
예제 #6
0
 /**
  * Validate a SOAP message against the certificate on the SSL connection.
  *
  * @param string         $data The public key that was used on the connection.
  * @param XMLSecurityKey $key  The key we should validate the certificate against.
  * @throws \Exception
  */
 public static function validateSSL($data, XMLSecurityKey $key)
 {
     assert('is_string($data)');
     $keyInfo = openssl_pkey_get_details($key->key);
     if ($keyInfo === false) {
         throw new \Exception('Unable to get key details from XMLSecurityKey.');
     }
     if (!isset($keyInfo['key'])) {
         throw new \Exception('Missing key in public key details.');
     }
     if ($keyInfo['key'] !== $data) {
         Utils::getContainer()->getLogger()->debug('Key on SSL connection did not match key we validated against.');
         return;
     }
     Utils::getContainer()->getLogger()->debug('Message validated based on SSL certificate.');
 }
예제 #7
0
 /**
  * Receive a SAML 2 message sent using the HTTP-Redirect binding.
  *
  * Throws an exception if it is unable receive the message.
  *
  * @return \SAML2\Message The received message.
  * @throws \Exception
  *
  * NPath is currently too high but solving that just moves code around.
  * @SuppressWarnings(PHPMD.NPathComplexity)
  */
 public function receive()
 {
     $data = self::parseQuery();
     if (array_key_exists('SAMLRequest', $data)) {
         $message = $data['SAMLRequest'];
     } elseif (array_key_exists('SAMLResponse', $data)) {
         $message = $data['SAMLResponse'];
     } else {
         throw new \Exception('Missing SAMLRequest or SAMLResponse parameter.');
     }
     if (isset($data['SAMLEncoding']) && $data['SAMLEncoding'] !== self::DEFLATE) {
         throw new \Exception('Unknown SAMLEncoding: ' . var_export($data['SAMLEncoding'], true));
     }
     $message = base64_decode($message);
     if ($message === false) {
         throw new \Exception('Error while base64 decoding SAML message.');
     }
     $message = gzinflate($message);
     if ($message === false) {
         throw new \Exception('Error while inflating SAML message.');
     }
     Utils::getContainer()->debugMessage($message, 'in');
     $document = DOMDocumentFactory::fromString($message);
     $xml = $document->firstChild;
     $message = Message::fromXML($xml);
     if (array_key_exists('RelayState', $data)) {
         $message->setRelayState($data['RelayState']);
     }
     if (!array_key_exists('Signature', $data)) {
         return $message;
     }
     if (!array_key_exists('SigAlg', $data)) {
         throw new \Exception('Missing signature algorithm.');
     }
     $signData = array('Signature' => $data['Signature'], 'SigAlg' => $data['SigAlg'], 'Query' => $data['SignedQuery']);
     $message->addValidator(array(get_class($this), 'validateSignature'), $signData);
     return $message;
 }
예제 #8
0
 /**
  * Receive a SAML 2 message sent using the HTTP-Artifact binding.
  *
  * Throws an exception if it is unable receive the message.
  *
  * @return \SAML2\Message The received message.
  * @throws \Exception
  */
 public function receive()
 {
     if (array_key_exists('SAMLart', $_REQUEST)) {
         $artifact = base64_decode($_REQUEST['SAMLart']);
         $endpointIndex = bin2hex(substr($artifact, 2, 2));
         $sourceId = bin2hex(substr($artifact, 4, 20));
     } else {
         throw new \Exception('Missing SAMLArt parameter.');
     }
     $metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
     $idpMetadata = $metadataHandler->getMetaDataConfigForSha1($sourceId, 'saml20-idp-remote');
     if ($idpMetadata === null) {
         throw new \Exception('No metadata found for remote provider with SHA1 ID: ' . var_export($sourceId, true));
     }
     $endpoint = null;
     foreach ($idpMetadata->getEndpoints('ArtifactResolutionService') as $ep) {
         if ($ep['index'] === hexdec($endpointIndex)) {
             $endpoint = $ep;
             break;
         }
     }
     if ($endpoint === null) {
         throw new \Exception('No ArtifactResolutionService with the correct index.');
     }
     Utils::getContainer()->getLogger()->debug("ArtifactResolutionService endpoint being used is := " . $endpoint['Location']);
     //Construct the ArtifactResolve Request
     $ar = new ArtifactResolve();
     /* Set the request attributes */
     $ar->setIssuer($this->spMetadata->getString('entityid'));
     $ar->setArtifact($_REQUEST['SAMLart']);
     $ar->setDestination($endpoint['Location']);
     /* Sign the request */
     sspmod_saml_Message::addSign($this->spMetadata, $idpMetadata, $ar);
     // Shoaib - moved from the SOAPClient.
     $soap = new SOAPClient();
     // Send message through SoapClient
     /** @var \SAML2\ArtifactResponse $artifactResponse */
     $artifactResponse = $soap->send($ar, $this->spMetadata);
     if (!$artifactResponse->isSuccess()) {
         throw new \Exception('Received error from ArtifactResolutionService.');
     }
     $xml = $artifactResponse->getAny();
     if ($xml === null) {
         /* Empty ArtifactResponse - possibly because of Artifact replay? */
         return null;
     }
     $samlResponse = Message::fromXML($xml);
     $samlResponse->addValidator(array(get_class($this), 'validateSignature'), $artifactResponse);
     if (isset($_REQUEST['RelayState'])) {
         $samlResponse->setRelayState($_REQUEST['RelayState']);
     }
     return $samlResponse;
 }