ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
sspmod_saml_Message Class Reference
+ Collaboration diagram for sspmod_saml_Message:

Static Public Member Functions

static addSign (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\SignedElement $element)
 Add signature key and sender certificate to an element (Message or Assertion). More...
 
static checkSign (SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
 Check the signature on a SAML2 message or assertion. More...
 
static validateMessage (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
 Check signature on a SAML2 message if enabled. More...
 
static getDecryptionKeys (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
 Retrieve the decryption keys from metadata. More...
 
static getBlacklistedAlgorithms (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
 Retrieve blacklisted algorithms. More...
 
static getResponseError (\SAML2\StatusResponse $response)
 Retrieve the status code of a response as a sspmod_saml_Error. More...
 
static buildAuthnRequest (SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata)
 Build an authentication request based on information in the metadata. More...
 
static buildLogoutRequest (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
 Build a logout request based on information in the metadata. More...
 
static buildLogoutResponse (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
 Build a logout response based on information in the metadata. More...
 
static processResponse (SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response)
 Process a response message. More...
 
static getEncryptionKey (SimpleSAML_Configuration $metadata)
 Retrieve the encryption key for the given entity. More...
 

Static Private Member Functions

static addRedirectSign (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
 Add signature key and and senders certificate to message. More...
 
static findCertificate (array $certFingerprints, array $certificates)
 Find the certificate used to sign a message or assertion. More...
 
static decryptAssertion (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $assertion)
 Decrypt an assertion. More...
 
static decryptAttributes (SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Assertion &$assertion)
 Decrypt any encrypted attributes in an assertion. More...
 
static processAssertion (SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response, $assertion, $responseSigned)
 Process an assertion in a response. More...
 

Detailed Description

Definition at line 10 of file Message.php.

Member Function Documentation

◆ addRedirectSign()

static sspmod_saml_Message::addRedirectSign ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata,
\SAML2\Message  $message 
)
staticprivate

Add signature key and and senders certificate to message.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
\SAML2\Message$messageThe message we should add the data to.

Definition at line 69 of file Message.php.

73 {
74
75 $signingEnabled = null;
76 if ($message instanceof \SAML2\LogoutRequest || $message instanceof \SAML2\LogoutResponse) {
77 $signingEnabled = $srcMetadata->getBoolean('sign.logout', null);
78 if ($signingEnabled === null) {
79 $signingEnabled = $dstMetadata->getBoolean('sign.logout', null);
80 }
81 } elseif ($message instanceof \SAML2\AuthnRequest) {
82 $signingEnabled = $srcMetadata->getBoolean('sign.authnrequest', null);
83 if ($signingEnabled === null) {
84 $signingEnabled = $dstMetadata->getBoolean('sign.authnrequest', null);
85 }
86 }
87
88 if ($signingEnabled === null) {
89 $signingEnabled = $dstMetadata->getBoolean('redirect.sign', null);
90 if ($signingEnabled === null) {
91 $signingEnabled = $srcMetadata->getBoolean('redirect.sign', false);
92 }
93 }
94 if (!$signingEnabled) {
95 return;
96 }
97
98 self::addSign($srcMetadata, $dstMetadata, $message);
99 }
getBoolean($name, $default=self::REQUIRED_OPTION)
This function retrieves a boolean configuration option.
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
catch(Exception $e) $message

References $message, addSign(), and SimpleSAML_Configuration\getBoolean().

Referenced by buildAuthnRequest(), buildLogoutRequest(), and buildLogoutResponse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ addSign()

static sspmod_saml_Message::addSign ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata,
\SAML2\SignedElement  $element 
)
static

Add signature key and sender certificate to an element (Message or Assertion).

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
\SAML2\SignedElement$elementThe element we should add the data to.

Definition at line 20 of file Message.php.

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 $algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
38 }
39
40 $privateKey = new XMLSecurityKey($algo, array('type' => 'private'));
41 if (array_key_exists('password', $keyArray)) {
42 $privateKey->passphrase = $keyArray['password'];
43 }
44 $privateKey->loadKey($keyArray['PEM'], false);
45
46 $element->setSignatureKey($privateKey);
47
48 if ($certArray === null) {
49 // we don't have a certificate to add
50 return;
51 }
52
53 if (!array_key_exists('PEM', $certArray)) {
54 // we have a public key with only a fingerprint
55 return;
56 }
57
58 $element->setCertificates(array($certArray['PEM']));
59 }
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
getString($name, $default=self::REQUIRED_OPTION)
This function retrieves a string configuration option.
$algo
Definition: pwgen.php:34

References $algo, SimpleSAML_Configuration\getString(), SimpleSAML\Utils\Crypto\loadPrivateKey(), and SimpleSAML\Utils\Crypto\loadPublicKey().

Referenced by addRedirectSign(), sspmod_saml_IdP_SAML2\buildAssertion(), and sspmod_saml_IdP_SAML2\buildResponse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildAuthnRequest()

static sspmod_saml_Message::buildAuthnRequest ( SimpleSAML_Configuration  $spMetadata,
SimpleSAML_Configuration  $idpMetadata 
)
static

Build an authentication request based on information in the metadata.

Parameters
SimpleSAML_Configuration$spMetadataThe metadata of the service provider.
SimpleSAML_Configuration$idpMetadataThe metadata of the identity provider.
Returns
\SAML2\AuthnRequest An authentication request object.

Definition at line 466 of file Message.php.

469 {
470 $ar = new \SAML2\AuthnRequest();
471
472 // get the NameIDPolicy to apply. IdP metadata has precedence.
473 $nameIdPolicy = array();
474 if ($idpMetadata->hasValue('NameIDPolicy')) {
475 $nameIdPolicy = $idpMetadata->getValue('NameIDPolicy');
476 } elseif ($spMetadata->hasValue('NameIDPolicy')) {
477 $nameIdPolicy = $spMetadata->getValue('NameIDPolicy');
478 }
479
480 if (!is_array($nameIdPolicy)) {
481 // handle old configurations where 'NameIDPolicy' was used to specify just the format
482 $nameIdPolicy = array('Format' => $nameIdPolicy);
483 }
484
485 $nameIdPolicy_cf = SimpleSAML_Configuration::loadFromArray($nameIdPolicy);
486 $policy = array(
487 'Format' => $nameIdPolicy_cf->getString('Format', \SAML2\Constants::NAMEID_TRANSIENT),
488 'AllowCreate' => $nameIdPolicy_cf->getBoolean('AllowCreate', true),
489 );
490 $spNameQualifier = $nameIdPolicy_cf->getString('SPNameQualifier', false);
491 if ($spNameQualifier !== false) {
492 $policy['SPNameQualifier'] = $spNameQualifier;
493 }
494 $ar->setNameIdPolicy($policy);
495
496 $ar->setForceAuthn($spMetadata->getBoolean('ForceAuthn', false));
497 $ar->setIsPassive($spMetadata->getBoolean('IsPassive', false));
498
499 $protbind = $spMetadata->getValueValidate('ProtocolBinding', array(
500 \SAML2\Constants::BINDING_HTTP_POST,
501 \SAML2\Constants::BINDING_HOK_SSO,
502 \SAML2\Constants::BINDING_HTTP_ARTIFACT,
503 \SAML2\Constants::BINDING_HTTP_REDIRECT,
504 ), \SAML2\Constants::BINDING_HTTP_POST);
505
506 // Shoaib: setting the appropriate binding based on parameter in sp-metadata defaults to HTTP_POST
507 $ar->setProtocolBinding($protbind);
508 $ar->setIssuer($spMetadata->getString('entityid'));
509 $ar->setAssertionConsumerServiceIndex($spMetadata->getInteger('AssertionConsumerServiceIndex', null));
510 $ar->setAttributeConsumingServiceIndex($spMetadata->getInteger('AttributeConsumingServiceIndex', null));
511
512 if ($spMetadata->hasValue('AuthnContextClassRef')) {
513 $accr = $spMetadata->getArrayizeString('AuthnContextClassRef');
514 $comp = $spMetadata->getValueValidate('AuthnContextComparison', array(
515 \SAML2\Constants::COMPARISON_EXACT,
516 \SAML2\Constants::COMPARISON_MINIMUM,
517 \SAML2\Constants::COMPARISON_MAXIMUM,
518 \SAML2\Constants::COMPARISON_BETTER,
519 ), \SAML2\Constants::COMPARISON_EXACT);
520 $ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
521 }
522
524
525 return $ar;
526 }
static loadFromArray($config, $location='[ARRAY]', $instance=null)
Loads a configuration from the given array.
static addRedirectSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Add signature key and and senders certificate to message.
Definition: Message.php:69
$idpMetadata
$spMetadata

References $idpMetadata, $spMetadata, addRedirectSign(), and SimpleSAML_Configuration\loadFromArray().

Referenced by sspmod_saml_Auth_Source_SP\startSSO2().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildLogoutRequest()

static sspmod_saml_Message::buildLogoutRequest ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata 
)
static

Build a logout request based on information in the metadata.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
Returns
\SAML2\LogoutRequest A logout request object.

Definition at line 536 of file Message.php.

539 {
540 $lr = new \SAML2\LogoutRequest();
541 $lr->setIssuer($srcMetadata->getString('entityid'));
542
543 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
544
545 return $lr;
546 }
$lr

References $lr, addRedirectSign(), and SimpleSAML_Configuration\getString().

Referenced by sspmod_saml_IdP_SAML2\buildLogoutRequest(), and sspmod_saml_Auth_Source_SP\startSLO2().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ buildLogoutResponse()

static sspmod_saml_Message::buildLogoutResponse ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata 
)
static

Build a logout response based on information in the metadata.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
Returns
\SAML2\LogoutResponse A logout response object.

Definition at line 556 of file Message.php.

559 {
560 $lr = new \SAML2\LogoutResponse();
561 $lr->setIssuer($srcMetadata->getString('entityid'));
562
563 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
564
565 return $lr;
566 }

References $lr, addRedirectSign(), and SimpleSAML_Configuration\getString().

Referenced by sspmod_saml_IdP_SAML2\sendLogoutResponse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ checkSign()

static sspmod_saml_Message::checkSign ( SimpleSAML_Configuration  $srcMetadata,
\SAML2\SignedElement  $element 
)
static

Check the signature on a SAML2 message or assertion.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
\SAML2\SignedElement$elementEither a \SAML2\Response or a \SAML2\Assertion.
Returns
boolean True if the signature is correct, false otherwise.
Exceptions

SimpleSAML_Error_Exception if there is not certificate in the metadata for the entity.

Exceptions

Exception if the signature validation fails with an exception.

Definition at line 149 of file Message.php.

150 {
151 // find the public key that should verify signatures by this entity
152 $keys = $srcMetadata->getPublicKeys('signing');
153 if (!empty($keys)) {
154 $pemKeys = array();
155 foreach ($keys as $key) {
156 switch ($key['type']) {
157 case 'X509Certificate':
158 $pemKeys[] = "-----BEGIN CERTIFICATE-----\n".
159 chunk_split($key['X509Certificate'], 64).
160 "-----END CERTIFICATE-----\n";
161 break;
162 default:
163 SimpleSAML\Logger::debug('Skipping unknown key type: '.$key['type']);
164 }
165 }
166 } elseif ($srcMetadata->hasValue('certFingerprint')) {
168 "Validating certificates by fingerprint is deprecated. Please use ".
169 "certData or certificate options in your remote metadata configuration."
170 );
171
172 $certFingerprint = $srcMetadata->getArrayizeString('certFingerprint');
173 foreach ($certFingerprint as &$fp) {
174 $fp = strtolower(str_replace(':', '', $fp));
175 }
176
177 $certificates = $element->getCertificates();
178
179 // we don't have the full certificate stored. Try to find it in the message or the assertion instead
180 if (count($certificates) === 0) {
181 /* We need the full certificate in order to match it against the fingerprint. */
182 SimpleSAML\Logger::debug('No certificate in message when validating against fingerprint.');
183 return false;
184 } else {
185 SimpleSAML\Logger::debug('Found '.count($certificates).' certificates in '.get_class($element));
186 }
187
188 $pemCert = self::findCertificate($certFingerprint, $certificates);
189 $pemKeys = array($pemCert);
190 } else {
192 'Missing certificate in metadata for '.
193 var_export($srcMetadata->getString('entityid'), true)
194 );
195 }
196
197 SimpleSAML\Logger::debug('Has '.count($pemKeys).' candidate keys for validation.');
198
199 $lastException = null;
200 foreach ($pemKeys as $i => $pem) {
201 $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'public'));
202 $key->loadKey($pem);
203
204 try {
205 // make sure that we have a valid signature on either the response or the assertion
206 $res = $element->validate($key);
207 if ($res) {
208 SimpleSAML\Logger::debug('Validation with key #'.$i.' succeeded.');
209 return true;
210 }
211 SimpleSAML\Logger::debug('Validation with key #'.$i.' failed without exception.');
212 } catch (Exception $e) {
213 SimpleSAML\Logger::debug('Validation with key #'.$i.' failed with exception: '.$e->getMessage());
214 $lastException = $e;
215 }
216 }
217
218 // we were unable to validate the signature with any of our keys
219 if ($lastException !== null) {
220 throw $lastException;
221 } else {
222 return false;
223 }
224 }
static debug($string)
Definition: Logger.php:211
static notice($string)
Definition: Logger.php:188
getArrayizeString($name, $default=self::REQUIRED_OPTION)
This function retrieves a configuration option with a string or an array of strings.
getPublicKeys($use=null, $required=false, $prefix='')
Get public key from metadata.
hasValue($name)
Check whether a key in the configuration exists or not.
static findCertificate(array $certFingerprints, array $certificates)
Find the certificate used to sign a message or assertion.
Definition: Message.php:114
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
$keys
$certificates
Definition: metarefresh.php:39
foreach($_POST as $key=> $value) $res

References $certificates, $i, $key, $keys, $res, SimpleSAML\Logger\debug(), findCertificate(), SimpleSAML_Configuration\getArrayizeString(), SimpleSAML_Configuration\getPublicKeys(), SimpleSAML_Configuration\getString(), SimpleSAML_Configuration\hasValue(), and SimpleSAML\Logger\notice().

Referenced by processResponse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decryptAssertion()

static sspmod_saml_Message::decryptAssertion ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata,
  $assertion 
)
staticprivate

Decrypt an assertion.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender (IdP).
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient (SP).
\SAML2\Assertion | \SAML2\EncryptedAssertion$assertionThe assertion we are decrypting.
Returns
\SAML2\Assertion The assertion.
Exceptions

SimpleSAML_Error_Exception if encryption is enabled but the assertion is not encrypted, or if we cannot get the decryption keys.

Exceptions

Exception if decryption fails for whatever reason.

Definition at line 357 of file Message.php.

361 {
362 assert($assertion instanceof \SAML2\Assertion || $assertion instanceof \SAML2\EncryptedAssertion);
363
364 if ($assertion instanceof \SAML2\Assertion) {
365 $encryptAssertion = $srcMetadata->getBoolean('assertion.encryption', null);
366 if ($encryptAssertion === null) {
367 $encryptAssertion = $dstMetadata->getBoolean('assertion.encryption', false);
368 }
369 if ($encryptAssertion) {
370 /* The assertion was unencrypted, but we have encryption enabled. */
371 throw new Exception('Received unencrypted assertion, but encryption was enabled.');
372 }
373
374 return $assertion;
375 }
376
377 try {
378 $keys = self::getDecryptionKeys($srcMetadata, $dstMetadata);
379 } catch (Exception $e) {
380 throw new SimpleSAML_Error_Exception('Error decrypting assertion: '.$e->getMessage());
381 }
382
383 $blacklist = self::getBlacklistedAlgorithms($srcMetadata, $dstMetadata);
384
385 $lastException = null;
386 foreach ($keys as $i => $key) {
387 try {
388 $ret = $assertion->getAssertion($key, $blacklist);
389 SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
390 return $ret;
391 } catch (Exception $e) {
392 SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
393 $lastException = $e;
394 }
395 }
396 throw $lastException;
397 }
static getDecryptionKeys(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve the decryption keys from metadata.
Definition: Message.php:281
static getBlacklistedAlgorithms(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve blacklisted algorithms.
Definition: Message.php:332
$ret
Definition: parser.php:6

References $i, $key, $keys, $ret, SimpleSAML\Logger\debug(), getBlacklistedAlgorithms(), SimpleSAML_Configuration\getBoolean(), and getDecryptionKeys().

Referenced by processAssertion().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ decryptAttributes()

static sspmod_saml_Message::decryptAttributes ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata,
\SAML2\Assertion $assertion 
)
staticprivate

Decrypt any encrypted attributes in an assertion.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender (IdP).
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient (SP).
\SAML2\Assertion | \SAML2\Assertion$assertionThe assertion containing any possibly encrypted attributes.
Returns
void
Exceptions

SimpleSAML_Error_Exception if we cannot get the decryption keys or decryption fails.

Definition at line 411 of file Message.php.

415 {
416 if (!$assertion->hasEncryptedAttributes()) {
417 return;
418 }
419
420 try {
421 $keys = self::getDecryptionKeys($srcMetadata, $dstMetadata);
422 } catch (Exception $e) {
423 throw new SimpleSAML_Error_Exception('Error decrypting attributes: '.$e->getMessage());
424 }
425
426 $blacklist = self::getBlacklistedAlgorithms($srcMetadata, $dstMetadata);
427
428 $error = true;
429 foreach ($keys as $i => $key) {
430 try {
431 $assertion->decryptAttributes($key, $blacklist);
432 SimpleSAML\Logger::debug('Attribute decryption with key #'.$i.' succeeded.');
433 $error = false;
434 break;
435 } catch (Exception $e) {
436 SimpleSAML\Logger::debug('Attribute decryption failed with exception: '.$e->getMessage());
437 }
438 }
439 if ($error) {
440 throw new SimpleSAML_Error_Exception('Could not decrypt the attributes');
441 }
442 }

References $i, $key, $keys, SimpleSAML\Logger\debug(), getBlacklistedAlgorithms(), and getDecryptionKeys().

Referenced by processAssertion().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ findCertificate()

static sspmod_saml_Message::findCertificate ( array  $certFingerprints,
array  $certificates 
)
staticprivate

Find the certificate used to sign a message or assertion.

An exception is thrown if we are unable to locate the certificate.

Parameters
array$certFingerprintsThe fingerprints we are looking for.
array$certificatesArray of certificates.
Returns
string Certificate, in PEM-format.
Exceptions
SimpleSAML_Error_Exceptionif we cannot find the certificate matching the fingerprint.

Definition at line 114 of file Message.php.

115 {
116 $candidates = array();
117
118 foreach ($certificates as $cert) {
119 $fp = strtolower(sha1(base64_decode($cert)));
120 if (!in_array($fp, $certFingerprints, true)) {
121 $candidates[] = $fp;
122 continue;
123 }
124
125 /* We have found a matching fingerprint. */
126 $pem = "-----BEGIN CERTIFICATE-----\n".
127 chunk_split($cert, 64).
128 "-----END CERTIFICATE-----\n";
129 return $pem;
130 }
131
132 $candidates = "'".implode("', '", $candidates)."'";
133 $fps = "'".implode("', '", $certFingerprints)."'";
134 throw new SimpleSAML_Error_Exception('Unable to find a certificate matching the configured '.
135 'fingerprint. Candidates: '.$candidates.'; certFingerprint: '.$fps.'.');
136 }

References $certificates.

Referenced by checkSign().

+ Here is the caller graph for this function:

◆ getBlacklistedAlgorithms()

static sspmod_saml_Message::getBlacklistedAlgorithms ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata 
)
static

Retrieve blacklisted algorithms.

Remote configuration overrides local configuration.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
Returns
array Array of blacklisted algorithms.

Definition at line 332 of file Message.php.

335 {
336 $blacklist = $srcMetadata->getArray('encryption.blacklisted-algorithms', null);
337 if ($blacklist === null) {
338 $blacklist = $dstMetadata->getArray('encryption.blacklisted-algorithms', array(XMLSecurityKey::RSA_1_5));
339 }
340 return $blacklist;
341 }
getArray($name, $default=self::REQUIRED_OPTION)
This function retrieves an array configuration option.

References SimpleSAML_Configuration\getArray().

Referenced by decryptAssertion(), decryptAttributes(), and processAssertion().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getDecryptionKeys()

static sspmod_saml_Message::getDecryptionKeys ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata 
)
static

Retrieve the decryption keys from metadata.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender (IdP).
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient (SP).
Returns
array Array of decryption keys.

Definition at line 281 of file Message.php.

284 {
285 $sharedKey = $srcMetadata->getString('sharedkey', null);
286 if ($sharedKey !== null) {
287 $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
288 $key->loadKey($sharedKey);
289 return array($key);
290 }
291
292 $keys = array();
293
294 // load the new private key if it exists
295 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, false, 'new_');
296 if ($keyArray !== null) {
297 assert(isset($keyArray['PEM']));
298
299 $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
300 if (array_key_exists('password', $keyArray)) {
301 $key->passphrase = $keyArray['password'];
302 }
303 $key->loadKey($keyArray['PEM']);
304 $keys[] = $key;
305 }
306
307 // find the existing private key
308 $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true);
309 assert(isset($keyArray['PEM']));
310
311 $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
312 if (array_key_exists('password', $keyArray)) {
313 $key->passphrase = $keyArray['password'];
314 }
315 $key->loadKey($keyArray['PEM']);
316 $keys[] = $key;
317
318 return $keys;
319 }

References $key, $keys, SimpleSAML_Configuration\getString(), and SimpleSAML\Utils\Crypto\loadPrivateKey().

Referenced by decryptAssertion(), decryptAttributes(), and processAssertion().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getEncryptionKey()

static sspmod_saml_Message::getEncryptionKey ( SimpleSAML_Configuration  $metadata)
static

Retrieve the encryption key for the given entity.

Parameters
SimpleSAML_Configuration$metadataThe metadata of the entity.
Returns
\RobRichards\XMLSecLibs\XMLSecurityKey The encryption key.
Exceptions

SimpleSAML_Error_Exception if there is no supported encryption key in the metadata of this entity.

Definition at line 865 of file Message.php.

866 {
867
868 $sharedKey = $metadata->getString('sharedkey', null);
869 if ($sharedKey !== null) {
870 $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
871 $key->loadKey($sharedKey);
872 return $key;
873 }
874
875 $keys = $metadata->getPublicKeys('encryption', true);
876 foreach ($keys as $key) {
877 switch ($key['type']) {
878 case 'X509Certificate':
879 $pemKey = "-----BEGIN CERTIFICATE-----\n".
880 chunk_split($key['X509Certificate'], 64).
881 "-----END CERTIFICATE-----\n";
882 $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
883 $key->loadKey($pemKey);
884 return $key;
885 }
886 }
887
888 throw new SimpleSAML_Error_Exception('No supported encryption key in '.
889 var_export($metadata->getString('entityid'), true));
890 }
$metadata['__DYNAMIC:1__']

References $key, $keys, and $metadata.

Referenced by sspmod_saml_IdP_SAML2\buildAssertion(), sspmod_saml_IdP_SAML2\buildLogoutRequest(), and sspmod_saml_Auth_Source_SP\startSLO2().

+ Here is the caller graph for this function:

◆ getResponseError()

static sspmod_saml_Message::getResponseError ( \SAML2\StatusResponse  $response)
static

Retrieve the status code of a response as a sspmod_saml_Error.

Parameters
\SAML2\StatusResponse$responseThe response.
Returns
sspmod_saml_Error The error.

Definition at line 452 of file Message.php.

453 {
454 $status = $response->getStatus();
455 return new sspmod_saml_Error($status['Code'], $status['SubCode'], $status['Message']);
456 }
$response

References $response.

Referenced by processResponse(), and sspmod_saml_IdP_SAML2\receiveLogoutMessage().

+ Here is the caller graph for this function:

◆ processAssertion()

static sspmod_saml_Message::processAssertion ( SimpleSAML_Configuration  $spMetadata,
SimpleSAML_Configuration  $idpMetadata,
\SAML2\Response  $response,
  $assertion,
  $responseSigned 
)
staticprivate

Process an assertion in a response.

Parameters
SimpleSAML_Configuration$spMetadataThe metadata of the service provider.
SimpleSAML_Configuration$idpMetadataThe metadata of the identity provider.
\SAML2\Response$responseThe response containing the assertion.
\SAML2\Assertion | \SAML2\EncryptedAssertion$assertionThe assertion.
bool$responseSignedWhether the response is signed.
Returns
\SAML2\Assertion The assertion, if it is valid.
Exceptions

SimpleSAML_Error_Exception if an error occurs while trying to validate the assertion, or if a assertion is not signed and it should be, or if we are unable to decrypt the NameID due to a local failure (missing or invalid decryption key).

Exceptions

Exception if we couldn't decrypt the NameID for unexpected reasons.

Definition at line 636 of file Message.php.

642 {
643 assert($assertion instanceof \SAML2\Assertion || $assertion instanceof \SAML2\EncryptedAssertion);
644 assert(is_bool($responseSigned));
645
646 $assertion = self::decryptAssertion($idpMetadata, $spMetadata, $assertion);
648
649 if (!self::checkSign($idpMetadata, $assertion)) {
650 if (!$responseSigned) {
651 throw new SimpleSAML_Error_Exception('Neither the assertion nor the response was signed.');
652 }
653 } // at least one valid signature found
654
656
657 // check various properties of the assertion
658 $notBefore = $assertion->getNotBefore();
659 if ($notBefore !== null && $notBefore > time() + 60) {
661 'Received an assertion that is valid in the future. Check clock synchronization on IdP and SP.'
662 );
663 }
664 $notOnOrAfter = $assertion->getNotOnOrAfter();
665 if ($notOnOrAfter !== null && $notOnOrAfter <= time() - 60) {
667 'Received an assertion that has expired. Check clock synchronization on IdP and SP.'
668 );
669 }
670 $sessionNotOnOrAfter = $assertion->getSessionNotOnOrAfter();
671 if ($sessionNotOnOrAfter !== null && $sessionNotOnOrAfter <= time() - 60) {
673 'Received an assertion with a session that has expired. Check clock synchronization on IdP and SP.'
674 );
675 }
676 $validAudiences = $assertion->getValidAudiences();
677 if ($validAudiences !== null) {
678 $spEntityId = $spMetadata->getString('entityid');
679 if (!in_array($spEntityId, $validAudiences, true)) {
680 $candidates = '['.implode('], [', $validAudiences).']';
681 throw new SimpleSAML_Error_Exception('This SP ['.$spEntityId.
682 '] is not a valid audience for the assertion. Candidates were: '.$candidates);
683 }
684 }
685
686 $found = false;
687 $lastError = 'No SubjectConfirmation element in Subject.';
688 $validSCMethods = array(\SAML2\Constants::CM_BEARER, \SAML2\Constants::CM_HOK, \SAML2\Constants::CM_VOUCHES);
689 foreach ($assertion->getSubjectConfirmation() as $sc) {
690 if (!in_array($sc->Method, $validSCMethods, true)) {
691 $lastError = 'Invalid Method on SubjectConfirmation: '.var_export($sc->Method, true);
692 continue;
693 }
694
695 // is SSO with HoK enabled? IdP remote metadata overwrites SP metadata configuration
696 $hok = $idpMetadata->getBoolean('saml20.hok.assertion', null);
697 if ($hok === null) {
698 $hok = $spMetadata->getBoolean('saml20.hok.assertion', false);
699 }
700 if ($sc->Method === \SAML2\Constants::CM_BEARER && $hok) {
701 $lastError = 'Bearer SubjectConfirmation received, but Holder-of-Key SubjectConfirmation needed';
702 continue;
703 }
704 if ($sc->Method === \SAML2\Constants::CM_HOK && !$hok) {
705 $lastError = 'Holder-of-Key SubjectConfirmation received, '.
706 'but the Holder-of-Key profile is not enabled.';
707 continue;
708 }
709
710 $scd = $sc->SubjectConfirmationData;
711 if ($sc->Method === \SAML2\Constants::CM_HOK) {
712 // check HoK Assertion
713 if (\SimpleSAML\Utils\HTTP::isHTTPS() === false) {
714 $lastError = 'No HTTPS connection, but required for Holder-of-Key SSO';
715 continue;
716 }
717 if (isset($_SERVER['SSL_CLIENT_CERT']) && empty($_SERVER['SSL_CLIENT_CERT'])) {
718 $lastError = 'No client certificate provided during TLS Handshake with SP';
719 continue;
720 }
721 // extract certificate data (if this is a certificate)
722 $clientCert = $_SERVER['SSL_CLIENT_CERT'];
723 $pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
724 if (!preg_match($pattern, $clientCert, $matches)) {
725 $lastError = 'Error while looking for client certificate during TLS handshake with SP, the client '.
726 'certificate does not have the expected structure';
727 continue;
728 }
729 // we have a valid client certificate from the browser
730 $clientCert = str_replace(array("\r", "\n", " "), '', $matches[1]);
731
732 $keyInfo = array();
733 foreach ($scd->info as $thing) {
734 if ($thing instanceof \SAML2\XML\ds\KeyInfo) {
735 $keyInfo[] = $thing;
736 }
737 }
738 if (count($keyInfo) != 1) {
739 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:KeyInfo> element in '.
740 '<SubjectConfirmationData> allowed';
741 continue;
742 }
743
744 $x509data = array();
745 foreach ($keyInfo[0]->info as $thing) {
746 if ($thing instanceof \SAML2\XML\ds\X509Data) {
747 $x509data[] = $thing;
748 }
749 }
750 if (count($x509data) != 1) {
751 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:X509Data> element in '.
752 '<ds:KeyInfo> within <SubjectConfirmationData> allowed';
753 continue;
754 }
755
756 $x509cert = array();
757 foreach ($x509data[0]->data as $thing) {
758 if ($thing instanceof \SAML2\XML\ds\X509Certificate) {
759 $x509cert[] = $thing;
760 }
761 }
762 if (count($x509cert) != 1) {
763 $lastError = 'Error validating Holder-of-Key assertion: Only one <ds:X509Certificate> element in '.
764 '<ds:X509Data> within <SubjectConfirmationData> allowed';
765 continue;
766 }
767
768 $HoKCertificate = $x509cert[0]->certificate;
769 if ($HoKCertificate !== $clientCert) {
770 $lastError = 'Provided client certificate does not match the certificate bound to the '.
771 'Holder-of-Key assertion';
772 continue;
773 }
774 }
775
776 // if no SubjectConfirmationData then don't do anything.
777 if ($scd === null) {
778 $lastError = 'No SubjectConfirmationData provided';
779 continue;
780 }
781
782 if ($scd->NotBefore && $scd->NotBefore > time() + 60) {
783 $lastError = 'NotBefore in SubjectConfirmationData is in the future: '.$scd->NotBefore;
784 continue;
785 }
786 if ($scd->NotOnOrAfter && $scd->NotOnOrAfter <= time() - 60) {
787 $lastError = 'NotOnOrAfter in SubjectConfirmationData is in the past: '.$scd->NotOnOrAfter;
788 continue;
789 }
790 if ($scd->Recipient !== null && $scd->Recipient !== $currentURL) {
791 $lastError = 'Recipient in SubjectConfirmationData does not match the current URL. Recipient is '.
792 var_export($scd->Recipient, true).', current URL is '.var_export($currentURL, true).'.';
793 continue;
794 }
795 if ($scd->InResponseTo !== null && $response->getInResponseTo() !== null &&
796 $scd->InResponseTo !== $response->getInResponseTo()
797 ) {
798 $lastError = 'InResponseTo in SubjectConfirmationData does not match the Response. Response has '.
799 var_export($response->getInResponseTo(), true).
800 ', SubjectConfirmationData has '.var_export($scd->InResponseTo, true).'.';
801 continue;
802 }
803 $found = true;
804 break;
805 }
806 if (!$found) {
807 throw new SimpleSAML_Error_Exception('Error validating SubjectConfirmation in Assertion: '.$lastError);
808 } // as far as we can tell, the assertion is valid
809
810 // maybe we need to base64 decode the attributes in the assertion?
811 if ($idpMetadata->getBoolean('base64attributes', false)) {
812 $attributes = $assertion->getAttributes();
813 $newAttributes = array();
814 foreach ($attributes as $name => $values) {
815 $newAttributes[$name] = array();
816 foreach ($values as $value) {
817 foreach (explode('_', $value) as $v) {
818 $newAttributes[$name][] = base64_decode($v);
819 }
820 }
821 }
822 $assertion->setAttributes($newAttributes);
823 }
824
825 // decrypt the NameID element if it is encrypted
826 if ($assertion->isNameIdEncrypted()) {
827 try {
829 } catch (Exception $e) {
830 throw new SimpleSAML_Error_Exception('Error decrypting NameID: '.$e->getMessage());
831 }
832
834
835 $lastException = null;
836 foreach ($keys as $i => $key) {
837 try {
838 $assertion->decryptNameId($key, $blacklist);
839 SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
840 $lastException = null;
841 break;
842 } catch (Exception $e) {
843 SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
844 $lastException = $e;
845 }
846 }
847 if ($lastException !== null) {
848 throw $lastException;
849 }
850 }
851
852 return $assertion;
853 }
$spEntityId
static getSelfURLNoQuery()
Retrieve the current URL using the base URL in the configuration, without the query parameters.
Definition: HTTP.php:843
static decryptAssertion(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $assertion)
Decrypt an assertion.
Definition: Message.php:357
static decryptAttributes(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Assertion &$assertion)
Decrypt any encrypted attributes in an assertion.
Definition: Message.php:411
if(array_key_exists('yes', $_REQUEST)) $attributes
Definition: getconsent.php:85
info()
Definition: info.php:2
Attribute-related utility methods.
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$this data['403_header']
$values

References $_SERVER, $attributes, $i, $idpMetadata, $key, $keys, $name, $response, $sc, $spEntityId, $spMetadata, $values, data, SimpleSAML\Logger\debug(), decryptAssertion(), decryptAttributes(), getBlacklistedAlgorithms(), getDecryptionKeys(), SimpleSAML\Utils\HTTP\getSelfURLNoQuery(), and info().

Referenced by processResponse().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ processResponse()

static sspmod_saml_Message::processResponse ( SimpleSAML_Configuration  $spMetadata,
SimpleSAML_Configuration  $idpMetadata,
\SAML2\Response  $response 
)
static

Process a response message.

If the response is an error response, we will throw a sspmod_saml_Error exception with the error.

Parameters
SimpleSAML_Configuration$spMetadataThe metadata of the service provider.
SimpleSAML_Configuration$idpMetadataThe metadata of the identity provider.
\SAML2\Response$responseThe response.
Returns
array Array with \SAML2\Assertion objects, containing valid assertions from the response.
Exceptions

SimpleSAML_Error_Exception if there are no assertions in the response.

Exceptions

Exception if the destination of the response does not match the current URL.

Definition at line 583 of file Message.php.

587 {
588 if (!$response->isSuccess()) {
590 }
591
592 // validate Response-element destination
594 $msgDestination = $response->getDestination();
595 if ($msgDestination !== null && $msgDestination !== $currentURL) {
596 throw new Exception('Destination in response doesn\'t match the current URL. Destination is "'.
597 $msgDestination.'", current URL is "'.$currentURL.'".');
598 }
599
600 $responseSigned = self::checkSign($idpMetadata, $response);
601
602 /*
603 * When we get this far, the response itself is valid.
604 * We only need to check signatures and conditions of the response.
605 */
606 $assertion = $response->getAssertions();
607 if (empty($assertion)) {
608 throw new SimpleSAML_Error_Exception('No assertions found in response from IdP.');
609 }
610
611 $ret = array();
612 foreach ($assertion as $a) {
614 }
615
616 return $ret;
617 }
static getResponseError(\SAML2\StatusResponse $response)
Retrieve the status code of a response as a sspmod_saml_Error.
Definition: Message.php:452
static checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
Check the signature on a SAML2 message or assertion.
Definition: Message.php:149
static processAssertion(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response, $assertion, $responseSigned)
Process an assertion in a response.
Definition: Message.php:636

References $idpMetadata, $response, $ret, $spMetadata, checkSign(), getResponseError(), SimpleSAML\Utils\HTTP\getSelfURLNoQuery(), and processAssertion().

+ Here is the call graph for this function:

◆ validateMessage()

static sspmod_saml_Message::validateMessage ( SimpleSAML_Configuration  $srcMetadata,
SimpleSAML_Configuration  $dstMetadata,
\SAML2\Message  $message 
)
static

Check signature on a SAML2 message if enabled.

Parameters
SimpleSAML_Configuration$srcMetadataThe metadata of the sender.
SimpleSAML_Configuration$dstMetadataThe metadata of the recipient.
\SAML2\Message$messageThe message we should check the signature on.
Exceptions

SimpleSAML_Error_Exception if message validation is enabled, but there is no signature in the message.

Definition at line 236 of file Message.php.

240 {
241 $enabled = null;
242 if ($message instanceof \SAML2\LogoutRequest || $message instanceof \SAML2\LogoutResponse) {
243 $enabled = $srcMetadata->getBoolean('validate.logout', null);
244 if ($enabled === null) {
245 $enabled = $dstMetadata->getBoolean('validate.logout', null);
246 }
247 } elseif ($message instanceof \SAML2\AuthnRequest) {
248 $enabled = $srcMetadata->getBoolean('validate.authnrequest', null);
249 if ($enabled === null) {
250 $enabled = $dstMetadata->getBoolean('validate.authnrequest', null);
251 }
252 }
253
254 if ($enabled === null) {
255 $enabled = $srcMetadata->getBoolean('redirect.validate', null);
256 if ($enabled === null) {
257 $enabled = $dstMetadata->getBoolean('redirect.validate', false);
258 }
259 }
260
261 if (!$enabled) {
262 return;
263 }
264
265 if (!self::checkSign($srcMetadata, $message)) {
267 'Validation of received messages enabled, but no signature found on message.'
268 );
269 }
270 }

References $message, and SimpleSAML_Configuration\getBoolean().

Referenced by sspmod_saml_IdP_SAML2\receiveAuthnRequest(), and sspmod_saml_IdP_SAML2\receiveLogoutMessage().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

The documentation for this class was generated from the following file: