From 1f51d663a0d651cfc8ff172357ce1b57823f8480 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 3 Feb 2010 08:18:53 -0800 Subject: Correct missing function name. --- modules/gallery/helpers/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery/helpers/auth.php') diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index 717cf40a..45561861 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -102,7 +102,7 @@ class auth_Core { /** * Clear any failed logins for this user */ - static function clear_failed_logins($user) { + static function clear_failed_auth_attempts($user) { db::build() ->delete("failed_logins") ->where("name", "=", $user->name) -- cgit v1.2.3 From aff5d1cef4cc2514fe6d714788fffcf418d8fc5b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 7 Feb 2010 08:45:10 -0800 Subject: Create the concept of a "failed authentication" as semantically separate from a successful or failed login. 1) Rename user_login_failed event to user_authenticate_failed 2) Rename failed_logins table to failed_auth (bump Gallery module to v27 to rename the table) 3) auth::too_many_failed_logins -> auth::too_many_failures 4) auth::record_failed_auth_attempts -> auth::record_failed_attempts auth::clear_failed_auth_attempts -> auth::clear_failed_attempts --- modules/gallery/controllers/login.php | 2 +- modules/gallery/helpers/auth.php | 41 +++++++++++++-------------- modules/gallery/helpers/gallery_event.php | 14 ++++----- modules/gallery/helpers/gallery_installer.php | 9 ++++-- modules/gallery/models/failed_auth.php | 20 +++++++++++++ modules/gallery/models/failed_login.php | 20 ------------- modules/gallery/module.info | 2 +- modules/rest/controllers/rest.php | 2 +- modules/user/controllers/users.php | 7 +++-- 9 files changed, 59 insertions(+), 58 deletions(-) create mode 100644 modules/gallery/models/failed_auth.php delete mode 100644 modules/gallery/models/failed_login.php (limited to 'modules/gallery/helpers/auth.php') diff --git a/modules/gallery/controllers/login.php b/modules/gallery/controllers/login.php index 1426f0d8..fa175ac8 100644 --- a/modules/gallery/controllers/login.php +++ b/modules/gallery/controllers/login.php @@ -65,7 +65,7 @@ class Login_Controller extends Controller { $form->login->inputs["name"]->add_error("invalid_login", 1); $name = $form->login->inputs["name"]->value; log::warning("user", t("Failed login for %name", array("name" => $name))); - module::event("user_login_failed", $name); + module::event("user_authenticate_failed", $name); $valid = false; } } diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index 45561861..2c1e3f67 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -20,7 +20,7 @@ class auth_Core { static function get_login_form($url) { $form = new Forge($url, "", "post", array("id" => "g-login-form")); - $form->set_attr('class', "g-narrow"); + $form->set_attr("class", "g-narrow"); $group = $form->group("login")->label(t("Login")); $group->input("name")->label(t("Username"))->id("g-username")->class(null) ->callback("auth::validate_too_many_failed_logins") @@ -60,52 +60,51 @@ class auth_Core { } /** - * After there have been 5 failed login attempts, any failure leads to getting locked out for a + * After there have been 5 failed auth attempts, any failure leads to getting locked out for a * minute. */ - static function too_many_failed_logins($name) { - $failed_login = ORM::factory("failed_login") + static function too_many_failures($name) { + $failed = ORM::factory("failed_auth") ->where("name", "=", $name) ->find(); - return ($failed_login->loaded() && - $failed_login->count > 5 && - (time() - $failed_login->time < 60)); + return ($failed->loaded() && + $failed->count > 5 && + (time() - $failed->time < 60)); } static function validate_too_many_failed_logins($name_input) { - if (self::too_many_failed_logins($name_input->value)) { + if (self::too_many_failures($name_input->value)) { $name_input->add_error("too_many_failed_logins", 1); } } static function validate_too_many_failed_password_changes($password_input) { - if (self::too_many_failed_logins(identity::active_user()->name)) { + if (self::too_many_failures(identity::active_user()->name)) { $password_input->add_error("too_many_failed_password_changes", 1); } } /** - * Record a failed login for this user + * Record a failed authentication for this user */ - static function record_failed_auth_attempts($name) { - $failed_login = ORM::factory("failed_login") + static function record_failed_attempt($name) { + $failed = ORM::factory("failed_auth") ->where("name", "=", $name) ->find(); - if (!$failed_login->loaded()) { - $failed_login->name = $name; + if (!$failed->loaded()) { + $failed->name = $name; } - $failed_login->time = time(); - $failed_login->count++; - $failed_login->save(); + $failed->time = time(); + $failed->count++; + $failed->save(); } /** * Clear any failed logins for this user */ - static function clear_failed_auth_attempts($user) { - db::build() - ->delete("failed_logins") + static function clear_failed_attempts($user) { + ORM::factory("failed_auth") ->where("name", "=", $user->name) - ->execute(); + ->delete_all(); } } \ No newline at end of file diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 7b538c49..9ce30929 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -110,19 +110,15 @@ class gallery_event_Core { graphics::choose_default_toolkit(); module::clear_var("gallery", "choose_default_tookit"); } - auth::clear_failed_auth_attempts($user); + auth::clear_failed_attempts($user); } - static function user_login_failed($name) { - auth::record_failed_auth_attempts($name); + static function user_authenticate_failed($name) { + auth::record_failed_attempt($name); } - static function user_password_changed($user) { - auth::clear_failed_auth_attempts($user); - } - - static function user_password_change_failed($name) { - auth::record_failed_auth_attempts($name); + static function user_authenticate($user) { + auth::clear_failed_attempts($user); } static function item_index_data($item, $data) { diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index 761843b0..05354f81 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -42,7 +42,7 @@ class gallery_installer { KEY (`tags`)) DEFAULT CHARSET=utf8;"); - $db->query("CREATE TABLE {failed_logins} ( + $db->query("CREATE TABLE {failed_auth} ( `id` int(9) NOT NULL auto_increment, `count` int(9) NOT NULL, `name` varchar(255) NOT NULL, @@ -526,6 +526,11 @@ class gallery_installer { ->execute(); module::set_version("gallery", $version = 26); } + + if ($version == 26) { + $db->query("RENAME TABLE {failed_logins} TO {failed_auths}"); + module::set_version("gallery", $version = 27); + } } static function uninstall() { @@ -534,7 +539,7 @@ class gallery_installer { $db->query("DROP TABLE IF EXISTS {access_intents}"); $db->query("DROP TABLE IF EXISTS {graphics_rules}"); $db->query("DROP TABLE IF EXISTS {incoming_translations}"); - $db->query("DROP TABLE IF EXISTS {failed_logins}"); + $db->query("DROP TABLE IF EXISTS {failed_auths}"); $db->query("DROP TABLE IF EXISTS {items}"); $db->query("DROP TABLE IF EXISTS {logs}"); $db->query("DROP TABLE IF EXISTS {modules}"); diff --git a/modules/gallery/models/failed_auth.php b/modules/gallery/models/failed_auth.php new file mode 100644 index 00000000..3c25f9d8 --- /dev/null +++ b/modules/gallery/models/failed_auth.php @@ -0,0 +1,20 @@ +post("user"); $password = Input::instance()->post("password"); - if (empty($username) || auth::too_many_failed_logins($username)) { + if (empty($username) || auth::too_many_failures($username)) { throw new Rest_Exception("Forbidden", 403); } diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index 83adc354..2675d918 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -84,6 +84,7 @@ class Users_Controller extends Controller { $user->save(); module::event("user_change_password_form_completed", $user, $form); message::success(t("Password changed")); + module::event("user_authenticate", $user); module::event("user_password_change", $user); print json_encode( array("result" => "success", @@ -91,7 +92,7 @@ class Users_Controller extends Controller { } else { log::warning("user", t("Failed password change for %name", array("name" => $user->name))); $name = $user->name; - module::event("user_password_change_failed", $name); + module::event("user_authenticate_failed", $name); print json_encode(array("result" => "error", "form" => (string) $form)); } } @@ -119,14 +120,14 @@ class Users_Controller extends Controller { $user->save(); module::event("user_change_email_form_completed", $user, $form); message::success(t("Email address changed")); - module::event("user_login", $user); // since there's no user_authenticated event + module::event("user_authenticate", $user); print json_encode( array("result" => "success", "resource" => url::site("users/{$user->id}"))); } else { log::warning("user", t("Failed email change for %name", array("name" => $user->name))); $name = $user->name; - module::event("user_login_failed", $name); + module::event("user_authenticate_failed", $name); print json_encode(array("result" => "error", "form" => (string) $form)); } } -- cgit v1.2.3 From f93528ffab19b7a733fc8fb21c22853d8ec0d2f5 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Sun, 7 Feb 2010 15:37:32 -0800 Subject: Last partial fix for ticket 585: Compartmentalize the admin area and require active authentication every 20 minutes to access the admin area. Also renaming auth::validate_too_many_failed_password_changes to validate_too_many_failed_auth_attempts since it's used in this generalized way in 3 places now. --- modules/gallery/controllers/admin.php | 6 ++- modules/gallery/controllers/reauthenticate.php | 72 ++++++++++++++++++++++++++ modules/gallery/helpers/auth.php | 27 +++++++++- modules/gallery/helpers/gallery_event.php | 2 + modules/gallery/views/reauthenticate.html.php | 10 ++++ modules/user/controllers/users.php | 8 +-- 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 modules/gallery/controllers/reauthenticate.php create mode 100644 modules/gallery/views/reauthenticate.html.php (limited to 'modules/gallery/helpers/auth.php') diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php index e4216991..b5f3db39 100644 --- a/modules/gallery/controllers/admin.php +++ b/modules/gallery/controllers/admin.php @@ -21,7 +21,7 @@ class Admin_Controller extends Controller { private $theme; public function __construct($theme=null) { - if (!(identity::active_user()->admin)) { + if (!identity::active_user()->admin) { access::forbidden(); } @@ -29,6 +29,10 @@ class Admin_Controller extends Controller { } public function __call($controller_name, $args) { + if (auth::must_reauth_for_admin_area()) { + return url::redirect("reauthenticate"); + } + if (request::method() == "post") { access::verify_csrf(); } diff --git a/modules/gallery/controllers/reauthenticate.php b/modules/gallery/controllers/reauthenticate.php new file mode 100644 index 00000000..4b88a9cc --- /dev/null +++ b/modules/gallery/controllers/reauthenticate.php @@ -0,0 +1,72 @@ +admin) { + access::forbidden(); + } + return self::_show_form(self::_form()); + } + + public function auth() { + if (!identity::active_user()->admin) { + access::forbidden(); + } + access::verify_csrf(); + + $form = self::_form(); + $valid = $form->validate(); + $user = identity::active_user(); + if ($valid) { + message::success(t("Successfully re-authenticated!")); + module::event("user_auth", $user); + url::redirect("admin"); + } else { + $name = $user->name; + log::warning("user", t("Failed re-authentication for %name", array("name" => $name))); + module::event("user_auth_failed", $name); + return self::_show_form($form); + } + } + + private static function _show_form($form) { + $view = new Theme_View("page.html", "other", "reauthenticate"); + $view->page_title = t("Re-authenticate"); + $view->content = new View("reauthenticate.html"); + $view->content->form = $form; + $view->content->user_name = identity::active_user()->name; + print $view; + } + + private static function _form() { + $form = new Forge("reauthenticate/auth", "", "post", array("id" => "g-reauthenticate-form")); + $form->set_attr('class', "g-narrow"); + $group = $form->group("reauthenticate")->label(t("Re-authenticate")); + $group->password("password")->label(t("Password"))->id("g-password")->class(null) + ->callback("auth::validate_too_many_failed_auth_attempts") + ->callback("user::valid_password") + ->error_messages("invalid", t("Incorrect password")) + ->error_messages( + "too_many_failed_auth_attempts", + t("Too many incorrect passwords. Try again later")); + $group->submit("")->value(t("Submit")); + return $form; + } +} diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index 2c1e3f67..c3e9e6e9 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -78,9 +78,9 @@ class auth_Core { } } - static function validate_too_many_failed_password_changes($password_input) { + static function validate_too_many_failed_auth_attempts($form_input) { if (self::too_many_failures(identity::active_user()->name)) { - $password_input->add_error("too_many_failed_password_changes", 1); + $form_input->add_error("too_many_failed_auth_attempts", 1); } } @@ -107,4 +107,27 @@ class auth_Core { ->where("name", "=", $user->name) ->delete_all(); } + + /** + * Checks whether the current user (= admin) must + * actively re-authenticate before access is given + * to the admin area. + */ + static function must_reauth_for_admin_area() { + if (!identity::active_user()->admin) { + access::forbidden(); + } + + $session = Session::instance(); + $last_active_auth = $session->get("active_auth_timestamp", 0); + $last_admin_area_activity = $session->get("admin_area_activity_timestamp", 0); + $admin_area_timeout = module::get_var("gallery", "admin_area_timeout"); + + if (max($last_active_auth, $last_admin_area_activity) + $admin_area_timeout < time()) { + return true; + } + + $session->set("admin_area_activity_timestamp", time()); + return false; + } } \ No newline at end of file diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 5fa82160..63f33c12 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -110,6 +110,7 @@ class gallery_event_Core { graphics::choose_default_toolkit(); module::clear_var("gallery", "choose_default_tookit"); } + Session::instance()->set("active_auth_timestamp", time()); auth::clear_failed_attempts($user); } @@ -119,6 +120,7 @@ class gallery_event_Core { static function user_auth($user) { auth::clear_failed_attempts($user); + Session::instance()->set("active_auth_timestamp", time()); } static function item_index_data($item, $data) { diff --git a/modules/gallery/views/reauthenticate.html.php b/modules/gallery/views/reauthenticate.html.php new file mode 100644 index 00000000..8611d0f7 --- /dev/null +++ b/modules/gallery/views/reauthenticate.html.php @@ -0,0 +1,10 @@ + +
+

+ +

+

+ $user_name)) ?> +

+ +
\ No newline at end of file diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index 1130852b..0730f391 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -164,11 +164,11 @@ class Users_Controller extends Controller { "users/change_password/$user->id", "", "post", array("id" => "g-change-password-user-form")); $group = $form->group("change_password")->label(t("Change your password")); $group->password("old_password")->label(t("Old password"))->id("g-password") - ->callback("auth::validate_too_many_failed_password_changes") + ->callback("auth::validate_too_many_failed_auth_attempts") ->callback("user::valid_password") ->error_messages("invalid", t("Incorrect password")) ->error_messages( - "too_many_failed_password_changes", + "too_many_failed_auth_attempts", t("Too many incorrect passwords. Try again later")); $group->password("password")->label(t("New password"))->id("g-password") ->error_messages("min_length", t("Your new password is too short")); @@ -189,11 +189,11 @@ class Users_Controller extends Controller { "users/change_email/$user->id", "", "post", array("id" => "g-change-email-user-form")); $group = $form->group("change_email")->label(t("Change your email address")); $group->password("password")->label(t("Current password"))->id("g-password") - ->callback("auth::validate_too_many_failed_password_changes") + ->callback("auth::validate_too_many_failed_auth_attempts") ->callback("user::valid_password") ->error_messages("invalid", t("Incorrect password")) ->error_messages( - "too_many_failed_password_changes", + "too_many_failed_auth_attempts", t("Too many incorrect passwords. Try again later")); $group->input("email")->label(t("New email address"))->id("g-email")->value($user->email) ->error_messages("email", t("You must enter a valid email address")) -- cgit v1.2.3 From 8ef08d20883d9b9aa0b7560ce3bf6da8a6632149 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 10 Feb 2010 08:53:39 -0800 Subject: Refactor the code to display the login page if the user does not have view permission into the common auth::require_login() method. --- modules/gallery/controllers/albums.php | 8 +------- modules/gallery/controllers/movies.php | 7 +------ modules/gallery/controllers/photos.php | 6 +----- modules/gallery/helpers/auth.php | 13 +++++++++++++ 4 files changed, 16 insertions(+), 18 deletions(-) (limited to 'modules/gallery/helpers/auth.php') diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index 1d369b95..e1985cfb 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -30,13 +30,7 @@ class Albums_Controller extends Items_Controller { } if (!access::can("view", $album)) { - $view = new Theme_View("page.html", "other", "login"); - $view->page_title = t("Log in to Gallery"); - $view->content = new View("login_ajax.html"); - $view->content->form = auth::get_login_form("login/auth_html"); - // Avoid anti-phishing protection by passing the url as session variable. - Session::instance()->set("continue_url", url::current(true)); - print $view; + print auth::require_login(); return; } diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index 9e882ef4..8041066e 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -26,12 +26,7 @@ class Movies_Controller extends Items_Controller { } if (!access::can("view", $movie)) { - $view = new Theme_View("page.html", "other", "login"); - $view->page_title = t("Log in to Gallery"); - $view->content = new View("login_ajax.html"); - $view->content->form = auth::get_login_form("login/auth_html"); - - print $view; + print auth::require_login(); return; } diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 8beae207..778e9ae7 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -26,11 +26,7 @@ class Photos_Controller extends Items_Controller { } if (!access::can("view", $photo)) { - $view = new Theme_View("page.html", "other", "login"); - $view->page_title = t("Log in to Gallery"); - $view->content = new View("login_ajax.html"); - $view->content->form = auth::get_login_form("login/auth_html"); - print $view; + print auth::require_login(); return; } diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index c3e9e6e9..f5454f85 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -130,4 +130,17 @@ class auth_Core { $session->set("admin_area_activity_timestamp", time()); return false; } + + /** + * Redirect to the login page. + */ + static function require_login() { + $view = new Theme_View("page.html", "other", "login"); + $view->page_title = t("Log in to Gallery"); + $view->content = new View("login_ajax.html"); + $view->content->form = auth::get_login_form("login/auth_html"); + // Avoid anti-phishing protection by passing the url as session variable. + Session::instance()->set("continue_url", url::current(true)); + return $view; + } } \ No newline at end of file -- cgit v1.2.3