resolveCert() public static method

Deprecation: This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\Config::getCertPath() instead.
public static resolveCert ( $path )
Esempio n. 1
0
 /**
  * Load private key from metadata.
  *
  * This function loads a private key from a metadata array. It searches for the
  * following elements:
  * 'privatekey'  Name of a private key file in the cert-directory.
  * 'privatekey_pass'  Password for the private key.
  *
  * It returns and array with the following elements:
  * 'PEM'  Data for the private key, in PEM-format
  * 'password'  Password for the private key.
  *
  * @param SimpleSAML_Configuration $metadata  The metadata array the private key should be loaded from.
  * @param bool $required  Whether the private key is required. If this is TRUE, a
  *                        missing key will cause an exception. Default is FALSE.
  * @param string $prefix  The prefix which should be used when reading from the metadata
  *                        array. Defaults to ''.
  * @return array|NULL  Extracted private key, or NULL if no private key is present.
  */
 public static function loadPrivateKey(SimpleSAML_Configuration $metadata, $required = FALSE, $prefix = '')
 {
     assert('is_bool($required)');
     assert('is_string($prefix)');
     $file = $metadata->getString($prefix . 'privatekey', NULL);
     if ($file === NULL) {
         /* No private key found. */
         if ($required) {
             throw new Exception('No private key found in metadata.');
         } else {
             return NULL;
         }
     }
     $file = SimpleSAML_Utilities::resolveCert($file);
     $data = @file_get_contents($file);
     if ($data === FALSE) {
         throw new Exception('Unable to load private key from file "' . $file . '"');
     }
     $ret = array('PEM' => $data);
     if ($metadata->hasValue($prefix . 'privatekey_pass')) {
         $ret['password'] = $metadata->getString($prefix . 'privatekey_pass');
     }
     return $ret;
 }
 public function validate()
 {
     assert('$this->dom instanceof DOMDocument');
     if ($this->messageValidated) {
         /* This message was validated externally. */
         return TRUE;
     }
     /* Validate the signature. */
     $this->validator = new SimpleSAML_XML_Validator($this->dom, array('ResponseID', 'AssertionID'));
     // Get the issuer of the response.
     $issuer = $this->getIssuer();
     /* Get the metadata of the issuer. */
     $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
     $md = $metadata->getMetaDataConfig($issuer, 'shib13-idp-remote');
     $publicKeys = $md->getPublicKeys('signing');
     if ($publicKeys !== NULL) {
         $certFingerprints = array();
         foreach ($publicKeys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             $certFingerprints[] = sha1(base64_decode($key['X509Certificate']));
         }
         $this->validator->validateFingerprint($certFingerprints);
     } elseif ($md->hasValue('certFingerprint')) {
         $certFingerprints = $md->getArrayizeString('certFingerprint');
         /* Validate the fingerprint. */
         $this->validator->validateFingerprint($certFingerprints);
     } elseif ($md->hasValue('caFile')) {
         /* Validate against CA. */
         $this->validator->validateCA(SimpleSAML_Utilities::resolveCert($md->getString('caFile')));
     } else {
         throw new SimpleSAML_Error_Exception('Missing certificate in Shibboleth 1.3 IdP Remote metadata for identity provider [' . $issuer . '].');
     }
     return true;
 }
Esempio n. 3
0
 /* Find the saml:Assertion element in the response. */
 $assertions = $xpath->query('/wst:RequestSecurityTokenResponse/wst:RequestedSecurityToken/saml:Assertion');
 if ($assertions->length === 0) {
     throw new Exception('Received a response without an assertion on the WS-Fed PRP handler.');
 }
 if ($assertions->length > 1) {
     throw new Exception('The WS-Fed PRP handler currently only supports a single assertion in a response.');
 }
 $assertion = $assertions->item(0);
 /* Find the entity id of the issuer. */
 $idpEntityId = $assertion->getAttribute('Issuer');
 /* Load the IdP metadata. */
 $idpMetadata = $metadata->getMetaData($idpEntityId, 'wsfed-idp-remote');
 /* Find the certificate used by the IdP. */
 if (array_key_exists('certificate', $idpMetadata)) {
     $certFile = SimpleSAML_Utilities::resolveCert($idpMetadata['certificate']);
 } else {
     throw new Exception('Missing \'certificate\' metadata option in the \'wsfed-idp-remote\' metadata' . ' for the IdP \'' . $idpEntityId . '\'.');
 }
 /* Load the certificate. */
 $certData = file_get_contents($certFile);
 if ($certData === FALSE) {
     throw new Exception('Unable to load certificate file \'' . $certFile . '\' for wsfed-idp \'' . $idpEntityId . '\'.');
 }
 /* Verify that the assertion is signed by the issuer. */
 $validator = new SimpleSAML_XML_Validator($assertion, 'AssertionID', $certData);
 if (!$validator->isNodeValidated($assertion)) {
     throw new Exception('The assertion was not correctly signed by the WS-Fed IdP \'' . $idpEntityId . '\'.');
 }
 /* Check time constraints of contitions (if present). */
 foreach ($xpath->query('./saml:Conditions', $assertion) as $condition) {
Esempio n. 4
0
 }
 echo " /> <label for='gepiEnableIdpSaml20' style='cursor: pointer;'>Fournir une identification SAML 2.0</label>\n";
 echo "<p>\n";
 echo "<label for='sacocheUrl' style='cursor: pointer;'>Adresse du service qui va se connecter si possible en https (<em>exemple : https://localhost/mon-appli</em>) </label>\n";
 echo "<input type='text' size='60' name='sacocheUrl' value='" . getSettingValue("sacocheUrl") . "' id='sacocheUrl' />\n<br/>";
 echo "<label for='sacoche_base' style='cursor: pointer;'>Numéro de base sacoche (<em>laisser vide si votre installation de sacoche est mono établissement</em>)</label>\n";
 echo "<input type='text' size='5' name='sacoche_base' value='" . getSettingValue("sacoche_base") . "' id='sacoche_base' />\n<br/>";
 echo 'pour une configuration manuelle, modifier le fichier /lib/simplesaml/metadata/saml20-sp-remote.php';
 try {
     require_once '../lib/simplesaml/lib/_autoload.php';
     $config = SimpleSAML_Configuration::getConfig();
     //$cert_file =SimpleSAML_Utilities::resolveCert('server.crt');
     $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
     $spMetadata = $metadata->getMetaDataConfig('gepi-idp', 'saml20-idp-hosted');
     if ($spMetadata != null) {
         $cert_file = SimpleSAML_Utilities::resolveCert($spMetadata->getString('certificate'));
         $x509cert = file_get_contents($cert_file);
         echo '<br/>Empreinte (fingerprint) du certificat x509 (à renseigner dans votre logiciel founisseur de service) : ';
         $lines = explode("\n", $x509cert);
         $data = '';
         foreach ($lines as $line) {
             /* Remove '\r' from end of line if present. */
             $line = rtrim($line);
             if ($line === '-----BEGIN CERTIFICATE-----') {
                 /* Delete junk from before the certificate. */
                 $data = '';
             } elseif ($line === '-----END CERTIFICATE-----') {
                 /* Ignore data after the certificate. */
                 break;
             } elseif ($line === '-----BEGIN PUBLIC KEY-----') {
                 /* This isn't an X509 certificate. */
 /**
  * Retrieve and parse the metadata.
  *
  * @return SAML2_XML_md_EntitiesDescriptor|SAML2_XML_md_EntityDescriptor|NULL
  * The downloaded metadata or NULL if we were unable to download or parse it.
  */
 private function downloadMetadata()
 {
     SimpleSAML\Logger::debug($this->logLoc . 'Downloading metadata from ' . var_export($this->url, TRUE));
     $context = array('ssl' => array());
     if ($this->sslCAFile !== NULL) {
         $context['ssl']['cafile'] = SimpleSAML_Utilities::resolveCert($this->sslCAFile);
         SimpleSAML\Logger::debug($this->logLoc . 'Validating https connection against CA certificate(s) found in ' . var_export($context['ssl']['cafile'], TRUE));
         $context['ssl']['verify_peer'] = TRUE;
         $context['ssl']['CN_match'] = parse_url($this->url, PHP_URL_HOST);
     }
     $data = SimpleSAML_Utilities::fetch($this->url, $context);
     if ($data === FALSE || $data === NULL) {
         SimpleSAML\Logger::error($this->logLoc . 'Unable to load metadata from ' . var_export($this->url, TRUE));
         return NULL;
     }
     $doc = new DOMDocument();
     $res = $doc->loadXML($data);
     if (!$res) {
         SimpleSAML\Logger::error($this->logLoc . 'Error parsing XML from ' . var_export($this->url, TRUE));
         return NULL;
     }
     $root = SAML2_Utils::xpQuery($doc->firstChild, '/saml_metadata:EntityDescriptor|/saml_metadata:EntitiesDescriptor');
     if (count($root) === 0) {
         SimpleSAML\Logger::error($this->logLoc . 'No <EntityDescriptor> or <EntitiesDescriptor> in metadata from ' . var_export($this->url, TRUE));
         return NULL;
     }
     if (count($root) > 1) {
         SimpleSAML\Logger::error($this->logLoc . 'More than one <EntityDescriptor> or <EntitiesDescriptor> in metadata from ' . var_export($this->url, TRUE));
         return NULL;
     }
     $root = $root[0];
     try {
         if ($root->localName === 'EntityDescriptor') {
             $md = new SAML2_XML_md_EntityDescriptor($root);
         } else {
             $md = new SAML2_XML_md_EntitiesDescriptor($root);
         }
     } catch (Exception $e) {
         SimpleSAML\Logger::error($this->logLoc . 'Unable to parse metadata from ' . var_export($this->url, TRUE) . ': ' . $e->getMessage());
         return NULL;
     }
     if ($this->certificate !== NULL) {
         $file = SimpleSAML_Utilities::resolveCert($this->certificate);
         $certData = file_get_contents($file);
         if ($certData === FALSE) {
             throw new SimpleSAML_Error_Exception('Error loading certificate from ' . var_export($file, TRUE));
         }
         // Extract the public key from the certificate for validation
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
         $key->loadKey($file, TRUE);
         if (!$md->validate($key)) {
             SimpleSAML\Logger::error($this->logLoc . 'Error validating signature on metadata.');
             return NULL;
         }
         SimpleSAML\Logger::debug($this->logLoc . 'Validated signature on metadata from ' . var_export($this->url, TRUE));
     }
     return $md;
 }
Esempio n. 6
0
 /**
  * Check the signature on a SAML2 message or assertion.
  *
  * @param SimpleSAML_Configuration $srcMetadata  The metadata of the sender.
  * @param SAML2_SignedElement $element  Either a SAML2_Response or a SAML2_Assertion.
  */
 public static function checkSign(SimpleSAML_Configuration $srcMetadata, SAML2_SignedElement $element)
 {
     $certificates = $element->getCertificates();
     SimpleSAML_Logger::debug('Found ' . count($certificates) . ' certificates in ' . get_class($element));
     /* Find the certificate that should verify signatures by this entity. */
     $certArray = SimpleSAML_Utilities::loadPublicKey($srcMetadata, FALSE);
     if ($certArray !== NULL) {
         if (array_key_exists('PEM', $certArray)) {
             $pemCert = $certArray['PEM'];
         } else {
             /*
              * We don't have the full certificate stored. Try to find it
              * in the message or the assertion instead.
              */
             if (count($certificates) === 0) {
                 /* We need the full certificate in order to match it against the fingerprint. */
                 SimpleSAML_Logger::debug('No certificate in message when validating against fingerprint.');
                 return FALSE;
             }
             $certFingerprints = $certArray['certFingerprint'];
             if (count($certFingerprints) === 0) {
                 /* For some reason, we have a certFingerprint entry without any fingerprints. */
                 throw new SimpleSAML_Error_Exception('certFingerprint array was empty.');
             }
             $pemCert = self::findCertificate($certFingerprints, $certificates);
         }
     } else {
         /* Attempt CA validation. */
         $caFile = $srcMetadata->getString('caFile', NULL);
         if ($caFile === NULL) {
             throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE));
         }
         $caFile = SimpleSAML_Utilities::resolveCert($caFile);
         if (count($certificates) === 0) {
             /* We need the full certificate in order to check it against the CA file. */
             SimpleSAML_Logger::debug('No certificate in message when validating with CA.');
             return FALSE;
         }
         /* We assume that it is the first certificate that was used to sign the message. */
         $pemCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certificates[0], 64) . "-----END CERTIFICATE-----\n";
         SimpleSAML_Utilities::validateCA($pemCert, $caFile);
     }
     /* Extract the public key from the certificate for validation. */
     $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
     $key->loadKey($pemCert);
     /*
      * Make sure that we have a valid signature on either the response
      * or the assertion.
      */
     return $element->validate($key);
 }
 /**
  * This function receives a SAML 1.1 artifact.
  *
  * @param SimpleSAML_Configuration $spMetadata  The metadata of the SP.
  * @param SimpleSAML_Configuration $idpMetadata  The metadata of the IdP.
  * @return string  The <saml1p:Response> element, as an XML string.
  */
 public static function receive(SimpleSAML_Configuration $spMetadata, SimpleSAML_Configuration $idpMetadata)
 {
     $artifacts = self::getArtifacts();
     $request = self::buildRequest($artifacts);
     SimpleSAML_Utilities::debugMessage($msgStr, 'out');
     $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding'));
     $url = $url['Location'];
     $peerPublicKeys = $idpMetadata->getPublicKeys('signing', TRUE);
     $certData = '';
     foreach ($peerPublicKeys as $key) {
         if ($key['type'] !== 'X509Certificate') {
             continue;
         }
         $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
     }
     $file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.crt';
     if (!file_exists($file)) {
         SimpleSAML_Utilities::writeFile($file, $certData);
     }
     $spKeyCertFile = SimpleSAML_Utilities::resolveCert($spMetadata->getString('privatekey'));
     $opts = array('ssl' => array('verify_peer' => TRUE, 'cafile' => $file, 'local_cert' => $spKeyCertFile, 'capture_peer_cert' => TRUE, 'capture_peer_chain' => TRUE), 'http' => array('method' => 'POST', 'content' => $request, 'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" . 'Content-Type: text/xml'));
     /* Fetch the artifact. */
     $response = SimpleSAML_Utilities::fetch($url, $opts);
     if ($response === FALSE) {
         throw new SimpleSAML_Error_Exception('Failed to retrieve assertion from IdP.');
     }
     SimpleSAML_Utilities::debugMessage($response, 'in');
     /* Find the response in the SOAP message. */
     $response = self::extractResponse($response);
     return $response;
 }
 /**
  * Get public key from metadata.
  *
  * @param string|NULL $use  The purpose this key can be used for. (encryption or signing).
  * @param bool $required  Whether the public key is required. If this is TRUE, a
  *                        missing key will cause an exception. Default is FALSE.
  * @param string $prefix  The prefix which should be used when reading from the metadata
  *                        array. Defaults to ''.
  * @return array|NULL  Public key data, or NULL if no public key or was found.
  */
 public function getPublicKeys($use = NULL, $required = FALSE, $prefix = '')
 {
     assert('is_bool($required)');
     assert('is_string($prefix)');
     if ($this->hasValue($prefix . 'keys')) {
         $ret = array();
         foreach ($this->getArray($prefix . 'keys') as $key) {
             if ($use !== NULL && isset($key[$use]) && !$key[$use]) {
                 continue;
             }
             if (isset($key['X509Certificate'])) {
                 /* Strip whitespace from key. */
                 $key['X509Certificate'] = preg_replace('/\\s+/', '', $key['X509Certificate']);
             }
             $ret[] = $key;
         }
         if (!empty($ret)) {
             return $ret;
         }
     } elseif ($this->hasValue($prefix . 'certData')) {
         $certData = $this->getString($prefix . 'certData');
         $certData = preg_replace('/\\s+/', '', $certData);
         return array(array('encryption' => TRUE, 'signing' => TRUE, 'type' => 'X509Certificate', 'X509Certificate' => $certData));
     } elseif ($this->hasValue($prefix . 'certificate')) {
         $file = $this->getString($prefix . 'certificate');
         $file = SimpleSAML_Utilities::resolveCert($file);
         $data = @file_get_contents($file);
         if ($data === FALSE) {
             throw new Exception($this->location . ': Unable to load certificate/public key from file "' . $file . '".');
         }
         /* Extract certificate data (if this is a certificate). */
         $pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
         if (!preg_match($pattern, $data, $matches)) {
             throw new SimpleSAML_Error_Exception($this->location . ': Could not find PEM encoded certificate in "' . $file . '".');
         }
         $certData = preg_replace('/\\s+/', '', $matches[1]);
         return array(array('encryption' => TRUE, 'signing' => TRUE, 'type' => 'X509Certificate', 'X509Certificate' => $certData));
     }
     if ($required) {
         throw new SimpleSAML_Error_Exception($this->location . ': Missing certificate in metadata.');
     } else {
         return NULL;
     }
 }
Esempio n. 9
0
 /**
  * This function sends the SOAP message to the service location and returns SOAP response
  *
  * @param SAML2_Message $m  The request that should be sent.
  * @param SimpleSAML_Configuration $srcMetadata  The metadata of the issuer of the message.
  * @param SimpleSAML_Configuration $dstMetadata  The metadata of the destination of the message.
  * @return SAML2_Message  The response we received.
  */
 public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL)
 {
     $issuer = $msg->getIssuer();
     $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE));
     // Determine if we are going to do a MutualSSL connection between the IdP and SP  - Shoaib
     if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
         $ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
         if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
             $ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
         }
     } else {
         /* Use the SP certificate and privatekey if it is configured. */
         $privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
         $publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
         if ($privateKey !== NULL && $publicKey !== NULL && isset($publicKey['PEM'])) {
             $keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
             $file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
             if (!file_exists($file)) {
                 SimpleSAML_Utilities::writeFile($file, $keyCertData);
             }
             $ctxOpts['ssl']['local_cert'] = $file;
             if (isset($privateKey['password'])) {
                 $ctxOpts['ssl']['passphrase'] = $privateKey['password'];
             }
         }
     }
     // do peer certificate verification
     if ($dstMetadata !== NULL) {
         $peerPublicKeys = $dstMetadata->getPublicKeys('signing', TRUE);
         $certData = '';
         foreach ($peerPublicKeys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
         }
         $peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
         if (!file_exists($peerCertFile)) {
             SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
         }
         // create ssl context
         $ctxOpts['ssl']['verify_peer'] = TRUE;
         $ctxOpts['ssl']['verify_depth'] = 1;
         $ctxOpts['ssl']['cafile'] = $peerCertFile;
     }
     $context = stream_context_create($ctxOpts);
     if ($context === NULL) {
         throw new Exception('Unable to create SSL stream context');
     }
     $options = array('uri' => $issuer, 'location' => $msg->getDestination(), 'stream_context' => $context);
     $x = new SoapClient(NULL, $options);
     // Add soap-envelopes
     $request = $msg->toSignedXML();
     $request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
     SimpleSAML_Utilities::debugMessage($request, 'out');
     $action = 'http://www.oasis-open.org/committees/security';
     $version = '1.1';
     $destination = $msg->getDestination();
     /* Perform SOAP Request over HTTP */
     $soapresponsexml = $x->__doRequest($request, $destination, $action, $version);
     if ($soapresponsexml === NULL || $soapresponsexml === "") {
         throw new Exception('Empty SOAP response, check peer certificate.');
     }
     SimpleSAML_Utilities::debugMessage($soapresponsexml, 'in');
     // Convert to SAML2_Message (DOMElement)
     $dom = new DOMDocument();
     if (!$dom->loadXML($soapresponsexml)) {
         throw new Exception('Not a SOAP response.');
     }
     $soapfault = $this->getSOAPFault($dom);
     if (isset($soapfault)) {
         throw new Exception($soapfault);
     }
     //Extract the message from the response
     $xml = $dom->firstChild;
     /* Soap Envelope */
     $samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
     $samlresponse = SAML2_Message::fromXML($samlresponse[0]);
     /* Add validator to message which uses the SSL context. */
     self::addSSLValidator($samlresponse, $context);
     SimpleSAML_Logger::debug("Valid ArtifactResponse received from IdP");
     return $samlresponse;
 }
Esempio n. 10
0
 public static function sendResponse(array $state)
 {
     $spMetadata = $state["SPMetadata"];
     $spEntityId = $spMetadata['entityid'];
     $spMetadata = SimpleSAML_Configuration::loadFromArray($spMetadata, '$metadata[' . var_export($spEntityId, TRUE) . ']');
     $attributes = $state['Attributes'];
     $nameidattribute = $spMetadata->getValue('simplesaml.nameidattribute');
     if (!empty($nameidattribute)) {
         if (!array_key_exists($nameidattribute, $attributes)) {
             throw new Exception('simplesaml.nameidattribute does not exist in resulting attribute set');
         }
         $nameid = $attributes[$nameidattribute][0];
     } else {
         $nameid = SimpleSAML_Utilities::generateID();
     }
     $idp = SimpleSAML_IdP::getByState($state);
     $idpMetadata = $idp->getConfig();
     $idpEntityId = $idpMetadata->getString('entityid');
     $idp->addAssociation(array('id' => 'adfs:' . $spEntityId, 'Handler' => 'sspmod_adfs_IdP_ADFS', 'adfs:entityID' => $spEntityId));
     $response = sspmod_adfs_IdP_ADFS::ADFS_GenerateResponse($idpEntityId, $spEntityId, $nameid, $attributes);
     $privateKeyFile = SimpleSAML_Utilities::resolveCert($idpMetadata->getString('privatekey'));
     $certificateFile = SimpleSAML_Utilities::resolveCert($idpMetadata->getString('certificate'));
     $wresult = sspmod_adfs_IdP_ADFS::ADFS_SignResponse($response, $privateKeyFile, $certificateFile);
     $wctx = $state['adfs:wctx'];
     sspmod_adfs_IdP_ADFS::ADFS_PostResponse($spMetadata->getValue('prp'), $wresult, $wctx);
 }
Esempio n. 11
0
 /**
  * This function sends the SOAP message to the service location and returns SOAP response
  *
  * @param  SAML2_Message            $msg         The request that should be sent.
  * @param  SimpleSAML_Configuration $srcMetadata The metadata of the issuer of the message.
  * @param  SimpleSAML_Configuration $dstMetadata The metadata of the destination of the message.
  * @return SAML2_Message            The response we received.
  * @throws Exception
  */
 public function send(SAML2_Message $msg, SimpleSAML_Configuration $srcMetadata, SimpleSAML_Configuration $dstMetadata = NULL)
 {
     $issuer = $msg->getIssuer();
     $ctxOpts = array('ssl' => array('capture_peer_cert' => TRUE));
     /* Determine if we are going to do a MutualSSL connection between the IdP and SP  - Shoaib */
     if ($srcMetadata->hasValue('saml.SOAPClient.certificate')) {
         $cert = $srcMetadata->getValue('saml.SOAPClient.certificate');
         if ($cert !== FALSE) {
             $ctxOpts['ssl']['local_cert'] = SimpleSAML_Utilities::resolveCert($srcMetadata->getString('saml.SOAPClient.certificate'));
             if ($srcMetadata->hasValue('saml.SOAPClient.privatekey_pass')) {
                 $ctxOpts['ssl']['passphrase'] = $srcMetadata->getString('saml.SOAPClient.privatekey_pass');
             }
         }
     } else {
         /* Use the SP certificate and privatekey if it is configured. */
         $privateKey = SimpleSAML_Utilities::loadPrivateKey($srcMetadata);
         $publicKey = SimpleSAML_Utilities::loadPublicKey($srcMetadata);
         if ($privateKey !== NULL && $publicKey !== NULL && isset($publicKey['PEM'])) {
             $keyCertData = $privateKey['PEM'] . $publicKey['PEM'];
             $file = SimpleSAML_Utilities::getTempDir() . '/' . sha1($keyCertData) . '.pem';
             if (!file_exists($file)) {
                 SimpleSAML_Utilities::writeFile($file, $keyCertData);
             }
             $ctxOpts['ssl']['local_cert'] = $file;
             if (isset($privateKey['password'])) {
                 $ctxOpts['ssl']['passphrase'] = $privateKey['password'];
             }
         }
     }
     /* Do peer certificate verification */
     if ($dstMetadata !== NULL) {
         $peerPublicKeys = $dstMetadata->getPublicKeys('signing', TRUE);
         $certData = '';
         foreach ($peerPublicKeys as $key) {
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
             $certData .= "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
         }
         $peerCertFile = SimpleSAML_Utilities::getTempDir() . '/' . sha1($certData) . '.pem';
         if (!file_exists($peerCertFile)) {
             SimpleSAML_Utilities::writeFile($peerCertFile, $certData);
         }
         /* Create ssl context */
         $ctxOpts['ssl']['verify_peer'] = TRUE;
         $ctxOpts['ssl']['verify_depth'] = 1;
         $ctxOpts['ssl']['cafile'] = $peerCertFile;
     }
     $ctxOpts['http']['header'] = 'SOAPAction: "http://www.oasis-open.org/committees/security"' . "\n";
     if ($this->username !== NULL && $this->password !== NULL) {
         /* Add HTTP Basic authentication header. */
         $authData = $this->username . ':' . $this->password;
         $authData = base64_encode($authData);
         $ctxOpts['http']['header'] .= 'Authorization: Basic ' . $authData . "\n";
     }
     if ($srcMetadata->hasValue('saml.SOAPClient.proxyhost')) {
         $options['proxy_host'] = $srcMetadata->getValue('saml.SOAPClient.proxyhost');
     }
     if ($srcMetadata->hasValue('saml.SOAPClient.proxyport')) {
         $options['proxy_port'] = $srcMetadata->getValue('saml.SOAPClient.proxyport');
     }
     $x = new SoapClient(NULL, $options);
     /* Add soap-envelopes */
     $request = $msg->toSignedXML();
     $request = self::START_SOAP_ENVELOPE . $request->ownerDocument->saveXML($request) . self::END_SOAP_ENVELOPE;
     SAML2_Utils::getContainer()->debugMessage($request, 'out');
     $ctxOpts['http']['content'] = $request;
     $ctxOpts['http']['header'] .= 'Content-Type: text/xml; charset=utf-8' . "\n";
     $ctxOpts['http']['method'] = 'POST';
     $destination = $msg->getDestination();
     /* Perform SOAP Request over HTTP */
     $context = stream_context_create($ctxOpts);
     if ($context === NULL) {
         throw new Exception('Unable to create stream context');
     }
     $soapresponsexml = @file_get_contents($destination, FALSE, $context);
     if ($soapresponsexml === FALSE) {
         throw new Exception('Error processing SOAP call: ' . SimpleSAML_Utilities::getLastError());
     }
     SAML2_Utils::getContainer()->debugMessage($soapresponsexml, 'in');
     /* Convert to SAML2_Message (DOMElement) */
     try {
         $dom = SAML2_DOMDocumentFactory::fromString($soapresponsexml);
     } catch (SAML2_Exception_RuntimeException $e) {
         throw new Exception('Not a SOAP response.', 0, $e);
     }
     $soapfault = $this->getSOAPFault($dom);
     if (isset($soapfault)) {
         throw new Exception($soapfault);
     }
     /* Extract the message from the response */
     $samlresponse = SAML2_Utils::xpQuery($dom->firstChild, '/soap-env:Envelope/soap-env:Body/*[1]');
     $samlresponse = SAML2_Message::fromXML($samlresponse[0]);
     /* Add validator to message which uses the SSL context. */
     self::addSSLValidator($samlresponse, $context);
     SAML2_Utils::getContainer()->getLogger()->debug("Valid ArtifactResponse received from IdP");
     return $samlresponse;
 }
Esempio n. 12
0
 /**
  * Check the signature on a SAML2 message or assertion.
  *
  * @param SimpleSAML_Configuration $srcMetadata  The metadata of the sender.
  * @param SAML2_SignedElement $element  Either a SAML2_Response or a SAML2_Assertion.
  */
 public static function checkSign(SimpleSAML_Configuration $srcMetadata, SAML2_SignedElement $element)
 {
     /* Find the public key that should verify signatures by this entity. */
     $keys = $srcMetadata->getPublicKeys('signing');
     if ($keys !== NULL) {
         $pemKeys = array();
         foreach ($keys as $key) {
             switch ($key['type']) {
                 case 'X509Certificate':
                     $pemKeys[] = "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n";
                     break;
                 default:
                     SimpleSAML_Logger::debug('Skipping unknown key type: ' . $key['type']);
             }
         }
     } elseif ($srcMetadata->hasValue('certFingerprint')) {
         $certFingerprint = $srcMetadata->getArrayizeString('certFingerprint');
         foreach ($certFingerprint as &$fp) {
             $fp = strtolower(str_replace(':', '', $fp));
         }
         $certificates = $element->getCertificates();
         /*
          * We don't have the full certificate stored. Try to find it
          * in the message or the assertion instead.
          */
         if (count($certificates) === 0) {
             /* We need the full certificate in order to match it against the fingerprint. */
             SimpleSAML_Logger::debug('No certificate in message when validating against fingerprint.');
             return FALSE;
         } else {
             SimpleSAML_Logger::debug('Found ' . count($certificates) . ' certificates in ' . get_class($element));
         }
         $pemCert = self::findCertificate($certFingerprint, $certificates);
         $pemKeys = array($pemCert);
     } else {
         /* Attempt CA validation. */
         $caFile = $srcMetadata->getString('caFile', NULL);
         if ($caFile === NULL) {
             throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE));
         }
         $caFile = SimpleSAML_Utilities::resolveCert($caFile);
         if (count($certificates) === 0) {
             /* We need the full certificate in order to check it against the CA file. */
             SimpleSAML_Logger::debug('No certificate in message when validating with CA.');
             return FALSE;
         }
         /* We assume that it is the first certificate that was used to sign the message. */
         $pemCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certificates[0], 64) . "-----END CERTIFICATE-----\n";
         SimpleSAML_Utilities::validateCA($pemCert, $caFile);
         $pemKeys = array($pemCert);
     }
     SimpleSAML_Logger::debug('Has ' . count($pemKeys) . ' candidate keys for validation.');
     $lastException = NULL;
     foreach ($pemKeys as $i => $pem) {
         $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
         $key->loadKey($pem);
         try {
             /*
              * Make sure that we have a valid signature on either the response
              * or the assertion.
              */
             $res = $element->validate($key);
             if ($res) {
                 SimpleSAML_Logger::debug('Validation with key #' . $i . ' succeeded.');
                 return TRUE;
             }
             SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed without exception.');
         } catch (Exception $e) {
             SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed with exception: ' . $e->getMessage());
             $lastException = $e;
         }
     }
     /* We were unable to validate the signature with any of our keys. */
     if ($lastException !== NULL) {
         throw $lastException;
     } else {
         return FALSE;
     }
 }
Esempio n. 13
0
 /**
  * Signs the given metadata if metadata signing is enabled.
  *
  * @param $metadataString  A string with the metadata.
  * @param $entityMetadata  The metadata of the entity.
  * @param $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
  * @return The $metadataString with the signature embedded.
  */
 public static function sign($metadataString, $entityMetadata, $type)
 {
     $config = SimpleSAML_Configuration::getInstance();
     /* Check if metadata signing is enabled. */
     if (!self::isMetadataSigningEnabled($config, $entityMetadata, $type)) {
         return $metadataString;
     }
     /* Find the key & certificate which should be used to sign the metadata. */
     $keyCertFiles = self::findKeyCert($config, $entityMetadata, $type);
     $keyFile = SimpleSAML_Utilities::resolveCert($keyCertFiles['privatekey']);
     if (!file_exists($keyFile)) {
         throw new Exception('Could not find private key file [' . $keyFile . '], which is needed to sign the metadata');
     }
     $keyData = file_get_contents($keyFile);
     $certFile = SimpleSAML_Utilities::resolveCert($keyCertFiles['certificate']);
     if (!file_exists($certFile)) {
         throw new Exception('Could not find certificate file [' . $certFile . '], which is needed to sign the metadata');
     }
     $certData = file_get_contents($certFile);
     /* Convert the metadata to a DOM tree. */
     $xml = new DOMDocument();
     if (!$xml->loadXML($metadataString)) {
         throw new Exception('Error parsing self-generated metadata.');
     }
     /* Load the private key. */
     $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
     if (array_key_exists('privatekey_pass', $keyCertFiles)) {
         $objKey->passphrase = $keyCertFiles['privatekey_pass'];
     }
     $objKey->loadKey($keyData, FALSE);
     /* Get the EntityDescriptor node we should sign. */
     $rootNode = $xml->firstChild;
     /* Sign the metadata with our private key. */
     if ($type == 'ADFS IdP') {
         $objXMLSecDSig = new sspmod_adfs_XMLSecurityDSig($metadataString);
     } else {
         $objXMLSecDSig = new XMLSecurityDSig();
     }
     $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
     $objXMLSecDSig->addReferenceList(array($rootNode), XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), array('id_name' => 'ID'));
     $objXMLSecDSig->sign($objKey);
     /* Add the certificate to the signature. */
     $objXMLSecDSig->add509Cert($certData, true);
     /* Add the signature to the metadata. */
     $objXMLSecDSig->insertSignature($rootNode, $rootNode->firstChild);
     /* Return the DOM tree as a string. */
     return $xml->saveXML();
 }
Esempio n. 14
0
 /**
  * Add an extra certificate to the certificate chain in the signature.
  *
  * Extra certificates will be added to the certificate chain in the order they
  * are added.
  *
  * @param $file  The file which contains the certificate, relative to the cert-directory.
  */
 public function addCertificate($file)
 {
     assert('is_string($file)');
     $certFile = SimpleSAML_Utilities::resolveCert($file);
     if (!file_exists($certFile)) {
         throw new Exception('Could not find extra certificate file "' . $certFile . '".');
     }
     $certificate = file_get_contents($certFile);
     if ($certificate === FALSE) {
         throw new Exception('Unable to read extra certificate file "' . $certFile . '".');
     }
     $this->extraCertificates[] = $certificate;
 }