23        \
SAML2\SignedElement $element
 
   25        $dstPrivateKey = $dstMetadata->
getString(
'signature.privatekey', 
null);
 
   27        if ($dstPrivateKey !== 
null) {
 
   37            $algo = $srcMetadata->
getString(
'signature.algorithm', XMLSecurityKey::RSA_SHA256);
 
   41        if (array_key_exists(
'password', $keyArray)) {
 
   42            $privateKey->passphrase = $keyArray[
'password'];
 
   44        $privateKey->loadKey($keyArray[
'PEM'], 
false);
 
   46        $element->setSignatureKey($privateKey);
 
   48        if ($certArray === 
null) {
 
   53        if (!array_key_exists(
'PEM', $certArray)) {
 
   58        $element->setCertificates(array($certArray[
'PEM']));
 
   75        $signingEnabled = 
null;
 
   77            $signingEnabled = $srcMetadata->
getBoolean(
'sign.logout', 
null);
 
   78            if ($signingEnabled === 
null) {
 
   79                $signingEnabled = $dstMetadata->
getBoolean(
'sign.logout', 
null);
 
   82            $signingEnabled = $srcMetadata->
getBoolean(
'sign.authnrequest', 
null);
 
   83            if ($signingEnabled === 
null) {
 
   84                $signingEnabled = $dstMetadata->
getBoolean(
'sign.authnrequest', 
null);
 
   88        if ($signingEnabled === 
null) {
 
   89            $signingEnabled = $dstMetadata->
getBoolean(
'redirect.sign', 
null);
 
   90            if ($signingEnabled === 
null) {
 
   91                $signingEnabled = $srcMetadata->
getBoolean(
'redirect.sign', 
false);
 
   94        if (!$signingEnabled) {
 
  116        $candidates = array();
 
  119            $fp = strtolower(sha1(base64_decode($cert)));
 
  120            if (!in_array($fp, $certFingerprints, 
true)) {
 
  126            $pem = 
"-----BEGIN CERTIFICATE-----\n".
 
  127                chunk_split($cert, 64).
 
  128                "-----END CERTIFICATE-----\n";
 
  132        $candidates = 
"'".implode(
"', '", $candidates).
"'";
 
  133        $fps = 
"'".implode(
"', '", $certFingerprints).
"'";
 
  135            'fingerprint. Candidates: '.$candidates.
'; certFingerprint: '.$fps.
'.');
 
  156                switch (
$key[
'type']) {
 
  157                    case 'X509Certificate':
 
  158                        $pemKeys[] = 
"-----BEGIN CERTIFICATE-----\n".
 
  159                            chunk_split(
$key[
'X509Certificate'], 64).
 
  160                            "-----END CERTIFICATE-----\n";
 
  166        } elseif ($srcMetadata->
hasValue(
'certFingerprint')) {
 
  168                "Validating certificates by fingerprint is deprecated. Please use ".
 
  169                "certData or certificate options in your remote metadata configuration." 
  173            foreach ($certFingerprint as &$fp) {
 
  174                $fp = strtolower(str_replace(
':', 
'', $fp));
 
  189            $pemKeys = array($pemCert);
 
  192                'Missing certificate in metadata for '.
 
  193                var_export($srcMetadata->
getString(
'entityid'), 
true)
 
  199        $lastException = 
null;
 
  200        foreach ($pemKeys as 
$i => $pem) {
 
  212            } 
catch (Exception $e) {
 
  219        if ($lastException !== 
null) {
 
  220            throw $lastException;
 
  243            $enabled = $srcMetadata->
getBoolean(
'validate.logout', 
null);
 
  244            if ($enabled === 
null) {
 
  245                $enabled = $dstMetadata->
getBoolean(
'validate.logout', 
null);
 
  248            $enabled = $srcMetadata->
getBoolean(
'validate.authnrequest', 
null);
 
  249            if ($enabled === 
null) {
 
  250                $enabled = $dstMetadata->
getBoolean(
'validate.authnrequest', 
null);
 
  254        if ($enabled === 
null) {
 
  255            $enabled = $srcMetadata->
getBoolean(
'redirect.validate', 
null);
 
  256            if ($enabled === 
null) {
 
  257                $enabled = $dstMetadata->
getBoolean(
'redirect.validate', 
false);
 
  265        if (!self::checkSign($srcMetadata, 
$message)) {
 
  267                'Validation of received messages enabled, but no signature found on message.' 
  285        $sharedKey = $srcMetadata->
getString(
'sharedkey', 
null);
 
  286        if ($sharedKey !== 
null) {
 
  288            $key->loadKey($sharedKey);
 
  296        if ($keyArray !== 
null) {
 
  297            assert(isset($keyArray[
'PEM']));
 
  300            if (array_key_exists(
'password', $keyArray)) {
 
  301                $key->passphrase = $keyArray[
'password'];
 
  303            $key->loadKey($keyArray[
'PEM']);
 
  309        assert(isset($keyArray[
'PEM']));
 
  312        if (array_key_exists(
'password', $keyArray)) {
 
  313            $key->passphrase = $keyArray[
'password'];
 
  315        $key->loadKey($keyArray[
'PEM']);
 
  336        $blacklist = $srcMetadata->
getArray(
'encryption.blacklisted-algorithms', 
null);
 
  337        if ($blacklist === 
null) {
 
  338            $blacklist = $dstMetadata->
getArray(
'encryption.blacklisted-algorithms', array(XMLSecurityKey::RSA_1_5));
 
  362        assert($assertion instanceof \
SAML2\Assertion || $assertion instanceof \
SAML2\EncryptedAssertion);
 
  364        if ($assertion instanceof \
SAML2\Assertion) {
 
  365            $encryptAssertion = $srcMetadata->
getBoolean(
'assertion.encryption', 
null);
 
  366            if ($encryptAssertion === 
null) {
 
  367                $encryptAssertion = $dstMetadata->
getBoolean(
'assertion.encryption', 
false);
 
  369            if ($encryptAssertion) {
 
  371                throw new Exception(
'Received unencrypted assertion, but encryption was enabled.');
 
  379        } 
catch (Exception $e) {
 
  385        $lastException = 
null;
 
  388                $ret = $assertion->getAssertion(
$key, $blacklist);
 
  391            } 
catch (Exception $e) {
 
  396        throw $lastException;
 
  414        \
SAML2\Assertion &$assertion
 
  416        if (!$assertion->hasEncryptedAttributes()) {
 
  422        } 
catch (Exception $e) {
 
  431                $assertion->decryptAttributes(
$key, $blacklist);
 
  435            } 
catch (Exception $e) {
 
  455        return new sspmod_saml_Error($status[
'Code'], $status[
'SubCode'], $status[
'Message']);
 
  470        $ar = new \SAML2\AuthnRequest();
 
  473        $nameIdPolicy = array();
 
  477            $nameIdPolicy = 
$spMetadata->getValue(
'NameIDPolicy');
 
  480        if (!is_array($nameIdPolicy)) {
 
  482            $nameIdPolicy = array(
'Format' => $nameIdPolicy);
 
  487            'Format'      => $nameIdPolicy_cf->getString(
'Format', \
SAML2\Constants::NAMEID_TRANSIENT),
 
  488            'AllowCreate' => $nameIdPolicy_cf->getBoolean(
'AllowCreate', 
true),
 
  490        $spNameQualifier = $nameIdPolicy_cf->getString(
'SPNameQualifier', 
false);
 
  491        if ($spNameQualifier !== 
false) {
 
  492            $policy[
'SPNameQualifier'] = $spNameQualifier;
 
  494        $ar->setNameIdPolicy($policy);
 
  496        $ar->setForceAuthn(
$spMetadata->getBoolean(
'ForceAuthn', 
false));
 
  497        $ar->setIsPassive(
$spMetadata->getBoolean(
'IsPassive', 
false));
 
  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);
 
  507        $ar->setProtocolBinding($protbind);
 
  508        $ar->setIssuer(
$spMetadata->getString(
'entityid'));
 
  509        $ar->setAssertionConsumerServiceIndex(
$spMetadata->getInteger(
'AssertionConsumerServiceIndex', 
null));
 
  510        $ar->setAttributeConsumingServiceIndex(
$spMetadata->getInteger(
'AttributeConsumingServiceIndex', 
null));
 
  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));
 
  540        $lr = new \SAML2\LogoutRequest();
 
  560        $lr = new \SAML2\LogoutResponse();
 
  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.
'".');
 
  607        if (empty($assertion)) {
 
  612        foreach ($assertion as $a) {
 
  643        assert($assertion instanceof \
SAML2\Assertion || $assertion instanceof \
SAML2\EncryptedAssertion);
 
  644        assert(is_bool($responseSigned));
 
  650            if (!$responseSigned) {
 
  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.' 
  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.' 
  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.' 
  676        $validAudiences = $assertion->getValidAudiences();
 
  677        if ($validAudiences !== 
null) {
 
  679            if (!in_array(
$spEntityId, $validAudiences, 
true)) {
 
  680                $candidates = 
'['.implode(
'], [', $validAudiences).
']';
 
  682                    ']  is not a valid audience for the assertion. Candidates were: '.$candidates);
 
  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);
 
  696            $hok = 
$idpMetadata->getBoolean(
'saml20.hok.assertion', 
null);
 
  698                $hok = 
$spMetadata->getBoolean(
'saml20.hok.assertion', 
false);
 
  700            if (
$sc->Method === \
SAML2\Constants::CM_BEARER && $hok) {
 
  701                $lastError = 
'Bearer SubjectConfirmation received, but Holder-of-Key SubjectConfirmation needed';
 
  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.';
 
  710            $scd = 
$sc->SubjectConfirmationData;
 
  711            if (
$sc->Method === \
SAML2\Constants::CM_HOK) {
 
  713                if (\
SimpleSAML\Utils\HTTP::isHTTPS() === 
false) {
 
  714                    $lastError = 
'No HTTPS connection, but required for Holder-of-Key SSO';
 
  717                if (isset(
$_SERVER[
'SSL_CLIENT_CERT']) && empty(
$_SERVER[
'SSL_CLIENT_CERT'])) {
 
  718                    $lastError = 
'No client certificate provided during TLS Handshake with SP';
 
  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';
 
  730                $clientCert = str_replace(array(
"\r", 
"\n", 
" "), 
'', $matches[1]);
 
  733                foreach ($scd->info as $thing) {
 
  734                    if ($thing instanceof \
SAML2\XML\ds\KeyInfo) {
 
  738                if (count($keyInfo) != 1) {
 
  739                    $lastError = 
'Error validating Holder-of-Key assertion: Only one <ds:KeyInfo> element in '.
 
  740                        '<SubjectConfirmationData> allowed';
 
  745                foreach ($keyInfo[0]->
info as $thing) {
 
  746                    if ($thing instanceof \
SAML2\XML\ds\X509Data) {
 
  747                        $x509data[] = $thing;
 
  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';
 
  757                foreach ($x509data[0]->
data as $thing) {
 
  758                    if ($thing instanceof \
SAML2\XML\ds\X509Certificate) {
 
  759                        $x509cert[] = $thing;
 
  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';
 
  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';
 
  778                $lastError = 
'No SubjectConfirmationData provided';
 
  782            if ($scd->NotBefore && $scd->NotBefore > time() + 60) {
 
  783                $lastError = 
'NotBefore in SubjectConfirmationData is in the future: '.$scd->NotBefore;
 
  786            if ($scd->NotOnOrAfter && $scd->NotOnOrAfter <= time() - 60) {
 
  787                $lastError = 
'NotOnOrAfter in SubjectConfirmationData is in the past: '.$scd->NotOnOrAfter;
 
  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).
'.';
 
  795            if ($scd->InResponseTo !== 
null && 
$response->getInResponseTo() !== 
null &&
 
  796                $scd->InResponseTo !== 
$response->getInResponseTo()
 
  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).
'.';
 
  811        if (
$idpMetadata->getBoolean(
'base64attributes', 
false)) {
 
  813            $newAttributes = array();
 
  815                $newAttributes[
$name] = array();
 
  817                    foreach (explode(
'_', $value) as $v) {
 
  818                        $newAttributes[
$name][] = base64_decode($v);
 
  822            $assertion->setAttributes($newAttributes);
 
  826        if ($assertion->isNameIdEncrypted()) {
 
  829            } 
catch (Exception $e) {
 
  835            $lastException = 
null;
 
  838                    $assertion->decryptNameId(
$key, $blacklist);
 
  840                    $lastException = 
null;
 
  842                } 
catch (Exception $e) {
 
  847            if ($lastException !== 
null) {
 
  848                throw $lastException;
 
  868        $sharedKey = 
$metadata->getString(
'sharedkey', 
null);
 
  869        if ($sharedKey !== 
null) {
 
  871            $key->loadKey($sharedKey);
 
  877            switch (
$key[
'type']) {
 
  878                case 'X509Certificate':
 
  879                    $pemKey = 
"-----BEGIN CERTIFICATE-----\n".
 
  880                        chunk_split(
$key[
'X509Certificate'], 64).
 
  881                        "-----END CERTIFICATE-----\n";
 
  883                    $key->loadKey($pemKey);
 
  889            var_export(
$metadata->getString(
'entityid'), 
true));
 
$metadata['__DYNAMIC:1__']
An exception for terminatinating execution or to throw for unit testing.
static loadPublicKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='')
Get public key or certificate from metadata.
static loadPrivateKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='', $full_path=false)
Load a private key from metadata.
static getSelfURLNoQuery()
Retrieve the current URL using the base URL in the configuration, without the query parameters.
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.
static addSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\SignedElement $element)
Add signature key and sender certificate to an element (Message or Assertion).
static buildLogoutRequest(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout request based on information in the metadata.
static buildAuthnRequest(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata)
Build an authentication request based on information in the metadata.
static checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
Check the signature on a SAML2 message or assertion.
static getDecryptionKeys(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve the decryption keys from metadata.
static decryptAssertion(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, $assertion)
Decrypt an assertion.
static buildLogoutResponse(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Build a logout response based on information in the metadata.
static processResponse(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response)
Process a response message.
static getBlacklistedAlgorithms(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata)
Retrieve blacklisted algorithms.
static getEncryptionKey(SimpleSAML_Configuration $metadata)
Retrieve the encryption key for the given entity.
static validateMessage(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Check signature on a SAML2 message if enabled.
static processAssertion(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata, \SAML2\Response $response, $assertion, $responseSigned)
Process an assertion in a response.
static findCertificate(array $certFingerprints, array $certificates)
Find the certificate used to sign a message or assertion.
static addRedirectSign(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Message $message)
Add signature key and and senders certificate to message.
static decryptAttributes(SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata, \SAML2\Assertion &$assertion)
Decrypt any encrypted attributes in an assertion.
if(array_key_exists('yes', $_REQUEST)) $attributes
catch(Exception $e) $message
Attribute-related utility methods.
foreach($_POST as $key=> $value) $res
if((!isset($_SERVER['DOCUMENT_ROOT'])) OR(empty($_SERVER['DOCUMENT_ROOT']))) $_SERVER['DOCUMENT_ROOT']