ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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 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 79 of file Message.php.

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 }
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 /*
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 }
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 431 of file Message.php.

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 }
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:79
$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 501 of file Message.php.

504 {
505 $lr = new \SAML2\LogoutRequest();
506 $lr->setIssuer($srcMetadata->getString('entityid'));
507
508 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
509
510 return $lr;
511 }
$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 521 of file Message.php.

524 {
525 $lr = new \SAML2\LogoutResponse();
526 $lr->setIssuer($srcMetadata->getString('entityid'));
527
528 self::addRedirectSign($srcMetadata, $dstMetadata, $lr);
529
530 return $lr;
531 }

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 159 of file Message.php.

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 }
static debug($string)
Definition: Logger.php:213
static notice($string)
Definition: Logger.php:190
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:124
$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 367 of file Message.php.

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 }
static getDecryptionKeys(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve the decryption keys from metadata.
Definition: Message.php:291
static getBlacklistedAlgorithms(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve blacklisted algorithms.
Definition: Message.php:342
$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:

◆ 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 124 of file Message.php.

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 }

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 342 of file Message.php.

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 }
getArray($name, $default=self::REQUIRED_OPTION)
This function retrieves an array configuration option.

References SimpleSAML_Configuration\getArray().

Referenced by decryptAssertion(), 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 291 of file Message.php.

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 }

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

Referenced by decryptAssertion(), 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 829 of file Message.php.

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 }
$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 417 of file Message.php.

418 {
419 $status = $response->getStatus();
420 return new sspmod_saml_Error($status['Code'], $status['SubCode'], $status['Message']);
421 }
$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 601 of file Message.php.

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 }
$spEntityId
static getSelfURLNoQuery()
Retrieve the current URL using the base URL in the configuration, without the query parameters.
Definition: HTTP.php:846
static decryptAssertion(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $assertion)
Decrypt an assertion.
Definition: Message.php:367
if($format !==null) $name
Definition: metadata.php:146
Attribute-related utility methods.
$attributes
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']
$this data['403_header']

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

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 548 of file Message.php.

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 }
static getResponseError(\SAML2\StatusResponse $response)
Retrieve the status code of a response as a sspmod_saml_Error.
Definition: Message.php:417
static checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
Check the signature on a SAML2 message or assertion.
Definition: Message.php:159
static processAssertion(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response, $assertion, $responseSigned)
Process an assertion in a response.
Definition: Message.php:601

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 246 of file Message.php.

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 }

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: