ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
Message.php
Go to the documentation of this file.
1<?php
2
4
11{
12
20 public static function addSign(
21 SimpleSAML_Configuration $srcMetadata,
22 SimpleSAML_Configuration $dstMetadata,
23 \SAML2\SignedElement $element
24 ) {
25 $dstPrivateKey = $dstMetadata->getString('signature.privatekey', null);
26
27 if ($dstPrivateKey !== null) {
28 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true, 'signature.');
29 $certArray = SimpleSAML\Utils\Crypto::loadPublicKey($dstMetadata, false, 'signature.');
30 } else {
31 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($srcMetadata, true);
32 $certArray = SimpleSAML\Utils\Crypto::loadPublicKey($srcMetadata, false);
33 }
34
35 $algo = $dstMetadata->getString('signature.algorithm', null);
36 if ($algo === null) {
37 /*
38 * In the NIST Special Publication 800-131A, SHA-1 became deprecated for generating
39 * new digital signatures in 2011, and will be explicitly disallowed starting the 1st
40 * of January, 2014. We'll keep this as a default for the next release and mark it
41 * as deprecated, as part of the transition to SHA-256.
42 *
43 * See http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf for more info.
44 *
45 * TODO: change default to XMLSecurityKey::RSA_SHA256.
46 */
47 $algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA1);
48 }
49
50 $privateKey = new XMLSecurityKey($algo, array('type' => 'private'));
51 if (array_key_exists('password', $keyArray)) {
52 $privateKey->passphrase = $keyArray['password'];
53 }
54 $privateKey->loadKey($keyArray['PEM'], false);
55
56 $element->setSignatureKey($privateKey);
57
58 if ($certArray === null) {
59 // we don't have a certificate to add
60 return;
61 }
62
63 if (!array_key_exists('PEM', $certArray)) {
64 // we have a public key with only a fingerprint
65 return;
66 }
67
68 $element->setCertificates(array($certArray['PEM']));
69 }
70
71
79 private static function addRedirectSign(
80 SimpleSAML_Configuration $srcMetadata,
81 SimpleSAML_Configuration $dstMetadata,
82 \SAML2\Message $message
83 ) {
84
85 $signingEnabled = null;
86 if ($message instanceof \SAML2\LogoutRequest || $message instanceof \SAML2\LogoutResponse) {
87 $signingEnabled = $srcMetadata->getBoolean('sign.logout', null);
88 if ($signingEnabled === null) {
89 $signingEnabled = $dstMetadata->getBoolean('sign.logout', null);
90 }
91 } elseif ($message instanceof \SAML2\AuthnRequest) {
92 $signingEnabled = $srcMetadata->getBoolean('sign.authnrequest', null);
93 if ($signingEnabled === null) {
94 $signingEnabled = $dstMetadata->getBoolean('sign.authnrequest', null);
95 }
96 }
97
98 if ($signingEnabled === null) {
99 $signingEnabled = $dstMetadata->getBoolean('redirect.sign', null);
100 if ($signingEnabled === null) {
101 $signingEnabled = $srcMetadata->getBoolean('redirect.sign', false);
102 }
103 }
104 if (!$signingEnabled) {
105 return;
106 }
107
108 self::addSign($srcMetadata, $dstMetadata, $message);
109 }
110
111
124 private static function findCertificate(array $certFingerprints, array $certificates)
125 {
126 $candidates = array();
127
128 foreach ($certificates as $cert) {
129 $fp = strtolower(sha1(base64_decode($cert)));
130 if (!in_array($fp, $certFingerprints, true)) {
131 $candidates[] = $fp;
132 continue;
133 }
134
135 /* We have found a matching fingerprint. */
136 $pem = "-----BEGIN CERTIFICATE-----\n".
137 chunk_split($cert, 64).
138 "-----END CERTIFICATE-----\n";
139 return $pem;
140 }
141
142 $candidates = "'".implode("', '", $candidates)."'";
143 $fps = "'".implode("', '", $certFingerprints)."'";
144 throw new SimpleSAML_Error_Exception('Unable to find a certificate matching the configured '.
145 'fingerprint. Candidates: '.$candidates.'; certFingerprint: '.$fps.'.');
146 }
147
148
159 public static function checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
160 {
161 // find the public key that should verify signatures by this entity
162 $keys = $srcMetadata->getPublicKeys('signing');
163 if ($keys !== null) {
164 $pemKeys = array();
165 foreach ($keys as $key) {
166 switch ($key['type']) {
167 case 'X509Certificate':
168 $pemKeys[] = "-----BEGIN CERTIFICATE-----\n".
169 chunk_split($key['X509Certificate'], 64).
170 "-----END CERTIFICATE-----\n";
171 break;
172 default:
173 SimpleSAML\Logger::debug('Skipping unknown key type: '.$key['type']);
174 }
175 }
176 } elseif ($srcMetadata->hasValue('certFingerprint')) {
178 "Validating certificates by fingerprint is deprecated. Please use ".
179 "certData or certificate options in your remote metadata configuration."
180 );
181
182 $certFingerprint = $srcMetadata->getArrayizeString('certFingerprint');
183 foreach ($certFingerprint as &$fp) {
184 $fp = strtolower(str_replace(':', '', $fp));
185 }
186
187 $certificates = $element->getCertificates();
188
189 // we don't have the full certificate stored. Try to find it in the message or the assertion instead
190 if (count($certificates) === 0) {
191 /* We need the full certificate in order to match it against the fingerprint. */
192 SimpleSAML\Logger::debug('No certificate in message when validating against fingerprint.');
193 return false;
194 } else {
195 SimpleSAML\Logger::debug('Found '.count($certificates).' certificates in '.get_class($element));
196 }
197
198 $pemCert = self::findCertificate($certFingerprint, $certificates);
199 $pemKeys = array($pemCert);
200 } else {
202 'Missing certificate in metadata for '.
203 var_export($srcMetadata->getString('entityid'), true)
204 );
205 }
206
207 SimpleSAML\Logger::debug('Has '.count($pemKeys).' candidate keys for validation.');
208
209 $lastException = null;
210 foreach ($pemKeys as $i => $pem) {
211 $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
212 $key->loadKey($pem);
213
214 try {
215 // make sure that we have a valid signature on either the response or the assertion
216 $res = $element->validate($key);
217 if ($res) {
218 SimpleSAML\Logger::debug('Validation with key #'.$i.' succeeded.');
219 return true;
220 }
221 SimpleSAML\Logger::debug('Validation with key #'.$i.' failed without exception.');
222 } catch (Exception $e) {
223 SimpleSAML\Logger::debug('Validation with key #'.$i.' failed with exception: '.$e->getMessage());
224 $lastException = $e;
225 }
226 }
227
228 // we were unable to validate the signature with any of our keys
229 if ($lastException !== null) {
230 throw $lastException;
231 } else {
232 return false;
233 }
234 }
235
236
246 public static function validateMessage(
247 SimpleSAML_Configuration $srcMetadata,
248 SimpleSAML_Configuration $dstMetadata,
249 \SAML2\Message $message
250 ) {
251 $enabled = null;
252 if ($message instanceof \SAML2\LogoutRequest || $message instanceof \SAML2\LogoutResponse) {
253 $enabled = $srcMetadata->getBoolean('validate.logout', null);
254 if ($enabled === null) {
255 $enabled = $dstMetadata->getBoolean('validate.logout', null);
256 }
257 } elseif ($message instanceof \SAML2\AuthnRequest) {
258 $enabled = $srcMetadata->getBoolean('validate.authnrequest', null);
259 if ($enabled === null) {
260 $enabled = $dstMetadata->getBoolean('validate.authnrequest', null);
261 }
262 }
263
264 if ($enabled === null) {
265 $enabled = $srcMetadata->getBoolean('redirect.validate', null);
266 if ($enabled === null) {
267 $enabled = $dstMetadata->getBoolean('redirect.validate', false);
268 }
269 }
270
271 if (!$enabled) {
272 return;
273 }
274
275 if (!self::checkSign($srcMetadata, $message)) {
277 'Validation of received messages enabled, but no signature found on message.'
278 );
279 }
280 }
281
282
291 public static function getDecryptionKeys(
292 SimpleSAML_Configuration $srcMetadata,
293 SimpleSAML_Configuration $dstMetadata
294 ) {
295 $sharedKey = $srcMetadata->getString('sharedkey', null);
296 if ($sharedKey !== null) {
297 $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
298 $key->loadKey($sharedKey);
299 return array($key);
300 }
301
302 $keys = array();
303
304 // load the new private key if it exists
305 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, false, 'new_');
306 if ($keyArray !== null) {
307 assert('isset($keyArray["PEM"])');
308
309 $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
310 if (array_key_exists('password', $keyArray)) {
311 $key->passphrase = $keyArray['password'];
312 }
313 $key->loadKey($keyArray['PEM']);
314 $keys[] = $key;
315 }
316
317 // find the existing private key
318 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true);
319 assert('isset($keyArray["PEM"])');
320
321 $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
322 if (array_key_exists('password', $keyArray)) {
323 $key->passphrase = $keyArray['password'];
324 }
325 $key->loadKey($keyArray['PEM']);
326 $keys[] = $key;
327
328 return $keys;
329 }
330
331
342 public static function getBlacklistedAlgorithms(
343 SimpleSAML_Configuration $srcMetadata,
344 SimpleSAML_Configuration $dstMetadata
345 ) {
346 $blacklist = $srcMetadata->getArray('encryption.blacklisted-algorithms', null);
347 if ($blacklist === null) {
348 $blacklist = $dstMetadata->getArray('encryption.blacklisted-algorithms', array(XMLSecurityKey::RSA_1_5));
349 }
350 return $blacklist;
351 }
352
353
367 private static function decryptAssertion(
368 SimpleSAML_Configuration $srcMetadata,
369 SimpleSAML_Configuration $dstMetadata,
370 $assertion
371 ) {
372 assert('$assertion instanceof \SAML2\Assertion || $assertion instanceof \SAML2\EncryptedAssertion');
373
374 if ($assertion instanceof \SAML2\Assertion) {
375 $encryptAssertion = $srcMetadata->getBoolean('assertion.encryption', null);
376 if ($encryptAssertion === null) {
377 $encryptAssertion = $dstMetadata->getBoolean('assertion.encryption', false);
378 }
379 if ($encryptAssertion) {
380 /* The assertion was unencrypted, but we have encryption enabled. */
381 throw new Exception('Received unencrypted assertion, but encryption was enabled.');
382 }
383
384 return $assertion;
385 }
386
387 try {
388 $keys = self::getDecryptionKeys($srcMetadata, $dstMetadata);
389 } catch (Exception $e) {
390 throw new SimpleSAML_Error_Exception('Error decrypting assertion: '.$e->getMessage());
391 }
392
393 $blacklist = self::getBlacklistedAlgorithms($srcMetadata, $dstMetadata);
394
395 $lastException = null;
396 foreach ($keys as $i => $key) {
397 try {
398 $ret = $assertion->getAssertion($key, $blacklist);
399 SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
400 return $ret;
401 } catch (Exception $e) {
402 SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
403 $lastException = $e;
404 }
405 }
406 throw $lastException;
407 }
408
409
417 public static function getResponseError(\SAML2\StatusResponse $response)
418 {
419 $status = $response->getStatus();
420 return new sspmod_saml_Error($status['Code'], $status['SubCode'], $status['Message']);
421 }
422
423
431 public static function buildAuthnRequest(
434 ) {
435 $ar = new \SAML2\AuthnRequest();
436
437 // get the NameIDPolicy to apply. IdP metadata has precedence.
438 $nameIdPolicy = array();
439 if ($idpMetadata->hasValue('NameIDPolicy')) {
440 $nameIdPolicy = $idpMetadata->getValue('NameIDPolicy');
441 } elseif ($spMetadata->hasValue('NameIDPolicy')) {
442 $nameIdPolicy = $spMetadata->getValue('NameIDPolicy');
443 }
444
445 if (!is_array($nameIdPolicy)) {
446 // handle old configurations where 'NameIDPolicy' was used to specify just the format
447 $nameIdPolicy = array('Format' => $nameIdPolicy);
448 }
449
450 $nameIdPolicy_cf = SimpleSAML_Configuration::loadFromArray($nameIdPolicy);
451 $policy = array(
452 'Format' => $nameIdPolicy_cf->getString('Format', \SAML2\Constants::NAMEID_TRANSIENT),
453 'AllowCreate' => $nameIdPolicy_cf->getBoolean('AllowCreate', true),
454 );
455 $spNameQualifier = $nameIdPolicy_cf->getString('SPNameQualifier', false);
456 if ($spNameQualifier !== false) {
457 $policy['SPNameQualifier'] = $spNameQualifier;
458 }
459 $ar->setNameIdPolicy($policy);
460
461 $ar->setForceAuthn($spMetadata->getBoolean('ForceAuthn', false));
462 $ar->setIsPassive($spMetadata->getBoolean('IsPassive', false));
463
464 $protbind = $spMetadata->getValueValidate('ProtocolBinding', array(
465 \SAML2\Constants::BINDING_HTTP_POST,
466 \SAML2\Constants::BINDING_HOK_SSO,
467 \SAML2\Constants::BINDING_HTTP_ARTIFACT,
468 \SAML2\Constants::BINDING_HTTP_REDIRECT,
469 ), \SAML2\Constants::BINDING_HTTP_POST);
470
471 // Shoaib: setting the appropriate binding based on parameter in sp-metadata defaults to HTTP_POST
472 $ar->setProtocolBinding($protbind);
473 $ar->setIssuer($spMetadata->getString('entityid'));
474 $ar->setAssertionConsumerServiceIndex($spMetadata->getInteger('AssertionConsumerServiceIndex', null));
475 $ar->setAttributeConsumingServiceIndex($spMetadata->getInteger('AttributeConsumingServiceIndex', null));
476
477 if ($spMetadata->hasValue('AuthnContextClassRef')) {
478 $accr = $spMetadata->getArrayizeString('AuthnContextClassRef');
479 $comp = $spMetadata->getValueValidate('AuthnContextComparison', array(
480 \SAML2\Constants::COMPARISON_EXACT,
481 \SAML2\Constants::COMPARISON_MINIMUM,
482 \SAML2\Constants::COMPARISON_MAXIMUM,
483 \SAML2\Constants::COMPARISON_BETTER,
484 ), \SAML2\Constants::COMPARISON_EXACT);
485 $ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
486 }
487
489
490 return $ar;
491 }
492
493
501 public static function buildLogoutRequest(
502 SimpleSAML_Configuration $srcMetadata,
503 SimpleSAML_Configuration $dstMetadata
504 ) {
505 $lr = new \SAML2\LogoutRequest();
506 $lr->setIssuer($srcMetadata->getString('entityid'));
507
508 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
509
510 return $lr;
511 }
512
513
521 public static function buildLogoutResponse(
522 SimpleSAML_Configuration $srcMetadata,
523 SimpleSAML_Configuration $dstMetadata
524 ) {
525 $lr = new \SAML2\LogoutResponse();
526 $lr->setIssuer($srcMetadata->getString('entityid'));
527
528 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
529
530 return $lr;
531 }
532
533
548 public static function processResponse(
551 \SAML2\Response $response
552 ) {
553 if (!$response->isSuccess()) {
555 }
556
557 // validate Response-element destination
559 $msgDestination = $response->getDestination();
560 if ($msgDestination !== null && $msgDestination !== $currentURL) {
561 throw new Exception('Destination in response doesn\'t match the current URL. Destination is "'.
562 $msgDestination.'", current URL is "'.$currentURL.'".');
563 }
564
565 $responseSigned = self::checkSign($idpMetadata, $response);
566
567 /*
568 * When we get this far, the response itself is valid.
569 * We only need to check signatures and conditions of the response.
570 */
571 $assertion = $response->getAssertions();
572 if (empty($assertion)) {
573 throw new SimpleSAML_Error_Exception('No assertions found in response from IdP.');
574 }
575
576 $ret = array();
577 foreach ($assertion as $a) {
579 }
580
581 return $ret;
582 }
583
584
601 private static function processAssertion(
604 \SAML2\Response $response,
605 $assertion,
606 $responseSigned
607 ) {
608 assert('$assertion instanceof \SAML2\Assertion || $assertion instanceof \SAML2\EncryptedAssertion');
609 assert('is_bool($responseSigned)');
610
611 $assertion = self::decryptAssertion($idpMetadata, $spMetadata, $assertion);
612
613 if (!self::checkSign($idpMetadata, $assertion)) {
614 if (!$responseSigned) {
615 throw new SimpleSAML_Error_Exception('Neither the assertion nor the response was signed.');
616 }
617 } // at least one valid signature found
618
620
621 // check various properties of the assertion
622 $notBefore = $assertion->getNotBefore();
623 if ($notBefore !== null && $notBefore > time() + 60) {
625 'Received an assertion that is valid in the future. Check clock synchronization on IdP and SP.'
626 );
627 }
628 $notOnOrAfter = $assertion->getNotOnOrAfter();
629 if ($notOnOrAfter !== null && $notOnOrAfter <= time() - 60) {
631 'Received an assertion that has expired. Check clock synchronization on IdP and SP.'
632 );
633 }
634 $sessionNotOnOrAfter = $assertion->getSessionNotOnOrAfter();
635 if ($sessionNotOnOrAfter !== null && $sessionNotOnOrAfter <= time() - 60) {
637 'Received an assertion with a session that has expired. Check clock synchronization on IdP and SP.'
638 );
639 }
640 $validAudiences = $assertion->getValidAudiences();
641 if ($validAudiences !== null) {
642 $spEntityId = $spMetadata->getString('entityid');
643 if (!in_array($spEntityId, $validAudiences, true)) {
644 $candidates = '['.implode('], [', $validAudiences).']';
645 throw new SimpleSAML_Error_Exception('This SP ['.$spEntityId.
646 '] is not a valid audience for the assertion. Candidates were: '.$candidates);
647 }
648 }
649
650 $found = false;
651 $lastError = 'No SubjectConfirmation element in Subject.';
652 $validSCMethods = array(\SAML2\Constants::CM_BEARER, \SAML2\Constants::CM_HOK, \SAML2\Constants::CM_VOUCHES);
653 foreach ($assertion->getSubjectConfirmation() as $sc) {
654 if (!in_array($sc->Method, $validSCMethods, true)) {
655 $lastError = 'Invalid Method on SubjectConfirmation: '.var_export($sc->Method, true);
656 continue;
657 }
658
659 // is SSO with HoK enabled? IdP remote metadata overwrites SP metadata configuration
660 $hok = $idpMetadata->getBoolean('saml20.hok.assertion', null);
661 if ($hok === null) {
662 $hok = $spMetadata->getBoolean('saml20.hok.assertion', false);
663 }
664 if ($sc->Method === \SAML2\Constants::CM_BEARER && $hok) {
665 $lastError = 'Bearer SubjectConfirmation received, but Holder-of-Key SubjectConfirmation needed';
666 continue;
667 }
668 if ($sc->Method === \SAML2\Constants::CM_HOK && !$hok) {
669 $lastError = 'Holder-of-Key SubjectConfirmation received, '.
670 'but the Holder-of-Key profile is not enabled.';
671 continue;
672 }
673
674 $scd = $sc->SubjectConfirmationData;
675 if ($sc->Method === \SAML2\Constants::CM_HOK) {
676 // check HoK Assertion
677 if (\SimpleSAML\Utils\HTTP::isHTTPS() === false) {
678 $lastError = 'No HTTPS connection, but required for Holder-of-Key SSO';
679 continue;
680 }
681 if (isset($_SERVER['SSL_CLIENT_CERT']) && empty($_SERVER['SSL_CLIENT_CERT'])) {
682 $lastError = 'No client certificate provided during TLS Handshake with SP';
683 continue;
684 }
685 // extract certificate data (if this is a certificate)
686 $clientCert = $_SERVER['SSL_CLIENT_CERT'];
687 $pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
688 if (!preg_match($pattern, $clientCert, $matches)) {
689 $lastError = 'Error while looking for client certificate during TLS handshake with SP, the client '.
690 'certificate does not have the expected structure';
691 continue;
692 }
693 // we have a valid client certificate from the browser
694 $clientCert = str_replace(array("\r", "\n", " "), '', $matches[1]);
695
696 $keyInfo = array();
697 foreach ($scd->info as $thing) {
698 if ($thing instanceof \SAML2\XML\ds\KeyInfo) {
699 $keyInfo[] = $thing;
700 }
701 }
702 if (count($keyInfo) != 1) {
703 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:KeyInfo> element in '.
704 '<SubjectConfirmationData> allowed';
705 continue;
706 }
707
708 $x509data = array();
709 foreach ($keyInfo[0]->info as $thing) {
710 if ($thing instanceof \SAML2\XML\ds\X509Data) {
711 $x509data[] = $thing;
712 }
713 }
714 if (count($x509data) != 1) {
715 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:X509Data> element in '.
716 '<ds:KeyInfo> within <SubjectConfirmationData> allowed';
717 continue;
718 }
719
720 $x509cert = array();
721 foreach ($x509data[0]->data as $thing) {
722 if ($thing instanceof \SAML2\XML\ds\X509Certificate) {
723 $x509cert[] = $thing;
724 }
725 }
726 if (count($x509cert) != 1) {
727 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:X509Certificate> element in '.
728 '<ds:X509Data> within <SubjectConfirmationData> allowed';
729 continue;
730 }
731
732 $HoKCertificate = $x509cert[0]->certificate;
733 if ($HoKCertificate !== $clientCert) {
734 $lastError = 'Provided client certificate does not match the certificate bound to the '.
735 'Holder-of-Key assertion';
736 continue;
737 }
738 }
739
740 // if no SubjectConfirmationData then don't do anything.
741 if ($scd === null) {
742 $lastError = 'No SubjectConfirmationData provided';
743 continue;
744 }
745
746 if ($scd->NotBefore && $scd->NotBefore > time() + 60) {
747 $lastError = 'NotBefore in SubjectConfirmationData is in the future: '.$scd->NotBefore;
748 continue;
749 }
750 if ($scd->NotOnOrAfter && $scd->NotOnOrAfter <= time() - 60) {
751 $lastError = 'NotOnOrAfter in SubjectConfirmationData is in the past: '.$scd->NotOnOrAfter;
752 continue;
753 }
754 if ($scd->Recipient !== null && $scd->Recipient !== $currentURL) {
755 $lastError = 'Recipient in SubjectConfirmationData does not match the current URL. Recipient is '.
756 var_export($scd->Recipient, true).', current URL is '.var_export($currentURL, true).'.';
757 continue;
758 }
759 if ($scd->InResponseTo !== null && $response->getInResponseTo() !== null &&
760 $scd->InResponseTo !== $response->getInResponseTo()
761 ) {
762 $lastError = 'InResponseTo in SubjectConfirmationData does not match the Response. Response has '.
763 var_export($response->getInResponseTo(), true).
764 ', SubjectConfirmationData has '.var_export($scd->InResponseTo, true).'.';
765 continue;
766 }
767 $found = true;
768 break;
769 }
770 if (!$found) {
771 throw new SimpleSAML_Error_Exception('Error validating SubjectConfirmation in Assertion: '.$lastError);
772 } // as far as we can tell, the assertion is valid
773
774 // maybe we need to base64 decode the attributes in the assertion?
775 if ($idpMetadata->getBoolean('base64attributes', false)) {
776 $attributes = $assertion->getAttributes();
777 $newAttributes = array();
778 foreach ($attributes as $name => $values) {
779 $newAttributes[$name] = array();
780 foreach ($values as $value) {
781 foreach (explode('_', $value) as $v) {
782 $newAttributes[$name][] = base64_decode($v);
783 }
784 }
785 }
786 $assertion->setAttributes($newAttributes);
787 }
788
789 // decrypt the NameID element if it is encrypted
790 if ($assertion->isNameIdEncrypted()) {
791 try {
793 } catch (Exception $e) {
794 throw new SimpleSAML_Error_Exception('Error decrypting NameID: '.$e->getMessage());
795 }
796
798
799 $lastException = null;
800 foreach ($keys as $i => $key) {
801 try {
802 $assertion->decryptNameId($key, $blacklist);
803 SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
804 $lastException = null;
805 break;
806 } catch (Exception $e) {
807 SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
808 $lastException = $e;
809 }
810 }
811 if ($lastException !== null) {
812 throw $lastException;
813 }
814 }
815
816 return $assertion;
817 }
818
819
830 {
831
832 $sharedKey = $metadata->getString('sharedkey', null);
833 if ($sharedKey !== null) {
834 $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
835 $key->loadKey($sharedKey);
836 return $key;
837 }
838
839 $keys = $metadata->getPublicKeys('encryption', true);
840 foreach ($keys as $key) {
841 switch ($key['type']) {
842 case 'X509Certificate':
843 $pemKey = "-----BEGIN CERTIFICATE-----\n".
844 chunk_split($key['X509Certificate'], 64).
845 "-----END CERTIFICATE-----\n";
846 $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
847 $key->loadKey($pemKey);
848 return $key;
849 }
850 }
851
852 throw new SimpleSAML_Error_Exception('No supported encryption key in '.
853 var_export($metadata->getString('entityid'), true));
854 }
855}
$metadata['__DYNAMIC:1__']
$spEntityId
An exception for terminatinating execution or to throw for unit testing.
static debug($string)
Definition: Logger.php:213
static notice($string)
Definition: Logger.php:190
static loadPublicKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='')
Get public key or certificate from metadata.
Definition: Crypto.php:265
static loadPrivateKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='', $full_path=false)
Load a private key from metadata.
Definition: Crypto.php:195
static getSelfURLNoQuery()
Retrieve the current URL using the base URL in the configuration, without the query parameters.
Definition: HTTP.php:846
getString($name, $default=self::REQUIRED_OPTION)
This function retrieves a string configuration option.
getBoolean($name, $default=self::REQUIRED_OPTION)
This function retrieves a boolean configuration option.
static loadFromArray($config, $location='[ARRAY]', $instance=null)
Loads a configuration from the given array.
getArrayizeString($name, $default=self::REQUIRED_OPTION)
This function retrieves a configuration option with a string or an array of strings.
getArray($name, $default=self::REQUIRED_OPTION)
This function retrieves an array configuration option.
getPublicKeys($use=null, $required=false, $prefix='')
Get public key from metadata.
hasValue($name)
Check whether a key in the configuration exists or not.
static getResponseError(\SAML2\StatusResponse $response)
Retrieve the status code of a response as a sspmod_saml_Error.
Definition: Message.php:417
static addSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\SignedElement $element)
Add signature key and sender certificate to an element (Message or Assertion).
Definition: Message.php:20
static buildLogoutRequest(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout request based on information in the metadata.
Definition: Message.php:501
static buildAuthnRequest(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata)
Build an authentication request based on information in the metadata.
Definition: Message.php:431
static checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
Check the signature on a SAML2 message or assertion.
Definition: Message.php:159
static getDecryptionKeys(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve the decryption keys from metadata.
Definition: Message.php:291
static decryptAssertion(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $assertion)
Decrypt an assertion.
Definition: Message.php:367
static buildLogoutResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout response based on information in the metadata.
Definition: Message.php:521
static processResponse(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response)
Process a response message.
Definition: Message.php:548
static getBlacklistedAlgorithms(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve blacklisted algorithms.
Definition: Message.php:342
static getEncryptionKey(SimpleSAML_Configuration $metadata)
Retrieve the encryption key for the given entity.
Definition: Message.php:829
static validateMessage(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Check signature on a SAML2 message if enabled.
Definition: Message.php:246
static processAssertion(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response, $assertion, $responseSigned)
Process an assertion in a response.
Definition: Message.php:601
static findCertificate(array $certFingerprints, array $certificates)
Find the certificate used to sign a message or assertion.
Definition: Message.php:124
static addRedirectSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Add signature key and and senders certificate to message.
Definition: Message.php:79
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
if($format !==null) $name
Definition: metadata.php:146
catch(Exception $e) $message
$lr
$idpMetadata
$spMetadata
$keys
$certificates
Definition: metarefresh.php:39
Attribute-related utility methods.
$ret
Definition: parser.php:6
$response
$algo
Definition: pwgen.php:34
foreach($_POST as $key=> $value) $res
$attributes
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$this data['403_header']