/** * Hook to run a cron job. * * @param array &$croninfo Output */ function statistics_hook_cron(&$croninfo) { assert('is_array($croninfo)'); assert('array_key_exists("summary", $croninfo)'); assert('array_key_exists("tag", $croninfo)'); $statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php'); if (is_null($statconfig->getValue('cron_tag', NULL))) { return; } if ($statconfig->getValue('cron_tag', NULL) !== $croninfo['tag']) { return; } $maxtime = $statconfig->getInteger('time_limit', NULL); if ($maxtime) { set_time_limit($maxtime); } try { $aggregator = new sspmod_statistics_Aggregator(); $results = $aggregator->aggregate(); if (empty($results)) { SimpleSAML\Logger::notice('Output from statistics aggregator was empty.'); } else { $aggregator->store($results); } } catch (Exception $e) { $message = 'Loganalyzer threw exception: ' . $e->getMessage(); SimpleSAML\Logger::warning($message); $croninfo['summary'][] = $message; } }
/** * 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')) { SimpleSAML\Logger::notice("Validating certificates by fingerprint is deprecated. Please use " . "certData or certificate options in your remote metadata configuration."); $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 { throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE)); } 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; } }
/** * Process this filter * * Logic is largely the same as (and lifted from) sqlauth:sql * @param mixed &$request * @throws SimpleSAML_Error_Exception */ public function process(&$request) { assert('is_array($request)'); assert('array_key_exists("Attributes", $request)'); assert('array_key_exists("entityid", $request["Destination"])'); $attributes =& $request['Attributes']; if (!array_key_exists($this->attribute, $attributes)) { SimpleSAML\Logger::info('AttributeFromSQL: attribute \'' . $this->attribute . '\' not set, declining'); return; } $db = $this->connect(); try { $sth = $db->prepare('SELECT attribute,value FROM ' . $this->table . ' WHERE uid=? AND (sp=\'%\' OR sp=?);'); } catch (PDOException $e) { throw new SimpleSAML_Error_Exception('AttributeFromSQL: prepare() failed: ' . $e->getMessage()); } try { $res = $sth->execute(array($attributes[$this->attribute][0], $request["Destination"]["entityid"])); } catch (PDOException $e) { throw new SimpleSAML_Error_Exception('AttributeFromSQL: execute(' . $attributes[$this->attribute][0] . ', ' . $request["Destination"]["entityid"] . ') failed: ' . $e->getMessage()); } try { $data = $sth->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { throw new SimpleSAML_Error_Exception('AttributeFromSQL: fetchAll() failed: ' . $e->getMessage()); } if (count($data) === 0) { SimpleSAML\Logger::info('AttributeFromSQL: no additional attributes for ' . $this->attribute . '=\'' . $attributes[$this->attribute][0] . '\''); return; } /* Extract attributes from the SQL datasource, and then merge them into * the existing attribute set. If $replace is set, overwrite any existing * attribute of the same name; otherwise add it as a multi-valued attribute */ foreach ($data as $row) { if (empty($row['attribute']) || $row['value'] === null) { SimpleSAML\Logger::debug('AttributeFromSQL: skipping invalid attribute/value tuple: ' . var_export($row, true)); continue; } $name = (string) $row['attribute']; $value = (string) $row['value']; /* Limit the attribute set returned */ if ($this->limit !== null && !in_array($name, $this->limit, true)) { SimpleSAML\Logger::notice('AttributeFromSQL: skipping unwanted attribute ' . $name . ' [limited to: ' . var_export($this->limit, true) . ']'); continue; } if (!array_key_exists($name, $attributes) || $this->replace === true) { $attributes[$name] = array(); } if (in_array($value, $attributes[$name], true)) { /* Value already exists in attribute. */ SimpleSAML\Logger::debug('AttributeFromSQL: skipping duplicate attribute/value tuple ' . $name . '=\'' . $value . '\''); continue; } $attributes[$name][] = $value; } }
/** * Searches LDAP using a ActiveDirectory specific filter, * looking for group membership for the users DN. Returns * the list of group DNs retrieved. * * @param string $dn * @return array */ protected function searchActiveDirectory($dn) { assert('is_string($dn) && $dn != ""'); // Shorten the variable name $map =& $this->attribute_map; // Log the search SimpleSAML\Logger::debug($this->title . 'Searching ActiveDirectory group membership.' . ' DN: ' . $dn . ' DN Attribute: ' . $map['dn'] . ' Member Attribute: ' . $map['member'] . ' Type Attribute: ' . $map['type'] . ' Type Value: ' . $this->type_map['group'] . ' Base: ' . implode('; ', $this->base_dn)); // AD connections should have this set $this->getLdap()->setOption(LDAP_OPT_REFERRALS, 0); // Search AD with the specific recursive flag try { $entries = $this->getLdap()->searchformultiple($this->base_dn, array($map['type'] => $this->type_map['group'], $map['member'] . ':1.2.840.113556.1.4.1941:' => $dn), array($map['dn'])); // The search may throw an exception if no entries // are found, unlikely but possible. } catch (SimpleSAML_Error_UserNotFound $e) { return array(); } //Init the groups $groups = array(); // Check each entry.. foreach ($entries as $entry) { // Check for the DN using the original attribute name if (isset($entry[$map['dn']][0])) { $groups[] = $entry[$map['dn']][0]; continue; } // Sometimes the returned attribute names are lowercase if (isset($entry[strtolower($map['dn'])][0])) { $groups[] = $entry[strtolower($map['dn'])][0]; continue; } // AD queries also seem to return the objects dn by default if (isset($entry['dn'])) { $groups[] = $entry['dn']; continue; } // Could not find DN, log and continue SimpleSAML\Logger::notice($this->title . 'The DN attribute [' . implode(', ', array($map['dn'], strtolower($map['dn']), 'dn')) . '] could not be found in the entry. ' . $this->var_export($entry)); } // All done return $groups; }