Patch by Holger Just and Go MAEDA. git-svn-id: http://svn.redmine.org/redmine/trunk@14264 e93f8b46-1217-0410-a6f0-8f06a7374b81tags/3.1.0
@@ -204,6 +204,7 @@ class ApplicationController < ActionController::Base | |||
def check_password_change | |||
if session[:pwd] | |||
if User.current.must_change_password? | |||
flash[:error] = l(:error_password_expired) | |||
redirect_to my_password_path | |||
else | |||
session.delete(:pwd) |
@@ -323,8 +323,19 @@ class User < Principal | |||
return auth_source.allow_password_changes? | |||
end | |||
def password_expired? | |||
changed_on = self.passwd_changed_on || Time.at(0) | |||
period = Setting.password_max_age.to_i | |||
if period.zero? | |||
false | |||
else | |||
changed_on < period.days.ago | |||
end | |||
end | |||
def must_change_password? | |||
must_change_passwd? && change_password_allowed? | |||
(must_change_passwd? || password_expired?) && change_password_allowed? | |||
end | |||
def generate_password? |
@@ -17,7 +17,7 @@ | |||
<%= submit_tag l(:button_apply) %> | |||
<% end %> | |||
<% unless @user.must_change_passwd? %> | |||
<% unless @user.must_change_passwd? || @user.password_expired? %> | |||
<% content_for :sidebar do %> | |||
<%= render :partial => 'sidebar' %> | |||
<% end %> |
@@ -14,6 +14,10 @@ | |||
<p><%= setting_text_field :password_min_length, :size => 6 %></p> | |||
<p> | |||
<%= setting_select :password_max_age, [[l(:label_disabled), 0]] + [7, 30, 60, 90, 180, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]} %> | |||
</p> | |||
<p><%= setting_check_box :lost_password, :label => :label_password_lost %></p> | |||
<p><%= setting_text_field :max_additional_emails, :size => 6 %></p> |
@@ -1026,6 +1026,7 @@ de: | |||
setting_non_working_week_days: Arbeitsfreie Tage | |||
setting_openid: Erlaube OpenID-Anmeldung und -Registrierung | |||
setting_password_min_length: Mindestlänge des Kennworts | |||
setting_password_max_age: Erzwinge Passwortwechsel nach | |||
setting_per_page_options: Objekte pro Seite | |||
setting_plain_text_mail: Nur reinen Text (kein HTML) senden | |||
setting_protocol: Protokoll |
@@ -204,6 +204,7 @@ en: | |||
error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})" | |||
error_session_expired: "Your session has expired. Please login again." | |||
warning_attachments_not_saved: "%{count} file(s) could not be saved." | |||
error_password_expired: "Your password has expired or the administrator requires you to change it." | |||
mail_subject_lost_password: "Your %{value} password" | |||
mail_body_lost_password: 'To change your password, click on the following link:' | |||
@@ -386,6 +387,7 @@ en: | |||
setting_file_max_size_displayed: Maximum size of text files displayed inline | |||
setting_repository_log_display_limit: Maximum number of revisions displayed on file log | |||
setting_openid: Allow OpenID login and registration | |||
setting_password_max_age: Require password change after | |||
setting_password_min_length: Minimum password length | |||
setting_new_project_user_role_id: Role given to a non-admin user who creates a project | |||
setting_default_projects_modules: Default enabled modules for new projects |
@@ -224,6 +224,7 @@ fr: | |||
error_attachment_too_big: Ce fichier ne peut pas être attaché car il excède la taille maximale autorisée (%{max_size}) | |||
error_session_expired: "Votre session a expiré. Veuillez vous reconnecter." | |||
warning_attachments_not_saved: "%{count} fichier(s) n'ont pas pu être sauvegardés." | |||
error_password_expired: "Votre mot de passe a expiré ou nécessite d'être changé." | |||
mail_subject_lost_password: "Votre mot de passe %{value}" | |||
mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :' | |||
@@ -406,6 +407,7 @@ fr: | |||
setting_file_max_size_displayed: Taille maximum des fichiers texte affichés en ligne | |||
setting_repository_log_display_limit: "Nombre maximum de révisions affichées sur l'historique d'un fichier" | |||
setting_openid: "Autoriser l'authentification et l'enregistrement OpenID" | |||
setting_password_max_age: Expiration des mots de passe après | |||
setting_password_min_length: Longueur minimum des mots de passe | |||
setting_new_project_user_role_id: Rôle donné à un utilisateur non-administrateur qui crée un projet | |||
setting_default_projects_modules: Modules activés par défaut pour les nouveaux projets |
@@ -36,6 +36,10 @@ unsubscribe: | |||
password_min_length: | |||
format: int | |||
default: 8 | |||
# Maximum password age in days | |||
password_max_age: | |||
format: int | |||
default: 0 | |||
# Maximum number of additional email addresses per user | |||
max_additional_emails: | |||
format: int |
@@ -150,6 +150,40 @@ class AccountTest < Redmine::IntegrationTest | |||
assert_equal false, User.find_by_login('jsmith').must_change_passwd? | |||
end | |||
def test_user_with_expired_password_should_be_forced_to_change_its_password | |||
User.find_by_login('jsmith').update_attribute :passwd_changed_on, 14.days.ago | |||
with_settings :password_max_age => 7 do | |||
post '/login', :username => 'jsmith', :password => 'jsmith' | |||
assert_redirected_to '/my/page' | |||
follow_redirect! | |||
assert_redirected_to '/my/password' | |||
get '/issues' | |||
assert_redirected_to '/my/password' | |||
end | |||
end | |||
def test_user_with_expired_password_should_be_able_to_change_its_password | |||
User.find_by_login('jsmith').update_attribute :passwd_changed_on, 14.days.ago | |||
with_settings :password_max_age => 7 do | |||
post '/login', :username => 'jsmith', :password => 'jsmith' | |||
assert_redirected_to '/my/page' | |||
follow_redirect! | |||
assert_redirected_to '/my/password' | |||
follow_redirect! | |||
assert_response :success | |||
post '/my/password', :password => 'jsmith', :new_password => 'newpassword', :new_password_confirmation => 'newpassword' | |||
assert_redirected_to '/my/account' | |||
follow_redirect! | |||
assert_response :success | |||
assert_equal false, User.find_by_login('jsmith').must_change_passwd? | |||
end | |||
end | |||
def test_register_with_automatic_activation | |||
Setting.self_registration = '3' | |||