From 1ac09e7fe4a5408290d06116c6fb8152e018fe26 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 31 Dec 2013 02:59:07 +0100 Subject: Multi-utilisateur fonctionnel en HTTP Auth MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + Possibilité d'ajout / suppression d'utilisateur (seulement par l'administrateur) + Divers changements pour le mode multi-utilisateur https://github.com/marienfressinaud/FreshRSS/issues/126 + Minz : Renomme "sel_application" en "salt' --- app/Controllers/usersController.php | 132 ++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 app/Controllers/usersController.php (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php new file mode 100644 index 000000000..7d9568083 --- /dev/null +++ b/app/Controllers/usersController.php @@ -0,0 +1,132 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(Minz_Translate::t('access_denied'))) + ); + } + } + + public function idAction() { + if (Minz_Request::isPost()) { + $ok = true; + $mail = Minz_Request::param('mail_login', false); + $this->view->conf->_mail_login($mail); + $ok &= $this->view->conf->save(); + + Minz_Session::_param('mail', $this->view->conf->mail_login); + + //TODO: use $ok + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('configuration_updated') + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + } + + public function authAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $ok = true; + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + Minz_Session::_param('mail', $this->view->conf->mail_login); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType()) { + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_authType($auth_type); + $ok &= Minz_Configuration::writeFile(); + } + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'configuration_updated' : 'error_occurred') + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + + public function createAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + require_once(APP_PATH . '/sql.php'); + + $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); + if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { + $new_user_language = $this->view->conf->language; + } + + $new_user_name = Minz_Request::param('new_user_name'); + $ok = ctype_alnum($new_user_name); + + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + $ok &= Minz_Configuration::authType() !== 'persona'; + } + + if ($ok) { + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; + $ok &= !file_exists($configPath); + } + if ($ok) { + $config_array = array( + 'language' => $new_user_language, + 'mail_login' => $new_user_email, + ); + $ok &= (file_put_contents($configPath, "createUser($new_user_name); + } + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'user_created' : 'error_occurred', $new_user_name) + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } + + public function deleteAction() { + if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + require_once(APP_PATH . '/sql.php'); + + $username = Minz_Request::param('username'); + $ok = ctype_alnum($username); + + if ($ok) { + $ok &= ($username !== Minz_Configuration::defaultUser()); //It is forbidden to delete the default user + } + if ($ok) { + $configPath = DATA_PATH . '/' . $username . '_user.php'; + $ok &= file_exists($configPath); + } + if ($ok) { + $userDAO = new FreshRSS_UserDAO(); + $ok &= $userDAO->deleteUser($username); + $ok &= unlink($configPath); + } + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) + ); + Minz_Session::_param('notification', $notif); + } + Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); + } +} -- cgit v1.2.3 From 5c9a32329ad68dc5ae8bc8a3566a0d603b80a934 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 31 Dec 2013 14:52:01 +0100 Subject: Multi-utilisateur fonctionnel avec Mozilla Persona MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Il faut ré-enregistrer l'adresse courriel une fois dans l'interface de FreshRSS pour créer le fichier nécessaire. + Comparaison sans tenir compte de la casse pour les noms d'utilisateur. Contribue à https://github.com/marienfressinaud/FreshRSS/issues/126 ll faudra tester la sécurité --- app/Controllers/indexController.php | 32 +++++++++++++++++++++++++++++--- app/Controllers/usersController.php | 37 ++++++++++++++++++++++++++----------- app/FreshRSS.php | 18 ++++++++++++++---- data/cache/index.html | 13 +++++++++++++ data/favicons/index.html | 13 +++++++++++++ data/log/index.html | 13 +++++++++++++ data/persona/.gitignore | 1 + data/persona/index.html | 13 +++++++++++++ p/i/install.php | 6 ++++++ 9 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 data/cache/index.html create mode 100644 data/favicons/index.html create mode 100644 data/log/index.html create mode 100644 data/persona/.gitignore create mode 100644 data/persona/index.html (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 7309169a6..5b51b3e28 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -249,14 +249,40 @@ class FreshRSS_index_Controller extends Minz_ActionController { curl_close ($ch); $res = json_decode ($result, true); - if ($res['status'] === 'okay' && $res['email'] === $this->view->conf->mail_login) { - Minz_Session::_param ('mail', $res['email']); + + $loginOk = false; + $reason = ''; + if ($res['status'] === 'okay') { + $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + if (($currentUser = @file_get_contents($personaFile)) !== false) { + $currentUser = trim($currentUser); + if (ctype_alnum($currentUser)) { + try { + $this->conf = new FreshRSS_Configuration($currentUser); + $loginOk = strcasecmp($email, $this->conf->mail_login) === 0; + } catch (Minz_Exception $e) { + $reason = 'Invalid configuration for user [' . $currentUser . ']! ' . $e->getMessage(); //Permission denied or conf file does not exist + } + } else { + $reason = 'Invalid username format [' . $currentUser . ']!'; + } + } + } else { + $reason = 'Invalid email format [' . $res['email'] . ']!'; + } + } + if ($loginOk) { + Minz_Session::_param('currentUser', $currentUser); + Minz_Session::_param ('mail', $email); $this->view->loginOk = true; invalidateHttpCache(); } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = Minz_Translate::t ('invalid_login'); + $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } header('Content-Type: application/json; charset=UTF-8'); diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 7d9568083..5b3ffe81a 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -17,7 +17,14 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); + $email = $this->view->conf->mail_login; + Minz_Session::_param('mail', $email); + + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); + } //TODO: use $ok $notif = array( @@ -38,8 +45,6 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_token($token); $ok &= $this->view->conf->save(); - Minz_Session::_param('mail', $this->view->conf->mail_login); - $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); @@ -69,18 +74,27 @@ class FreshRSS_users_Controller extends Minz_ActionController { } $new_user_name = Minz_Request::param('new_user_name'); - $ok = ctype_alnum($new_user_name); - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - $ok &= Minz_Configuration::authType() !== 'persona'; - } + $ok = ($new_user_name != '') && ctype_alnum($new_user_name); if ($ok) { + $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user + + $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; $ok &= !file_exists($configPath); } + if ($ok) { + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + $ok &= Minz_Configuration::authType() !== 'persona'; + } else { + $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, $new_user_name) !== false); + } + } if ($ok) { $config_array = array( 'language' => $new_user_language, @@ -110,7 +124,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok = ctype_alnum($username); if ($ok) { - $ok &= ($username !== Minz_Configuration::defaultUser()); //It is forbidden to delete the default user + $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user } if ($ok) { $configPath = DATA_PATH . '/' . $username . '_user.php'; @@ -120,6 +134,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->deleteUser($username); $ok &= unlink($configPath); + //TODO: delete Persona file } $notif = array( 'type' => $ok ? 'good' : 'bad', diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 0e166cc3b..0af0c01da 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -18,8 +18,18 @@ class FreshRSS extends Minz_FrontController { $loginOk = $currentUser != ''; break; case 'persona': - $currentUser = Minz_Configuration::defaultUser(); //TODO: Make Persona compatible with multi-user - $loginOk = Minz_Session::param('mail') != ''; + $loginOk = false; + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + if ($email != '') { //TODO: Remove redundancy with indexController + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + if (($currentUser = @file_get_contents($personaFile)) !== false) { + $currentUser = trim($currentUser); + $loginOk = true; + } + } + if (!$loginOk) { + $currentUser = Minz_Configuration::defaultUser(); + } break; case 'none': $currentUser = Minz_Configuration::defaultUser(); @@ -51,10 +61,10 @@ class FreshRSS extends Minz_FrontController { if ($loginOk) { switch (Minz_Configuration::authType()) { case 'http_auth': - $loginOk = $currentUser === httpAuthUser(); + $loginOk = strcasecmp($currentUser, httpAuthUser()) === 0; break; case 'persona': - $loginOk = Minz_Session::param('mail') === $this->conf->mail_login; + $loginOk = strcasecmp(Minz_Session::param('mail'), $this->conf->mail_login) === 0; break; case 'none': $loginOk = true; diff --git a/data/cache/index.html b/data/cache/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/cache/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/favicons/index.html b/data/favicons/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/favicons/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/log/index.html b/data/log/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/log/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/data/persona/.gitignore b/data/persona/.gitignore new file mode 100644 index 000000000..314f02b1b --- /dev/null +++ b/data/persona/.gitignore @@ -0,0 +1 @@ +*.txt \ No newline at end of file diff --git a/data/persona/index.html b/data/persona/index.html new file mode 100644 index 000000000..85faaa37e --- /dev/null +++ b/data/persona/index.html @@ -0,0 +1,13 @@ + + + + + +Redirection + + + + +

Redirection

+ + diff --git a/p/i/install.php b/p/i/install.php index e953cf699..0cd952fef 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -178,6 +178,12 @@ function saveStep2 () { @unlink($configPath); //To avoid access-rights problems file_put_contents($configPath, " Date: Tue, 31 Dec 2013 15:21:39 +0100 Subject: Ajouts de quelques invalidateHttpCache --- app/Controllers/configureController.php | 7 +++++++ app/Controllers/usersController.php | 5 +++++ 2 files changed, 12 insertions(+) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 17abf6b89..0e4801a2d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -50,6 +50,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $catDAO->addCategory ($values); } } + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -124,6 +125,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'content' => Minz_Translate::t ('error_occurred_update') ); } + invalidateHttpCache(); Minz_Session::_param ('notification', $notif); Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array ('id' => $id)), true); @@ -168,6 +170,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Session::_param ('language', $this->view->conf->language); Minz_Translate::reset (); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -196,6 +199,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'print' => Minz_Request::param ('print', false), )); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -235,6 +239,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->categories = $list; } elseif ($this->view->req == 'import' && Minz_Request::isPost ()) { if ($_FILES['file']['error'] == 0) { + invalidateHttpCache(); // on parse le fichier OPML pour récupérer les catégories et les flux associés try { list ($categories, $feeds) = opml_import ( @@ -295,6 +300,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_shortcuts ($shortcuts_ok); $this->view->conf->save(); + invalidateHttpCache(); $notif = array ( 'type' => 'good', @@ -320,6 +326,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_old_entries($old); $this->view->conf->_keep_history_default($keepHistoryDefault); $this->view->conf->save(); + invalidateHttpCache(); $notif = array( 'type' => 'good', diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 5b3ffe81a..0ce3b3447 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -25,6 +25,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } + invalidateHttpCache(); //TODO: use $ok $notif = array( @@ -54,6 +55,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { Minz_Configuration::_authType($auth_type); $ok &= Minz_Configuration::writeFile(); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -106,6 +108,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->createUser($new_user_name); } + invalidateHttpCache(); $notif = array( 'type' => $ok ? 'good' : 'bad', @@ -136,6 +139,8 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok &= unlink($configPath); //TODO: delete Persona file } + invalidateHttpCache(); + $notif = array( 'type' => $ok ? 'good' : 'bad', 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) -- cgit v1.2.3 From 50c41d9bb2b1766feac984685bb2a954ab4799f3 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 1 Jan 2014 13:48:32 +0100 Subject: Détails multi-utilisateur MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/126 --- app/Controllers/usersController.php | 47 ++++++++++++++----------------------- app/views/configure/archiving.phtml | 4 ++-- app/views/configure/feed.phtml | 4 ++-- app/views/configure/users.phtml | 9 ++++--- p/themes/default/global.css | 2 +- p/themes/flat-design/global.css | 2 +- 6 files changed, 28 insertions(+), 40 deletions(-) (limited to 'app/Controllers/usersController.php') diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 0ce3b3447..482e35c3e 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -10,9 +10,10 @@ class FreshRSS_users_Controller extends Minz_ActionController { } } - public function idAction() { + public function authAction() { if (Minz_Request::isPost()) { $ok = true; + $mail = Minz_Request::param('mail_login', false); $this->view->conf->_mail_login($mail); $ok &= $this->view->conf->save(); @@ -25,36 +26,24 @@ class FreshRSS_users_Controller extends Minz_ActionController { @unlink($personaFile); $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } - invalidateHttpCache(); - //TODO: use $ok - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'users'), true); - } - } - - public function authAction() { - if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { - $ok = true; - $current_token = $this->view->conf->token; - $token = Minz_Request::param('token', $current_token); - $this->view->conf->_token($token); - $ok &= $this->view->conf->save(); - - $anon = Minz_Request::param('anon_access', false); - $anon = ((bool)$anon) && ($anon !== 'no'); - $auth_type = Minz_Request::param('auth_type', 'none'); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType()) { - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_authType($auth_type); - $ok &= Minz_Configuration::writeFile(); + if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType()) { + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_authType($auth_type); + $ok &= Minz_Configuration::writeFile(); + } } + invalidateHttpCache(); $notif = array( diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index cbe3b086c..6e26ca81e 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -17,8 +17,8 @@
- '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> () diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index e738ab64f..a0fe39f8a 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -87,8 +87,8 @@
- '', -2 => Minz_Translate::t('by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', -1 => '∞') as $v => $t) { echo ''; } ?> diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 223f81e8d..d40a3ad5b 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -3,7 +3,7 @@
-
+
@@ -34,20 +34,19 @@
- -
- + - + $_SERVER['REMOTE_USER'] = ``
diff --git a/p/themes/default/global.css b/p/themes/default/global.css index 913da4b27..2cc195f90 100644 --- a/p/themes/default/global.css +++ b/p/themes/default/global.css @@ -112,7 +112,7 @@ input, select, textarea { border-color: #33BBFF; box-shadow: 0 2px 2px #DDDDFF inset; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } diff --git a/p/themes/flat-design/global.css b/p/themes/flat-design/global.css index cb9495865..c24a9f481 100644 --- a/p/themes/flat-design/global.css +++ b/p/themes/flat-design/global.css @@ -113,7 +113,7 @@ input, select, textarea { color: #333; border-color: #2980b9; } - input:invalid { + input:invalid, select:invalid { border-color: red; box-shadow: 0 0 2px 1px red; } -- cgit v1.2.3