PDF rausgenommen

This commit is contained in:
aschwarz
2023-01-23 11:03:31 +01:00
parent 82d562a322
commit a6523903eb
28078 changed files with 4247552 additions and 2 deletions

View File

@ -0,0 +1,199 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Session\SaveHandler;
use Piwik\Common;
use Piwik\Db;
use Piwik\DbHelper;
use Exception;
use Piwik\Updater\Migration;
use Zend_Session;
use Zend_Session_SaveHandler_Interface;
/**
* Database-backed session save handler
*
*/
class DbTable implements Zend_Session_SaveHandler_Interface
{
protected $config;
protected $maxLifetime;
const TABLE_NAME = 'session';
/**
* @param array $config
*/
public function __construct($config)
{
$this->config = $config;
$this->maxLifetime = ini_get('session.gc_maxlifetime');
}
/**
* Destructor
*
* @return void
*/
public function __destruct()
{
Zend_Session::writeClose();
}
/**
* Open Session - retrieve resources
*
* @param string $save_path
* @param string $name
* @return boolean
*/
public function open($save_path, $name)
{
Db::get()->getConnection();
return true;
}
/**
* Close Session - free resources
*
* @return boolean
*/
public function close()
{
return true;
}
/**
* Read session data
*
* @param string $id
* @return string
*/
public function read($id)
{
$sql = 'SELECT ' . $this->config['dataColumn'] . ' FROM ' . $this->config['name']
. ' WHERE ' . $this->config['primary'] . ' = ?'
. ' AND ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' >= ?';
$result = $this->fetchOne($sql, array($id, time()));
if (!$result) {
$result = '';
}
return $result;
}
private function fetchOne($sql, $bind)
{
try {
$result = Db::get()->fetchOne($sql, $bind);
} catch (Exception $e) {
if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
$this->migrateToDbSessionTable();
$result = Db::get()->fetchOne($sql, $bind);
} else {
throw $e;
}
}
return $result;
}
private function query($sql, $bind)
{
try {
$result = Db::get()->query($sql, $bind);
} catch (Exception $e) {
if (Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_NOT_EXISTS)) {
$this->migrateToDbSessionTable();
$result = Db::get()->query($sql, $bind);
} else {
throw $e;
}
}
return $result;
}
/**
* Write Session - commit data to resource
*
* @param string $id
* @param mixed $data
* @return boolean
*/
public function write($id, $data)
{
$sql = 'INSERT INTO ' . $this->config['name']
. ' (' . $this->config['primary'] . ','
. $this->config['modifiedColumn'] . ','
. $this->config['lifetimeColumn'] . ','
. $this->config['dataColumn'] . ')'
. ' VALUES (?,?,?,?)'
. ' ON DUPLICATE KEY UPDATE '
. $this->config['modifiedColumn'] . ' = ?,'
. $this->config['lifetimeColumn'] . ' = ?,'
. $this->config['dataColumn'] . ' = ?';
$this->query($sql, array($id, time(), $this->maxLifetime, $data, time(), $this->maxLifetime, $data));
return true;
}
/**
* Destroy Session - remove data from resource for
* given session id
*
* @param string $id
* @return boolean
*/
public function destroy($id)
{
$sql = 'DELETE FROM ' . $this->config['name'] . ' WHERE ' . $this->config['primary'] . ' = ?';
$this->query($sql, array($id));
return true;
}
/**
* Garbage Collection - remove old session data older
* than $maxlifetime (in seconds)
*
* @param int $maxlifetime timestamp in seconds
* @return bool always true
*/
public function gc($maxlifetime)
{
$sql = 'DELETE FROM ' . $this->config['name']
. ' WHERE ' . $this->config['modifiedColumn'] . ' + ' . $this->config['lifetimeColumn'] . ' < ?';
$this->query($sql, array(time()));
return true;
}
private function migrateToDbSessionTable()
{
// happens when updating from Piwik 1.4 or earlier to Matomo 3.7+
// in this case on update it will change the session handler to dbtable, but it hasn't performed
// the DB updates just yet which means the session table won't be available as it was only added in
// Piwik 1.5 => results in a sql error the session table does not exist
try {
$sql = DbHelper::getTableCreateSql(self::TABLE_NAME);
Db::query($sql);
} catch (Exception $e) {
if (!Db::get()->isErrNo($e, Migration\Db::ERROR_CODE_TABLE_EXISTS)) {
throw $e;
}
}
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Session;
use Piwik\Auth;
use Piwik\AuthResult;
use Piwik\Config;
use Piwik\Date;
use Piwik\Plugins\UsersManager\Model as UsersModel;
use Piwik\Session;
/**
* Validates already authenticated sessions.
*
* See {@link \Piwik\Session\SessionFingerprint} for more info.
*/
class SessionAuth implements Auth
{
/**
* For tests, since there's no actual session there.
*
* @var bool
*/
private $shouldDestroySession;
/**
* @var UsersModel
*/
private $userModel;
/**
* Set internally so it can be queried in FrontController.
*
* @var array
*/
private $user;
public function __construct(UsersModel $userModel = null, $shouldDestroySession = true)
{
$this->userModel = $userModel ?: new UsersModel();
$this->shouldDestroySession = $shouldDestroySession;
}
public function getName()
{
// empty
}
public function setTokenAuth($token_auth)
{
// empty
}
public function getLogin()
{
return $this->user['login'];
}
public function getTokenAuthSecret()
{
// empty
}
public function setLogin($login)
{
// empty
}
public function setPassword($password)
{
// empty
}
public function setPasswordHash($passwordHash)
{
// empty
}
public function authenticate()
{
$sessionFingerprint = new SessionFingerprint();
$userModel = $this->userModel;
$userForSession = $sessionFingerprint->getUser();
if (empty($userForSession)) {
return $this->makeAuthFailure();
}
$user = $userModel->getUser($userForSession);
if (empty($user)
|| $user['login'] !== $userForSession // sanity check in case there's a bug in getUser()
) {
return $this->makeAuthFailure();
}
$tsPasswordModified = !empty($user['ts_password_modified']) ? $user['ts_password_modified'] : null;
if ($this->isSessionStartedBeforePasswordChange($sessionFingerprint, $tsPasswordModified)) {
$this->destroyCurrentSession($sessionFingerprint);
return $this->makeAuthFailure();
}
if ($sessionFingerprint->isRemembered()) {
$this->updateSessionExpireTime();
}
return $this->makeAuthSuccess($user);
}
private function isSessionStartedBeforePasswordChange(SessionFingerprint $sessionFingerprint, $tsPasswordModified)
{
// sanity check, make sure users can still login if the ts_password_modified column does not exist
if ($tsPasswordModified === null) {
return false;
}
// if the session start time doesn't exist for some reason, log the user out
$sessionStartTime = $sessionFingerprint->getSessionStartTime();
if (empty($sessionStartTime)) {
return true;
}
return $sessionStartTime < Date::factory($tsPasswordModified)->getTimestampUTC();
}
private function makeAuthFailure()
{
return new AuthResult(AuthResult::FAILURE, null, null);
}
private function makeAuthSuccess($user)
{
$this->user = $user;
$isSuperUser = (int) $user['superuser_access'];
$code = $isSuperUser ? AuthResult::SUCCESS_SUPERUSER_AUTH_CODE : AuthResult::SUCCESS;
return new AuthResult($code, $user['login'], $user['token_auth']);
}
protected function initNewBlankSession(SessionFingerprint $sessionFingerprint)
{
// this user should be using a different session, so generate a new ID
// NOTE: Zend_Session cannot be used since it will destroy the old
// session.
if ($this->shouldDestroySession) {
session_regenerate_id();
}
// regenerating the ID will create a new session w/ a new ID, but will
// copy over the existing session data. we want the new session for the
// unauthorized user to be different, so we clear the session fingerprint.
$sessionFingerprint->clear();
}
protected function destroyCurrentSession(SessionFingerprint $sessionFingerprint)
{
// Note: Piwik will attempt to create another session in the LoginController
// when rendering the login form (the nonce for the form is stored in the session).
// So we can't use Session::destroy() since Zend prohibits starting a new session
// after session_destroy() is called. Instead we clear the session fingerprint for
// the existing session and generate a new session. Both the old session &
// new session should have no stored data.
$sessionFingerprint->clear();
if ($this->shouldDestroySession) {
Session::regenerateId();
}
}
public function getTokenAuth()
{
return $this->user['token_auth'];
}
private function updateSessionExpireTime()
{
$sessionParams = session_get_cookie_params();
$sessionCookieLifetime = Config::getInstance()->General['login_cookie_expire'];
setcookie(session_name(), session_id(), time() + $sessionCookieLifetime, $sessionParams['path'],
$sessionParams['domain'], $sessionParams['secure'], $sessionParams['httponly']);
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Session;
use Piwik\Date;
/**
* Manages session information that is used to identify who the session
* is for.
*
* Once a session is authenticated using either a user name & password or
* token auth, some information about the user is stored in the session.
* This info includes the user name and the user agent
* string of the user's client, and a random session secret.
*
* In subsequent requests that use this session, we use the above information
* to verify that the session is allowed to be used by the person sending the
* request.
*
* This is accomplished by checking the request's user agent
* against what is stored in the session. If it doesn't then this is a
* session hijacking attempt.
*
* We also check that a hash in the piwik_auth cookie matches the hash
* of the time the user last changed their password + the session secret.
* If they don't match, the password has been changed since this session
* started, and is no longer valid.
*/
class SessionFingerprint
{
const USER_NAME_SESSION_VAR_NAME = 'user.name';
const SESSION_INFO_SESSION_VAR_NAME = 'session.info';
const SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED = 'twofactorauth.verified';
public function getUser()
{
if (isset($_SESSION[self::USER_NAME_SESSION_VAR_NAME])) {
return $_SESSION[self::USER_NAME_SESSION_VAR_NAME];
}
return null;
}
public function getUserInfo()
{
if (isset($_SESSION[self::SESSION_INFO_SESSION_VAR_NAME])) {
return $_SESSION[self::SESSION_INFO_SESSION_VAR_NAME];
}
return null;
}
public function hasVerifiedTwoFactor()
{
if (isset($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED])) {
return !empty($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED]);
}
return null;
}
public function setTwoFactorAuthenticationVerified()
{
$_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED] = 1;
}
public function initialize($userName, $isRemembered = false, $time = null)
{
$_SESSION[self::USER_NAME_SESSION_VAR_NAME] = $userName;
$_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED] = 0;
$_SESSION[self::SESSION_INFO_SESSION_VAR_NAME] = [
'ts' => $time ?: Date::now()->getTimestampUTC(),
'remembered' => $isRemembered,
];
}
public function clear()
{
unset($_SESSION[self::USER_NAME_SESSION_VAR_NAME]);
unset($_SESSION[self::SESSION_INFO_SESSION_VAR_NAME]);
unset($_SESSION[self::SESSION_INFO_TWO_FACTOR_AUTH_VERIFIED]);
}
public function getSessionStartTime()
{
$userInfo = $this->getUserInfo();
if (empty($userInfo)
|| empty($userInfo['ts'])
) {
return null;
}
return $userInfo['ts'];
}
public function isRemembered()
{
$userInfo = $this->getUserInfo();
return !empty($userInfo['remembered']);
}
}

View File

@ -0,0 +1,117 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Session;
use Exception;
use Piwik\Auth as AuthInterface;
use Piwik\AuthResult;
use Piwik\Piwik;
use Piwik\Session;
/**
* Initializes authenticated sessions using an Auth implementation.
*/
class SessionInitializer
{
/**
* Authenticates the user and, if successful, initializes an authenticated session.
*
* @param \Piwik\Auth $auth The Auth implementation to use.
* @throws Exception If authentication fails or the user is not allowed to login for some reason.
*/
public function initSession(AuthInterface $auth)
{
$this->regenerateSessionId();
$authResult = $this->doAuthenticateSession($auth);
if (!$authResult->wasAuthenticationSuccessful()) {
Piwik::postEvent('Login.authenticate.failed', array($auth->getLogin()));
$this->processFailedSession();
} else {
Piwik::postEvent('Login.authenticate.successful', array($auth->getLogin()));
$this->processSuccessfulSession($authResult);
}
}
/**
* Authenticates the user.
*
* Derived classes can override this method to customize authentication logic or impose
* extra requirements on the user trying to login.
*
* @param AuthInterface $auth The Auth implementation to use when authenticating.
* @return AuthResult
*/
protected function doAuthenticateSession(AuthInterface $auth)
{
Piwik::postEvent(
'Login.authenticate',
array(
$auth->getLogin(),
)
);
return $auth->authenticate();
}
/**
* Executed when the session could not authenticate.
*
* @throws Exception always.
*/
protected function processFailedSession()
{
throw new Exception(Piwik::translate('Login_LoginPasswordNotCorrect'));
}
/**
* Executed when the session was successfully authenticated.
*
* @param AuthResult $authResult The successful authentication result.
*/
protected function processSuccessfulSession(AuthResult $authResult)
{
$sessionIdentifier = new SessionFingerprint();
$sessionIdentifier->initialize($authResult->getIdentity(), $this->isRemembered());
/**
* @ignore
*/
Piwik::postEvent('Login.authenticate.processSuccessfulSession.end', array($authResult->getIdentity()));
}
protected function regenerateSessionId()
{
Session::regenerateId();
}
/**
* Accessor to compute the hashed authentication token.
*
* @param string $login user login
* @param string $token_auth authentication token
* @return string hashed authentication token
* @deprecated
*/
public static function getHashTokenAuth($login, $token_auth)
{
return md5($login . $token_auth);
}
private function isRemembered()
{
$cookieParams = session_get_cookie_params();
return $cookieParams['lifetime'] > 0;
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* Piwik - free/libre analytics platform
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Session;
use Piwik\Common;
use Piwik\Session;
use Zend_Session_Namespace;
/**
* Session namespace.
*
*/
class SessionNamespace extends Zend_Session_Namespace
{
/**
* @param string $namespace
* @param bool $singleInstance
*/
public function __construct($namespace = 'Default', $singleInstance = false)
{
if (Common::isPhpCliMode()) {
self::$_readable = true;
self::$_writable = true;
return;
}
Session::start();
parent::__construct($namespace, $singleInstance);
}
}