From 8ca6cc32b2c789a3149861159ad258f2cb9491e3 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 14:39:39 +0200 Subject: Adding upstream version 2.11.4. Signed-off-by: Daniel Baumann --- library/Icinga/Web/Session/Php72Session.php | 37 ++++ library/Icinga/Web/Session/PhpSession.php | 256 ++++++++++++++++++++++++ library/Icinga/Web/Session/Session.php | 126 ++++++++++++ library/Icinga/Web/Session/SessionNamespace.php | 201 +++++++++++++++++++ 4 files changed, 620 insertions(+) create mode 100644 library/Icinga/Web/Session/Php72Session.php create mode 100644 library/Icinga/Web/Session/PhpSession.php create mode 100644 library/Icinga/Web/Session/Session.php create mode 100644 library/Icinga/Web/Session/SessionNamespace.php (limited to 'library/Icinga/Web/Session') diff --git a/library/Icinga/Web/Session/Php72Session.php b/library/Icinga/Web/Session/Php72Session.php new file mode 100644 index 0000000..e6a6b19 --- /dev/null +++ b/library/Icinga/Web/Session/Php72Session.php @@ -0,0 +1,37 @@ +sessionName); + + $cookie = new Cookie('bogus'); + session_set_cookie_params( + 0, + $cookie->getPath(), + $cookie->getDomain(), + $cookie->isSecure(), + true + ); + + session_start(array( + 'use_cookies' => true, + 'use_only_cookies' => true, + 'use_trans_sid' => false + )); + } +} diff --git a/library/Icinga/Web/Session/PhpSession.php b/library/Icinga/Web/Session/PhpSession.php new file mode 100644 index 0000000..36dd84e --- /dev/null +++ b/library/Icinga/Web/Session/PhpSession.php @@ -0,0 +1,256 @@ + false, + 'use_cookies' => true, + 'cookie_httponly' => true, + 'use_only_cookies' => true + ); + + if (version_compare(PHP_VERSION, '7.1.0') < 0) { + $defaultCookieOptions['hash_function'] = true; + $defaultCookieOptions['hash_bits_per_character'] = 5; + } else { + $defaultCookieOptions['sid_bits_per_character'] = 5; + } + + if ($options !== null) { + $options = array_merge($defaultCookieOptions, $options); + } else { + $options = $defaultCookieOptions; + } + + if (array_key_exists('test_session_name', $options)) { + $this->sessionName = $options['test_session_name']; + unset($options['test_session_name']); + } + + foreach ($options as $sessionVar => $value) { + if (ini_set("session." . $sessionVar, $value) === false) { + Logger::warning( + 'Could not set php.ini setting %s = %s. This might affect your sessions behaviour.', + $sessionVar, + $value + ); + } + } + + $sessionSavePath = session_save_path() ?: sys_get_temp_dir(); + if (session_module_name() === 'files' && !is_writable($sessionSavePath)) { + throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable."); + } + + if ($this->exists()) { + // We do not want to start a new session here if there is not any + $this->read(); + } + } + + /** + * Open a PHP session + */ + protected function open() + { + session_name($this->sessionName); + + if ($this->hasBeenTouched) { + $cacheLimiter = ini_get('session.cache_limiter'); + ini_set('session.use_cookies', false); + ini_set('session.use_only_cookies', false); + ini_set('session.cache_limiter', null); + } + + $cookie = new Cookie('bogus'); + session_set_cookie_params( + 0, + $cookie->getPath(), + $cookie->getDomain(), + $cookie->isSecure(), + true + ); + + session_start(); + + if ($this->hasBeenTouched) { + ini_set('session.use_cookies', true); + ini_set('session.use_only_cookies', true); + /** @noinspection PhpUndefinedVariableInspection */ + ini_set('session.cache_limiter', $cacheLimiter); + } + } + + /** + * Read all values written to the underling session and make them accessible. + */ + public function read() + { + $this->clear(); + $this->open(); + + foreach ($_SESSION as $key => $value) { + if (strpos($key, self::NAMESPACE_PREFIX) === 0) { + $namespace = new SessionNamespace(); + $namespace->setAll($value); + $this->namespaces[substr($key, strlen(self::NAMESPACE_PREFIX))] = $namespace; + } else { + $this->set($key, $value); + } + } + + session_write_close(); + $this->hasBeenTouched = true; + } + + /** + * Write all values of this session object to the underlying session implementation + */ + public function write() + { + $this->open(); + + foreach ($this->removed as $key) { + unset($_SESSION[$key]); + } + foreach ($this->values as $key => $value) { + $_SESSION[$key] = $value; + } + foreach ($this->removedNamespaces as $identifier) { + unset($_SESSION[self::NAMESPACE_PREFIX . $identifier]); + } + foreach ($this->namespaces as $identifier => $namespace) { + $_SESSION[self::NAMESPACE_PREFIX . $identifier] = $namespace->getAll(); + } + + session_write_close(); + $this->hasBeenTouched = true; + } + + /** + * Delete the current session, causing all session information to be lost + */ + public function purge() + { + $this->open(); + $_SESSION = array(); + $this->clear(); + session_destroy(); + $this->clearCookies(); + session_write_close(); + $this->hasBeenTouched = true; + } + + /** + * Remove session cookies + */ + protected function clearCookies() + { + if (ini_get('session.use_cookies')) { + Logger::debug('Clear session cookie'); + $params = session_get_cookie_params(); + setcookie( + session_name(), + '', + time() - 42000, + $params['path'], + $params['domain'], + $params['secure'], + $params['httponly'] + ); + } + } + + /** + * @see Session::getId() + */ + public function getId() + { + if (($id = session_id()) === '') { + // Make sure we actually get a id + $this->open(); + session_write_close(); + $this->hasBeenTouched = true; + $id = session_id(); + } + + return $id; + } + + /** + * Assign a new sessionId to the currently active session + */ + public function refreshId() + { + $this->open(); + if ($this->exists()) { + session_regenerate_id(); + } + session_write_close(); + $this->hasBeenTouched = true; + } + + /** + * @see Session::exists() + */ + public function exists() + { + return isset($_COOKIE[$this->sessionName]); + } +} diff --git a/library/Icinga/Web/Session/Session.php b/library/Icinga/Web/Session/Session.php new file mode 100644 index 0000000..e73e9b4 --- /dev/null +++ b/library/Icinga/Web/Session/Session.php @@ -0,0 +1,126 @@ +namespaces[$identifier])) { + if (in_array($identifier, $this->removedNamespaces, true)) { + unset($this->removedNamespaces[array_search($identifier, $this->removedNamespaces, true)]); + } + + $this->namespaces[$identifier] = new SessionNamespace(); + } + + return $this->namespaces[$identifier]; + } + + /** + * Return whether the given session namespace exists + * + * @param string $identifier The namespace's identifier to check + * + * @return bool + */ + public function hasNamespace($identifier) + { + return isset($this->namespaces[$identifier]); + } + + /** + * Remove the given session namespace + * + * @param string $identifier The identifier of the namespace to remove + */ + public function removeNamespace($identifier) + { + unset($this->namespaces[$identifier]); + $this->removedNamespaces[] = $identifier; + } + + /** + * Return whether the session has changed + * + * @return bool + */ + public function hasChanged() + { + return parent::hasChanged() || false === empty($this->namespaces) || false === empty($this->removedNamespaces); + } + + /** + * Clear all values and namespaces from the session cache + */ + public function clear() + { + parent::clear(); + $this->namespaces = array(); + $this->removedNamespaces = array(); + } +} diff --git a/library/Icinga/Web/Session/SessionNamespace.php b/library/Icinga/Web/Session/SessionNamespace.php new file mode 100644 index 0000000..1c9c13f --- /dev/null +++ b/library/Icinga/Web/Session/SessionNamespace.php @@ -0,0 +1,201 @@ +getAll()); + } + + /** + * Set a session value by property access + * + * @param string $key The value's name + * @param mixed $value The value + */ + public function __set($key, $value) + { + $this->set($key, $value); + } + + /** + * Return a session value by property access + * + * @param string $key The value's name + * + * @return mixed The value + * @throws Exception When the given value-name is not found + */ + public function __get($key) + { + if (!array_key_exists($key, $this->values)) { + throw new IcingaException( + 'Cannot access non-existent session value "%s"', + $key + ); + } + + return $this->get($key); + } + + /** + * Return whether the given session value is set + * + * @param string $key The value's name + * @return bool + */ + public function __isset($key) + { + return isset($this->values[$key]); + } + + /** + * Unset the given session value + * + * @param string $key The value's name + */ + public function __unset($key) + { + $this->delete($key); + } + + /** + * Setter for session values + * + * @param string $key Name of value + * @param mixed $value Value to set + * + * @return $this + */ + public function set($key, $value) + { + $this->values[$key] = $value; + + if (in_array($key, $this->removed, true)) { + unset($this->removed[array_search($key, $this->removed, true)]); + } + + return $this; + } + + public function setByRef($key, &$value) + { + $this->values[$key] = & $value; + + if (in_array($key, $this->removed, true)) { + unset($this->removed[array_search($key, $this->removed, true)]); + } + + return $this; + } + + /** + * Getter for session values + * + * @param string $key Name of the value to return + * @param mixed $default Default value to return + * + * @return mixed + */ + public function get($key, $default = null) + { + return isset($this->values[$key]) ? $this->values[$key] : $default; + } + + public function & getByRef($key, $default = null) + { + $value = $default; + if (isset($this->values[$key])) { + $value = & $this->values[$key]; + } + + return $value; + } + + /** + * Delete the given value from the session + * + * @param string $key The value's name + */ + public function delete($key) + { + $this->removed[] = $key; + unset($this->values[$key]); + } + + /** + * Getter for all session values + * + * @return array + */ + public function getAll() + { + return $this->values; + } + + /** + * Put an array into the session + * + * @param array $values Values to set + * @param bool $overwrite Overwrite existing values + */ + public function setAll(array $values, $overwrite = false) + { + foreach ($values as $key => $value) { + if ($this->get($key, $value) !== $value && !$overwrite) { + continue; + } + $this->set($key, $value); + } + } + + /** + * Return whether the session namespace has been changed + * + * @return bool + */ + public function hasChanged() + { + return false === empty($this->values) || false === empty($this->removed); + } + + /** + * Clear all values from the session namespace + */ + public function clear() + { + $this->values = array(); + $this->removed = array(); + } +} -- cgit v1.2.3