vendor/onelogin/php-saml/src/Saml2/Settings.php line 141

Open in your IDE?
  1. <?php
  2. /**
  3.  * This file is part of php-saml.
  4.  *
  5.  * (c) OneLogin Inc
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  *
  10.  * @package OneLogin
  11.  * @author  OneLogin Inc <saml-info@onelogin.com>
  12.  * @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE
  13.  * @link    https://github.com/onelogin/php-saml
  14.  */
  15. namespace OneLogin\Saml2;
  16. use RobRichards\XMLSecLibs\XMLSecurityKey;
  17. use RobRichards\XMLSecLibs\XMLSecurityDSig;
  18. use DOMDocument;
  19. use Exception;
  20. /**
  21.  * Configuration of the OneLogin PHP Toolkit
  22.  */
  23. class Settings
  24. {
  25.     /**
  26.      * List of paths.
  27.      *
  28.      * @var array
  29.      */
  30.     private $_paths = array();
  31.     /**
  32.      * @var string
  33.      */
  34.     private $_baseurl;
  35.     /**
  36.      * Strict. If active, PHP Toolkit will reject unsigned or unencrypted messages
  37.      * if it expects them signed or encrypted. If not, the messages will be accepted
  38.      * and some security issues will be also relaxed.
  39.      *
  40.      * @var bool
  41.      */
  42.     private $_strict true;
  43.     /**
  44.      * Activate debug mode
  45.      *
  46.      * @var bool
  47.      */
  48.     private $_debug false;
  49.     /**
  50.      * SP data.
  51.      *
  52.      * @var array
  53.      */
  54.     private $_sp = array();
  55.     /**
  56.      * IdP data.
  57.      *
  58.      * @var array
  59.      */
  60.     private $_idp = array();
  61.     /**
  62.      * Compression settings that determine
  63.      * whether gzip compression should be used.
  64.      *
  65.      * @var array
  66.      */
  67.     private $_compress = array();
  68.     /**
  69.      * Security Info related to the SP.
  70.      *
  71.      * @var array
  72.      */
  73.     private $_security = array();
  74.     /**
  75.      * Setting contacts.
  76.      *
  77.      * @var array
  78.      */
  79.     private $_contacts = array();
  80.     /**
  81.      * Setting organization.
  82.      *
  83.      * @var array
  84.      */
  85.     private $_organization = array();
  86.     /**
  87.      * Setting errors.
  88.      *
  89.      * @var array
  90.      */
  91.     private $_errors = array();
  92.     /**
  93.      * Valitate SP data only flag
  94.      *
  95.      * @var bool
  96.      */
  97.     private $_spValidationOnly false;
  98.     /**
  99.      * Initializes the settings:
  100.      * - Sets the paths of the different folders
  101.      * - Loads settings info from settings file or array/object provided
  102.      *
  103.      * @param array|null $settings         SAML Toolkit Settings
  104.      * @param bool       $spValidationOnly Validate or not the IdP data
  105.      *
  106.      * @throws Error If any settings parameter is invalid
  107.      * @throws Exception If Settings is incorrectly supplied
  108.      */
  109.     public function __construct(array $settings null$spValidationOnly false)
  110.     {
  111.         $this->_spValidationOnly $spValidationOnly;
  112.         $this->_loadPaths();
  113.         if (!isset($settings)) {
  114.             if (!$this->_loadSettingsFromFile()) {
  115.                 throw new Error(
  116.                     'Invalid file settings: %s',
  117.                     Error::SETTINGS_INVALID,
  118.                     array(implode(', '$this->_errors))
  119.                 );
  120.             }
  121.             $this->_addDefaultValues();
  122.         } else {
  123.             if (!$this->_loadSettingsFromArray($settings)) {
  124.                 throw new Error(
  125.                     'Invalid array settings: %s',
  126.                     Error::SETTINGS_INVALID,
  127.                     array(implode(', '$this->_errors))
  128.                 );
  129.             }
  130.         }
  131.         $this->formatIdPCert();
  132.         $this->formatSPCert();
  133.         $this->formatSPKey();
  134.         $this->formatSPCertNew();
  135.         $this->formatIdPCertMulti();
  136.     }
  137.     /**
  138.      * Sets the paths of the different folders
  139.      * @suppress PhanUndeclaredConstant
  140.      */
  141.     private function _loadPaths()
  142.     {
  143.         $basePath dirname(dirname(__DIR__)) . '/';
  144.         $this->_paths = array(
  145.             'base' => $basePath,
  146.             'config' => $basePath,
  147.             'cert' => $basePath.'certs/',
  148.             'lib' => __DIR__ '/',
  149.         );
  150.         if (defined('ONELOGIN_CUSTOMPATH')) {
  151.             $this->_paths['config'] = ONELOGIN_CUSTOMPATH;
  152.             $this->_paths['cert'] = ONELOGIN_CUSTOMPATH 'certs/';
  153.         }
  154.     }
  155.     /**
  156.      * Returns base path.
  157.      *
  158.      * @return string  The base toolkit folder path
  159.      */
  160.     public function getBasePath()
  161.     {
  162.         return $this->_paths['base'];
  163.     }
  164.     /**
  165.      * Returns cert path.
  166.      *
  167.      * @return string The cert folder path
  168.      */
  169.     public function getCertPath()
  170.     {
  171.         return $this->_paths['cert'];
  172.     }
  173.     /**
  174.      * Returns config path.
  175.      *
  176.      * @return string The config folder path
  177.      */
  178.     public function getConfigPath()
  179.     {
  180.         return $this->_paths['config'];
  181.     }
  182.     /**
  183.      * Returns lib path.
  184.      *
  185.      * @return string The library folder path
  186.      */
  187.     public function getLibPath()
  188.     {
  189.         return $this->_paths['lib'];
  190.     }
  191.     /**
  192.      * Returns schema path.
  193.      *
  194.      * @return string  The external library folder path
  195.      */
  196.     public function getSchemasPath()
  197.     {
  198.         if (isset($this->_paths['schemas'])) {
  199.             return $this->_paths['schemas'];
  200.         }
  201.         return __DIR__ '/schemas/';
  202.     }
  203.     /**
  204.      * Set schemas path
  205.      *
  206.      * @param string $path
  207.      * @return $this
  208.      */
  209.     public function setSchemasPath($path)
  210.     {
  211.         $this->_paths['schemas'] = $path;
  212.     }
  213.     /**
  214.      * Loads settings info from a settings Array
  215.      *
  216.      * @param array $settings SAML Toolkit Settings
  217.      *
  218.      * @return bool True if the settings info is valid
  219.      */
  220.     private function _loadSettingsFromArray(array $settings)
  221.     {
  222.         if (isset($settings['sp'])) {
  223.             $this->_sp $settings['sp'];
  224.         }
  225.         if (isset($settings['idp'])) {
  226.             $this->_idp $settings['idp'];
  227.         }
  228.         $errors $this->checkSettings($settings);
  229.         if (empty($errors)) {
  230.             $this->_errors = array();
  231.             if (isset($settings['strict'])) {
  232.                 $this->_strict $settings['strict'];
  233.             }
  234.             if (isset($settings['debug'])) {
  235.                 $this->_debug $settings['debug'];
  236.             }
  237.             if (isset($settings['baseurl'])) {
  238.                 $this->_baseurl $settings['baseurl'];
  239.             }
  240.             if (isset($settings['compress'])) {
  241.                 $this->_compress $settings['compress'];
  242.             }
  243.             if (isset($settings['security'])) {
  244.                 $this->_security $settings['security'];
  245.             }
  246.             if (isset($settings['contactPerson'])) {
  247.                 $this->_contacts $settings['contactPerson'];
  248.             }
  249.             if (isset($settings['organization'])) {
  250.                 $this->_organization $settings['organization'];
  251.             }
  252.             $this->_addDefaultValues();
  253.             return true;
  254.         } else {
  255.             $this->_errors $errors;
  256.             return false;
  257.         }
  258.     }
  259.     /**
  260.      * Loads settings info from the settings file
  261.      *
  262.      * @return bool True if the settings info is valid
  263.      *
  264.      * @throws Error
  265.      *
  266.      * @suppress PhanUndeclaredVariable
  267.      */
  268.     private function _loadSettingsFromFile()
  269.     {
  270.         $filename $this->getConfigPath().'settings.php';
  271.         if (!file_exists($filename)) {
  272.             throw new Error(
  273.                 'Settings file not found: %s',
  274.                 Error::SETTINGS_FILE_NOT_FOUND,
  275.                 array($filename)
  276.             );
  277.         }
  278.         /** @var array $settings */
  279.         include $filename;
  280.         // Add advance_settings if exists
  281.         $advancedFilename $this->getConfigPath().'advanced_settings.php';
  282.         if (file_exists($advancedFilename)) {
  283.             /** @var array $advancedSettings */
  284.             include $advancedFilename;
  285.             $settings array_merge($settings$advancedSettings);
  286.         }
  287.         return $this->_loadSettingsFromArray($settings);
  288.     }
  289.     /**
  290.      * Add default values if the settings info is not complete
  291.      */
  292.     private function _addDefaultValues()
  293.     {
  294.         if (!isset($this->_sp['assertionConsumerService']['binding'])) {
  295.             $this->_sp['assertionConsumerService']['binding'] = Constants::BINDING_HTTP_POST;
  296.         }
  297.         if (isset($this->_sp['singleLogoutService']) && !isset($this->_sp['singleLogoutService']['binding'])) {
  298.             $this->_sp['singleLogoutService']['binding'] = Constants::BINDING_HTTP_REDIRECT;
  299.         }
  300.         if (!isset($this->_compress['requests'])) {
  301.             $this->_compress['requests'] = true;
  302.         }
  303.         if (!isset($this->_compress['responses'])) {
  304.             $this->_compress['responses'] = true;
  305.         }
  306.         // Related to nameID
  307.         if (!isset($this->_sp['NameIDFormat'])) {
  308.             $this->_sp['NameIDFormat'] = Constants::NAMEID_UNSPECIFIED;
  309.         }
  310.         if (!isset($this->_security['nameIdEncrypted'])) {
  311.             $this->_security['nameIdEncrypted'] = false;
  312.         }
  313.         if (!isset($this->_security['requestedAuthnContext'])) {
  314.             $this->_security['requestedAuthnContext'] = true;
  315.         }
  316.         // sign provided
  317.         if (!isset($this->_security['authnRequestsSigned'])) {
  318.             $this->_security['authnRequestsSigned'] = false;
  319.         }
  320.         if (!isset($this->_security['logoutRequestSigned'])) {
  321.             $this->_security['logoutRequestSigned'] = false;
  322.         }
  323.         if (!isset($this->_security['logoutResponseSigned'])) {
  324.             $this->_security['logoutResponseSigned'] = false;
  325.         }
  326.         if (!isset($this->_security['signMetadata'])) {
  327.             $this->_security['signMetadata'] = false;
  328.         }
  329.         // sign expected
  330.         if (!isset($this->_security['wantMessagesSigned'])) {
  331.             $this->_security['wantMessagesSigned'] = false;
  332.         }
  333.         if (!isset($this->_security['wantAssertionsSigned'])) {
  334.             $this->_security['wantAssertionsSigned'] = false;
  335.         }
  336.         // NameID element expected
  337.         if (!isset($this->_security['wantNameId'])) {
  338.             $this->_security['wantNameId'] = true;
  339.         }
  340.         // Relax Destination validation
  341.         if (!isset($this->_security['relaxDestinationValidation'])) {
  342.             $this->_security['relaxDestinationValidation'] = false;
  343.         }
  344.         // Strict Destination match validation
  345.         if (!isset($this->_security['destinationStrictlyMatches'])) {
  346.             $this->_security['destinationStrictlyMatches'] = false;
  347.         }
  348.         // Allow duplicated Attribute Names
  349.         if (!isset($this->_security['allowRepeatAttributeName'])) {
  350.             $this->_security['allowRepeatAttributeName'] = false;
  351.         }
  352.         // InResponseTo
  353.         if (!isset($this->_security['rejectUnsolicitedResponsesWithInResponseTo'])) {
  354.             $this->_security['rejectUnsolicitedResponsesWithInResponseTo'] = false;
  355.         }
  356.         // encrypt expected
  357.         if (!isset($this->_security['wantAssertionsEncrypted'])) {
  358.             $this->_security['wantAssertionsEncrypted'] = false;
  359.         }
  360.         if (!isset($this->_security['wantNameIdEncrypted'])) {
  361.             $this->_security['wantNameIdEncrypted'] = false;
  362.         }
  363.         // XML validation
  364.         if (!isset($this->_security['wantXMLValidation'])) {
  365.             $this->_security['wantXMLValidation'] = true;
  366.         }
  367.         // SignatureAlgorithm
  368.         if (!isset($this->_security['signatureAlgorithm'])) {
  369.             $this->_security['signatureAlgorithm'] = XMLSecurityKey::RSA_SHA256;
  370.         }
  371.         // DigestAlgorithm
  372.         if (!isset($this->_security['digestAlgorithm'])) {
  373.             $this->_security['digestAlgorithm'] = XMLSecurityDSig::SHA256;
  374.         }
  375.         // EncryptionAlgorithm
  376.         if (!isset($this->_security['encryption_algorithm'])) {
  377.             $this->_security['encryption_algorithm'] = XMLSecurityKey::AES128_CBC;
  378.         }
  379.         if (!isset($this->_security['lowercaseUrlencoding'])) {
  380.             $this->_security['lowercaseUrlencoding'] = false;
  381.         }
  382.         // Certificates / Private key /Fingerprint
  383.         if (!isset($this->_idp['x509cert'])) {
  384.             $this->_idp['x509cert'] = '';
  385.         }
  386.         if (!isset($this->_idp['certFingerprint'])) {
  387.             $this->_idp['certFingerprint'] = '';
  388.         }
  389.         if (!isset($this->_idp['certFingerprintAlgorithm'])) {
  390.             $this->_idp['certFingerprintAlgorithm'] = 'sha1';
  391.         }
  392.         if (!isset($this->_sp['x509cert'])) {
  393.             $this->_sp['x509cert'] = '';
  394.         }
  395.         if (!isset($this->_sp['privateKey'])) {
  396.             $this->_sp['privateKey'] = '';
  397.         }
  398.     }
  399.     /**
  400.      * Checks the settings info.
  401.      *
  402.      * @param array $settings Array with settings data
  403.      *
  404.      * @return array $errors  Errors found on the settings data
  405.      */
  406.     public function checkSettings(array $settings)
  407.     {
  408.         if (empty($settings)) {
  409.             $errors = array('invalid_syntax');
  410.         } else {
  411.             $errors = array();
  412.             if (!$this->_spValidationOnly) {
  413.                 $idpErrors $this->checkIdPSettings($settings);
  414.                 $errors array_merge($idpErrors$errors);
  415.             }
  416.             $spErrors $this->checkSPSettings($settings);
  417.             $errors array_merge($spErrors$errors);
  418.             $compressErrors $this->checkCompressionSettings($settings);
  419.             $errors array_merge($compressErrors$errors);
  420.         }
  421.         return $errors;
  422.     }
  423.     /**
  424.      * Checks the compression settings info.
  425.      *
  426.      * @param array $settings Array with settings data
  427.      *
  428.      * @return array $errors  Errors found on the settings data
  429.      */
  430.     public function checkCompressionSettings($settings)
  431.     {
  432.         $errors = array();
  433.         if (isset($settings['compress'])) {
  434.             if (!is_array($settings['compress'])) {
  435.                 $errors[] = "invalid_syntax";
  436.             } else if (isset($settings['compress']['requests'])
  437.                 && $settings['compress']['requests'] !== true
  438.                 && $settings['compress']['requests'] !== false
  439.             ) {
  440.                 $errors[] = "'compress'=>'requests' values must be true or false.";
  441.             } else if (isset($settings['compress']['responses'])
  442.                 && $settings['compress']['responses'] !== true
  443.                 && $settings['compress']['responses'] !== false
  444.             ) {
  445.                 $errors[] = "'compress'=>'responses' values must be true or false.";
  446.             }
  447.         }
  448.         return $errors;
  449.     }
  450.     /**
  451.      * Checks the IdP settings info.
  452.      *
  453.      * @param array $settings Array with settings data
  454.      *
  455.      * @return array $errors  Errors found on the IdP settings data
  456.      */
  457.     public function checkIdPSettings(array $settings)
  458.     {
  459.         if (empty($settings)) {
  460.             return array('invalid_syntax');
  461.         }
  462.         $errors = array();
  463.         if (!isset($settings['idp']) || empty($settings['idp'])) {
  464.             $errors[] = 'idp_not_found';
  465.         } else {
  466.             $idp $settings['idp'];
  467.             if (!isset($idp['entityId']) || empty($idp['entityId'])) {
  468.                 $errors[] = 'idp_entityId_not_found';
  469.             }
  470.             if (!isset($idp['singleSignOnService'])
  471.                 || !isset($idp['singleSignOnService']['url'])
  472.                 || empty($idp['singleSignOnService']['url'])
  473.             ) {
  474.                 $errors[] = 'idp_sso_not_found';
  475.             } else if (!filter_var($idp['singleSignOnService']['url'], FILTER_VALIDATE_URL)) {
  476.                 $errors[] = 'idp_sso_url_invalid';
  477.             }
  478.             if (isset($idp['singleLogoutService'])
  479.                 && isset($idp['singleLogoutService']['url'])
  480.                 && !empty($idp['singleLogoutService']['url'])
  481.                 && !filter_var($idp['singleLogoutService']['url'], FILTER_VALIDATE_URL)
  482.             ) {
  483.                 $errors[] = 'idp_slo_url_invalid';
  484.             }
  485.             if (isset($idp['singleLogoutService'])
  486.                 && isset($idp['singleLogoutService']['responseUrl'])
  487.                 && !empty($idp['singleLogoutService']['responseUrl'])
  488.                 && !filter_var($idp['singleLogoutService']['responseUrl'], FILTER_VALIDATE_URL)
  489.             ) {
  490.                 $errors[] = 'idp_slo_response_url_invalid';
  491.             }
  492.             $existsX509 = isset($idp['x509cert']) && !empty($idp['x509cert']);
  493.             $existsMultiX509Sign = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['signing']) && !empty($idp['x509certMulti']['signing']);
  494.             $existsFingerprint = isset($idp['certFingerprint']) && !empty($idp['certFingerprint']);
  495.             if (!($existsX509 || $existsFingerprint || $existsMultiX509Sign)
  496.             ) {
  497.                 $errors[] = 'idp_cert_or_fingerprint_not_found_and_required';
  498.             }
  499.             if (isset($settings['security'])) {
  500.                 $existsMultiX509Enc = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['encryption']) && !empty($idp['x509certMulti']['encryption']);
  501.                 if ((isset($settings['security']['nameIdEncrypted']) && $settings['security']['nameIdEncrypted'] == true)
  502.                     && !($existsX509 || $existsMultiX509Enc)
  503.                 ) {
  504.                     $errors[] = 'idp_cert_not_found_and_required';
  505.                 }
  506.             }
  507.         }
  508.         return $errors;
  509.     }
  510.     /**
  511.      * Checks the SP settings info.
  512.      *
  513.      * @param array $settings Array with settings data
  514.      *
  515.      * @return array $errors  Errors found on the SP settings data
  516.      */
  517.     public function checkSPSettings(array $settings)
  518.     {
  519.         if (empty($settings)) {
  520.             return array('invalid_syntax');
  521.         }
  522.         $errors = array();
  523.         if (!isset($settings['sp']) || empty($settings['sp'])) {
  524.             $errors[] = 'sp_not_found';
  525.         } else {
  526.             $sp $settings['sp'];
  527.             $security = array();
  528.             if (isset($settings['security'])) {
  529.                 $security $settings['security'];
  530.             }
  531.             if (!isset($sp['entityId']) || empty($sp['entityId'])) {
  532.                 $errors[] = 'sp_entityId_not_found';
  533.             }
  534.             if (!isset($sp['assertionConsumerService'])
  535.                 || !isset($sp['assertionConsumerService']['url'])
  536.                 || empty($sp['assertionConsumerService']['url'])
  537.             ) {
  538.                 $errors[] = 'sp_acs_not_found';
  539.             } else if (!filter_var($sp['assertionConsumerService']['url'], FILTER_VALIDATE_URL)) {
  540.                 $errors[] = 'sp_acs_url_invalid';
  541.             }
  542.             if (isset($sp['singleLogoutService'])
  543.                 && isset($sp['singleLogoutService']['url'])
  544.                 && !filter_var($sp['singleLogoutService']['url'], FILTER_VALIDATE_URL)
  545.             ) {
  546.                 $errors[] = 'sp_sls_url_invalid';
  547.             }
  548.             if (isset($security['signMetadata']) && is_array($security['signMetadata'])) {
  549.                 if ((!isset($security['signMetadata']['keyFileName'])
  550.                     || !isset($security['signMetadata']['certFileName'])) &&
  551.                     (!isset($security['signMetadata']['privateKey'])
  552.                     || !isset($security['signMetadata']['x509cert']))
  553.                 ) {
  554.                     $errors[] = 'sp_signMetadata_invalid';
  555.                 }
  556.             }
  557.             if (((isset($security['authnRequestsSigned']) && $security['authnRequestsSigned'] == true)
  558.                 || (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned'] == true)
  559.                 || (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned'] == true)
  560.                 || (isset($security['wantAssertionsEncrypted']) && $security['wantAssertionsEncrypted'] == true)
  561.                 || (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted'] == true))
  562.                 && !$this->checkSPCerts()
  563.             ) {
  564.                 $errors[] = 'sp_certs_not_found_and_required';
  565.             }
  566.         }
  567.         if (isset($settings['contactPerson'])) {
  568.             $types array_keys($settings['contactPerson']);
  569.             $validTypes = array('technical''support''administrative''billing''other');
  570.             foreach ($types as $type) {
  571.                 if (!in_array($type$validTypes)) {
  572.                     $errors[] = 'contact_type_invalid';
  573.                     break;
  574.                 }
  575.             }
  576.             foreach ($settings['contactPerson'] as $type => $contact) {
  577.                 if (!isset($contact['givenName']) || empty($contact['givenName'])
  578.                     || !isset($contact['emailAddress']) || empty($contact['emailAddress'])
  579.                 ) {
  580.                     $errors[] = 'contact_not_enought_data';
  581.                     break;
  582.                 }
  583.             }
  584.         }
  585.         if (isset($settings['organization'])) {
  586.             foreach ($settings['organization'] as $organization) {
  587.                 if (!isset($organization['name']) || empty($organization['name'])
  588.                     || !isset($organization['displayname']) || empty($organization['displayname'])
  589.                     || !isset($organization['url']) || empty($organization['url'])
  590.                 ) {
  591.                     $errors[] = 'organization_not_enought_data';
  592.                     break;
  593.                 }
  594.             }
  595.         }
  596.         return $errors;
  597.     }
  598.     /**
  599.      * Checks if the x509 certs of the SP exists and are valid.
  600.      *
  601.      * @return bool
  602.      */
  603.     public function checkSPCerts()
  604.     {
  605.         $key $this->getSPkey();
  606.         $cert $this->getSPcert();
  607.         return (!empty($key) && !empty($cert));
  608.     }
  609.     /**
  610.      * Returns the x509 private key of the SP.
  611.      *
  612.      * @return string SP private key
  613.      */
  614.     public function getSPkey()
  615.     {
  616.         $key null;
  617.         if (isset($this->_sp['privateKey']) && !empty($this->_sp['privateKey'])) {
  618.             $key $this->_sp['privateKey'];
  619.         } else {
  620.             $keyFile $this->_paths['cert'].'sp.key';
  621.             if (file_exists($keyFile)) {
  622.                 $key file_get_contents($keyFile);
  623.             }
  624.         }
  625.         return $key;
  626.     }
  627.     /**
  628.      * Returns the x509 public cert of the SP.
  629.      *
  630.      * @return string SP public cert
  631.      */
  632.     public function getSPcert()
  633.     {
  634.         $cert null;
  635.         if (isset($this->_sp['x509cert']) && !empty($this->_sp['x509cert'])) {
  636.             $cert $this->_sp['x509cert'];
  637.         } else {
  638.             $certFile $this->_paths['cert'].'sp.crt';
  639.             if (file_exists($certFile)) {
  640.                 $cert file_get_contents($certFile);
  641.             }
  642.         }
  643.         return $cert;
  644.     }
  645.     /**
  646.      * Returns the x509 public of the SP that is
  647.      * planed to be used soon instead the other
  648.      * public cert
  649.      *
  650.      * @return string SP public cert New
  651.      */
  652.     public function getSPcertNew()
  653.     {
  654.         $cert null;
  655.         if (isset($this->_sp['x509certNew']) && !empty($this->_sp['x509certNew'])) {
  656.             $cert $this->_sp['x509certNew'];
  657.         } else {
  658.             $certFile $this->_paths['cert'].'sp_new.crt';
  659.             if (file_exists($certFile)) {
  660.                 $cert file_get_contents($certFile);
  661.             }
  662.         }
  663.         return $cert;
  664.     }
  665.     /**
  666.      * Gets the IdP data.
  667.      *
  668.      * @return array  IdP info
  669.      */
  670.     public function getIdPData()
  671.     {
  672.         return $this->_idp;
  673.     }
  674.     /**
  675.      * Gets the SP data.
  676.      *
  677.      * @return array  SP info
  678.      */
  679.     public function getSPData()
  680.     {
  681.         return $this->_sp;
  682.     }
  683.     /**
  684.      * Gets security data.
  685.      *
  686.      * @return array  SP info
  687.      */
  688.     public function getSecurityData()
  689.     {
  690.         return $this->_security;
  691.     }
  692.     /**
  693.      * Gets contact data.
  694.      *
  695.      * @return array  SP info
  696.      */
  697.     public function getContacts()
  698.     {
  699.         return $this->_contacts;
  700.     }
  701.     /**
  702.      * Gets organization data.
  703.      *
  704.      * @return array  SP info
  705.      */
  706.     public function getOrganization()
  707.     {
  708.         return $this->_organization;
  709.     }
  710.     /**
  711.      * Should SAML requests be compressed?
  712.      *
  713.      * @return bool Yes/No as True/False
  714.      */
  715.     public function shouldCompressRequests()
  716.     {
  717.         return $this->_compress['requests'];
  718.     }
  719.     /**
  720.      * Should SAML responses be compressed?
  721.      *
  722.      * @return bool Yes/No as True/False
  723.      */
  724.     public function shouldCompressResponses()
  725.     {
  726.         return $this->_compress['responses'];
  727.     }
  728.     /**
  729.      * Gets the IdP SSO url.
  730.      *
  731.      * @return string|null The url of the IdP Single Sign On Service
  732.      */
  733.     public function getIdPSSOUrl()
  734.     {
  735.         $ssoUrl null;
  736.         if (isset($this->_idp['singleSignOnService']) && isset($this->_idp['singleSignOnService']['url'])) {
  737.             $ssoUrl $this->_idp['singleSignOnService']['url'];
  738.         }
  739.         return $ssoUrl;
  740.     }
  741.     /**
  742.      * Gets the IdP SLO url.
  743.      *
  744.      * @return string|null The request url of the IdP Single Logout Service
  745.      */
  746.     public function getIdPSLOUrl()
  747.     {
  748.         $sloUrl null;
  749.         if (isset($this->_idp['singleLogoutService']) && isset($this->_idp['singleLogoutService']['url'])) {
  750.             $sloUrl $this->_idp['singleLogoutService']['url'];
  751.         }
  752.         return $sloUrl;
  753.     }
  754.     /**
  755.      * Gets the IdP SLO response url.
  756.      *
  757.      * @return string|null The response url of the IdP Single Logout Service
  758.      */
  759.     public function getIdPSLOResponseUrl()
  760.     {
  761.         if (isset($this->_idp['singleLogoutService']) && isset($this->_idp['singleLogoutService']['responseUrl'])) {
  762.             return $this->_idp['singleLogoutService']['responseUrl'];
  763.         }
  764.         return $this->getIdPSLOUrl();
  765.     }
  766.     /**
  767.      * Gets the SP metadata. The XML representation.
  768.      *
  769.      * @param bool $alwaysPublishEncryptionCert When 'true', the returned
  770.      * metadata will always include an 'encryption' KeyDescriptor. Otherwise,
  771.      * the 'encryption' KeyDescriptor will only be included if
  772.      * $advancedSettings['security']['wantNameIdEncrypted'] or
  773.      * $advancedSettings['security']['wantAssertionsEncrypted'] are enabled.
  774.      * @param int|null      $validUntil    Metadata's valid time
  775.      * @param int|null      $cacheDuration Duration of the cache in seconds
  776.      *
  777.      * @return string  SP metadata (xml)
  778.      * @throws Exception
  779.      * @throws Error
  780.      */
  781.     public function getSPMetadata($alwaysPublishEncryptionCert false$validUntil null$cacheDuration null)
  782.     {
  783.         $metadata Metadata::builder($this->_sp$this->_security['authnRequestsSigned'], $this->_security['wantAssertionsSigned'], $validUntil$cacheDuration$this->getContacts(), $this->getOrganization());
  784.         $certNew $this->getSPcertNew();
  785.         if (!empty($certNew)) {
  786.             $metadata Metadata::addX509KeyDescriptors(
  787.                 $metadata,
  788.                 $certNew,
  789.                 $alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
  790.             );
  791.         }
  792.         $cert $this->getSPcert();
  793.         if (!empty($cert)) {
  794.             $metadata Metadata::addX509KeyDescriptors(
  795.                 $metadata,
  796.                 $cert,
  797.                 $alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted']
  798.             );
  799.         }
  800.         //Sign Metadata
  801.         if (isset($this->_security['signMetadata']) && $this->_security['signMetadata'] != false) {
  802.             if ($this->_security['signMetadata'] === true) {
  803.                 $keyMetadata $this->getSPkey();
  804.                 $certMetadata $cert;
  805.                 if (!$keyMetadata) {
  806.                     throw new Error(
  807.                         'SP Private key not found.',
  808.                         Error::PRIVATE_KEY_FILE_NOT_FOUND
  809.                     );
  810.                 }
  811.                 if (!$certMetadata) {
  812.                     throw new Error(
  813.                         'SP Public cert not found.',
  814.                         Error::PUBLIC_CERT_FILE_NOT_FOUND
  815.                     );
  816.                 }
  817.             } else if (isset($this->_security['signMetadata']['keyFileName']) &&
  818.                 isset($this->_security['signMetadata']['certFileName'])) {
  819.                 $keyFileName $this->_security['signMetadata']['keyFileName'];
  820.                 $certFileName $this->_security['signMetadata']['certFileName'];
  821.                 $keyMetadataFile $this->_paths['cert'].$keyFileName;
  822.                 $certMetadataFile $this->_paths['cert'].$certFileName;
  823.                 if (!file_exists($keyMetadataFile)) {
  824.                     throw new Error(
  825.                         'SP Private key file not found: %s',
  826.                         Error::PRIVATE_KEY_FILE_NOT_FOUND,
  827.                         array($keyMetadataFile)
  828.                     );
  829.                 }
  830.                 if (!file_exists($certMetadataFile)) {
  831.                     throw new Error(
  832.                         'SP Public cert file not found: %s',
  833.                         Error::PUBLIC_CERT_FILE_NOT_FOUND,
  834.                         array($certMetadataFile)
  835.                     );
  836.                 }
  837.                 $keyMetadata file_get_contents($keyMetadataFile);
  838.                 $certMetadata file_get_contents($certMetadataFile);
  839.             } else if (isset($this->_security['signMetadata']['privateKey']) &&
  840.                 isset($this->_security['signMetadata']['x509cert'])) {
  841.                 $keyMetadata Utils::formatPrivateKey($this->_security['signMetadata']['privateKey']);
  842.                 $certMetadata Utils::formatCert($this->_security['signMetadata']['x509cert']);
  843.                 if (!$keyMetadata) {
  844.                     throw new Error(
  845.                         'Private key not found.',
  846.                         Error::PRIVATE_KEY_FILE_NOT_FOUND
  847.                     );
  848.                 }
  849.                 if (!$certMetadata) {
  850.                     throw new Error(
  851.                         'Public cert not found.',
  852.                         Error::PUBLIC_CERT_FILE_NOT_FOUND
  853.                     );
  854.                 }
  855.             } else {
  856.                 throw new Error(
  857.                     'Invalid Setting: signMetadata value of the sp is not valid',
  858.                     Error::SETTINGS_INVALID_SYNTAX
  859.                 );
  860.             }
  861.             $signatureAlgorithm $this->_security['signatureAlgorithm'];
  862.             $digestAlgorithm $this->_security['digestAlgorithm'];
  863.             $metadata Metadata::signMetadata($metadata$keyMetadata$certMetadata$signatureAlgorithm$digestAlgorithm);
  864.         }
  865.         return $metadata;
  866.     }
  867.     /**
  868.      * Validates an XML SP Metadata.
  869.      *
  870.      * @param string $xml Metadata's XML that will be validate
  871.      *
  872.      * @return array The list of found errors
  873.      *
  874.      * @throws Exception
  875.      */
  876.     public function validateMetadata($xml)
  877.     {
  878.         assert(is_string($xml));
  879.         $errors = array();
  880.         $res Utils::validateXML($xml'saml-schema-metadata-2.0.xsd'$this->_debug$this->getSchemasPath());
  881.         if (!$res instanceof DOMDocument) {
  882.             $errors[] = $res;
  883.         } else {
  884.             $dom $res;
  885.             $element $dom->documentElement;
  886.             if ($element->tagName !== 'md:EntityDescriptor') {
  887.                 $errors[] = 'noEntityDescriptor_xml';
  888.             } else {
  889.                 $validUntil $cacheDuration $expireTime null;
  890.                 if ($element->hasAttribute('validUntil')) {
  891.                     $validUntil Utils::parseSAML2Time($element->getAttribute('validUntil'));
  892.                 }
  893.                 if ($element->hasAttribute('cacheDuration')) {
  894.                     $cacheDuration $element->getAttribute('cacheDuration');
  895.                 }
  896.                 $expireTime Utils::getExpireTime($cacheDuration$validUntil);
  897.                 if (isset($expireTime) && time() > $expireTime) {
  898.                     $errors[] = 'expired_xml';
  899.                 }
  900.             }
  901.         }
  902.         // TODO: Support Metadata Sign Validation
  903.         return $errors;
  904.     }
  905.     /**
  906.      * Formats the IdP cert.
  907.      */
  908.     public function formatIdPCert()
  909.     {
  910.         if (isset($this->_idp['x509cert'])) {
  911.             $this->_idp['x509cert'] = Utils::formatCert($this->_idp['x509cert']);
  912.         }
  913.     }
  914.     /**
  915.      * Formats the Multple IdP certs.
  916.      */
  917.     public function formatIdPCertMulti()
  918.     {
  919.         if (isset($this->_idp['x509certMulti'])) {
  920.             if (isset($this->_idp['x509certMulti']['signing'])) {
  921.                 foreach ($this->_idp['x509certMulti']['signing'] as $i => $cert) {
  922.                     $this->_idp['x509certMulti']['signing'][$i] = Utils::formatCert($cert);
  923.                 }
  924.             }
  925.             if (isset($this->_idp['x509certMulti']['encryption'])) {
  926.                 foreach ($this->_idp['x509certMulti']['encryption'] as $i => $cert) {
  927.                     $this->_idp['x509certMulti']['encryption'][$i] = Utils::formatCert($cert);
  928.                 }
  929.             }
  930.         }
  931.     }
  932.     /**
  933.      * Formats the SP cert.
  934.      */
  935.     public function formatSPCert()
  936.     {
  937.         if (isset($this->_sp['x509cert'])) {
  938.             $this->_sp['x509cert'] = Utils::formatCert($this->_sp['x509cert']);
  939.         }
  940.     }
  941.     /**
  942.      * Formats the SP cert.
  943.      */
  944.     public function formatSPCertNew()
  945.     {
  946.         if (isset($this->_sp['x509certNew'])) {
  947.             $this->_sp['x509certNew'] = Utils::formatCert($this->_sp['x509certNew']);
  948.         }
  949.     }
  950.     /**
  951.      * Formats the SP private key.
  952.      */
  953.     public function formatSPKey()
  954.     {
  955.         if (isset($this->_sp['privateKey'])) {
  956.             $this->_sp['privateKey'] = Utils::formatPrivateKey($this->_sp['privateKey']);
  957.         }
  958.     }
  959.     /**
  960.      * Returns an array with the errors, the array is empty when the settings is ok.
  961.      *
  962.      * @return array Errors
  963.      */
  964.     public function getErrors()
  965.     {
  966.         return $this->_errors;
  967.     }
  968.     /**
  969.      * Activates or deactivates the strict mode.
  970.      *
  971.      * @param bool $value Strict parameter
  972.      *
  973.      * @throws Exception
  974.      */
  975.     public function setStrict($value)
  976.     {
  977.         if (!is_bool($value)) {
  978.             throw new Exception('Invalid value passed to setStrict()');
  979.         }
  980.         $this->_strict $value;
  981.     }
  982.     /**
  983.      * Returns if the 'strict' mode is active.
  984.      *
  985.      * @return bool Strict parameter
  986.      */
  987.     public function isStrict()
  988.     {
  989.         return $this->_strict;
  990.     }
  991.     /**
  992.      * Returns if the debug is active.
  993.      *
  994.      * @return bool Debug parameter
  995.      */
  996.     public function isDebugActive()
  997.     {
  998.         return $this->_debug;
  999.     }
  1000.     /**
  1001.      * Set a baseurl value.
  1002.      *
  1003.      * @param string $baseurl Base URL.
  1004.      */
  1005.     public function setBaseURL($baseurl)
  1006.     {
  1007.         $this->_baseurl $baseurl;
  1008.     }
  1009.     /**
  1010.      * Returns the baseurl set on the settings if any.
  1011.      *
  1012.      * @return null|string The baseurl
  1013.      */
  1014.     public function getBaseURL()
  1015.     {
  1016.         return $this->_baseurl;
  1017.     }
  1018.     /**
  1019.      * Sets the IdP certificate.
  1020.      *
  1021.      * @param string $cert IdP certificate
  1022.      */
  1023.     public function setIdPCert($cert)
  1024.     {
  1025.         $this->_idp['x509cert'] = $cert;
  1026.         $this->formatIdPCert();
  1027.     }
  1028. }