##// END OF EJS Templates
Option to force a user to change his password (#3872)....
Jean-Philippe Lang -
r11851:b764e398475c
parent child
Show More
@@ -0,0 +1,9
1 class AddUsersMustChangePasswd < ActiveRecord::Migration
2 def up
3 add_column :users, :must_change_passwd, :boolean, :default => false, :null => false
4 end
5
6 def down
7 remove_column :users, :must_change_passwd
8 end
9 end
@@ -20,7 +20,7 class AccountController < ApplicationController
20 include CustomFieldsHelper
20 include CustomFieldsHelper
21
21
22 # prevents login action to be filtered by check_if_login_required application scope filter
22 # prevents login action to be filtered by check_if_login_required application scope filter
23 skip_before_filter :check_if_login_required
23 skip_before_filter :check_if_login_required, :check_password_change
24
24
25 # Login request and validation
25 # Login request and validation
26 def login
26 def login
@@ -38,7 +38,7 class ApplicationController < ActionController::Base
38 cookies.delete(autologin_cookie_name)
38 cookies.delete(autologin_cookie_name)
39 end
39 end
40
40
41 before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
41 before_filter :session_expiration, :user_setup, :check_if_login_required, :check_password_change, :set_localization
42
42
43 rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
43 rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
44 rescue_from ::Unauthorized, :with => :deny_access
44 rescue_from ::Unauthorized, :with => :deny_access
@@ -78,6 +78,9 class ApplicationController < ActionController::Base
78 session[:user_id] = user.id
78 session[:user_id] = user.id
79 session[:ctime] = Time.now.utc.to_i
79 session[:ctime] = Time.now.utc.to_i
80 session[:atime] = Time.now.utc.to_i
80 session[:atime] = Time.now.utc.to_i
81 if user.must_change_password?
82 session[:pwd] = '1'
83 end
81 end
84 end
82
85
83 def user_setup
86 def user_setup
@@ -112,6 +115,10 class ApplicationController < ActionController::Base
112 authenticate_with_http_basic do |username, password|
115 authenticate_with_http_basic do |username, password|
113 user = User.try_to_login(username, password) || User.find_by_api_key(username)
116 user = User.try_to_login(username, password) || User.find_by_api_key(username)
114 end
117 end
118 if user && user.must_change_password?
119 render_error :message => 'You must change your password', :status => 403
120 return
121 end
115 end
122 end
116 # Switch user if requested by an admin user
123 # Switch user if requested by an admin user
117 if user && user.admin? && (username = api_switch_user_from_request)
124 if user && user.admin? && (username = api_switch_user_from_request)
@@ -170,6 +177,16 class ApplicationController < ActionController::Base
170 require_login if Setting.login_required?
177 require_login if Setting.login_required?
171 end
178 end
172
179
180 def check_password_change
181 if session[:pwd]
182 if User.current.must_change_password?
183 redirect_to my_password_path
184 else
185 session.delete(:pwd)
186 end
187 end
188 end
189
173 def set_localization
190 def set_localization
174 lang = nil
191 lang = nil
175 if User.current.logged?
192 if User.current.logged?
@@ -17,6 +17,8
17
17
18 class MyController < ApplicationController
18 class MyController < ApplicationController
19 before_filter :require_login
19 before_filter :require_login
20 # let user change his password when he has to
21 skip_before_filter :check_password_change, :only => :password
20
22
21 helper :issues
23 helper :issues
22 helper :users
24 helper :users
@@ -90,14 +92,17 class MyController < ApplicationController
90 return
92 return
91 end
93 end
92 if request.post?
94 if request.post?
93 if @user.check_password?(params[:password])
95 if !@user.check_password?(params[:password])
96 flash.now[:error] = l(:notice_account_wrong_password)
97 elsif params[:password] == params[:new_password]
98 flash.now[:error] = 'Your new password must be different from your current password'
99 else
94 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
100 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
101 @user.must_change_passwd = false
95 if @user.save
102 if @user.save
96 flash[:notice] = l(:notice_account_password_updated)
103 flash[:notice] = l(:notice_account_password_updated)
97 redirect_to my_account_path
104 redirect_to my_account_path
98 end
105 end
99 else
100 flash[:error] = l(:notice_account_wrong_password)
101 end
106 end
102 end
107 end
103 end
108 end
@@ -280,6 +280,10 class User < Principal
280 return auth_source.allow_password_changes?
280 return auth_source.allow_password_changes?
281 end
281 end
282
282
283 def must_change_password?
284 must_change_passwd? && change_password_allowed?
285 end
286
283 def generate_password?
287 def generate_password?
284 generate_password == '1' || generate_password == true
288 generate_password == '1' || generate_password == true
285 end
289 end
@@ -568,6 +572,7 class User < Principal
568 safe_attributes 'status',
572 safe_attributes 'status',
569 'auth_source_id',
573 'auth_source_id',
570 'generate_password',
574 'generate_password',
575 'must_change_passwd',
571 :if => lambda {|user, current_user| current_user.admin?}
576 :if => lambda {|user, current_user| current_user.admin?}
572
577
573 safe_attributes 'group_ids',
578 safe_attributes 'group_ids',
@@ -17,6 +17,10
17 <%= submit_tag l(:button_apply) %>
17 <%= submit_tag l(:button_apply) %>
18 <% end %>
18 <% end %>
19
19
20 <% unless @user.must_change_passwd? %>
20 <% content_for :sidebar do %>
21 <% content_for :sidebar do %>
21 <%= render :partial => 'sidebar' %>
22 <%= render :partial => 'sidebar' %>
22 <% end %>
23 <% end %>
24 <% end %>
25
26 <%= javascript_tag "$('#password').focus();" %>
@@ -28,10 +28,11
28 <p><%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {$('#password_fields').show();} else {$('#password_fields').hide();}" %></p>
28 <p><%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {$('#password_fields').show();} else {$('#password_fields').hide();}" %></p>
29 <% end %>
29 <% end %>
30 <div id="password_fields" style="<%= 'display:none;' if @user.auth_source %>">
30 <div id="password_fields" style="<%= 'display:none;' if @user.auth_source %>">
31 <p><%= f.check_box :generate_password %></p>
32 <p><%= f.password_field :password, :required => true, :size => 25 %>
31 <p><%= f.password_field :password, :required => true, :size => 25 %>
33 <em class="info"><%= l(:text_caracters_minimum, :count => Setting.password_min_length) %></em></p>
32 <em class="info"><%= l(:text_caracters_minimum, :count => Setting.password_min_length) %></em></p>
34 <p><%= f.password_field :password_confirmation, :required => true, :size => 25 %></p>
33 <p><%= f.password_field :password_confirmation, :required => true, :size => 25 %></p>
34 <p><%= f.check_box :generate_password %></p>
35 <p><%= f.check_box :must_change_passwd %></p>
35 </div>
36 </div>
36 </fieldset>
37 </fieldset>
37 </div>
38 </div>
@@ -335,6 +335,7 en:
335 field_private_notes: Private notes
335 field_private_notes: Private notes
336 field_inherit_members: Inherit members
336 field_inherit_members: Inherit members
337 field_generate_password: Generate password
337 field_generate_password: Generate password
338 field_must_change_passwd: Must change password at next logon
338
339
339 setting_app_title: Application title
340 setting_app_title: Application title
340 setting_app_subtitle: Application subtitle
341 setting_app_subtitle: Application subtitle
@@ -335,6 +335,7 fr:
335 field_private_notes: Notes privΓ©es
335 field_private_notes: Notes privΓ©es
336 field_inherit_members: HΓ©riter les membres
336 field_inherit_members: HΓ©riter les membres
337 field_generate_password: GΓ©nΓ©rer un mot de passe
337 field_generate_password: GΓ©nΓ©rer un mot de passe
338 field_must_change_passwd: Doit changer de mot de passe Γ  la prochaine connexion
338
339
339 setting_app_title: Titre de l'application
340 setting_app_title: Titre de l'application
340 setting_app_subtitle: Sous-titre de l'application
341 setting_app_subtitle: Sous-titre de l'application
@@ -128,6 +128,35 class AccountTest < ActionController::IntegrationTest
128 assert_equal 0, Token.count
128 assert_equal 0, Token.count
129 end
129 end
130
130
131 def test_user_with_must_change_passwd_should_be_forced_to_change_its_password
132 User.find_by_login('jsmith').update_attribute :must_change_passwd, true
133
134 post '/login', :username => 'jsmith', :password => 'jsmith'
135 assert_redirected_to '/my/page'
136 follow_redirect!
137 assert_redirected_to '/my/password'
138
139 get '/issues'
140 assert_redirected_to '/my/password'
141 end
142
143 def test_user_with_must_change_passwd_should_be_able_to_change_its_password
144 User.find_by_login('jsmith').update_attribute :must_change_passwd, true
145
146 post '/login', :username => 'jsmith', :password => 'jsmith'
147 assert_redirected_to '/my/page'
148 follow_redirect!
149 assert_redirected_to '/my/password'
150 follow_redirect!
151 assert_response :success
152 post '/my/password', :password => 'jsmith', :new_password => 'newpassword', :new_password_confirmation => 'newpassword'
153 assert_redirected_to '/my/account'
154 follow_redirect!
155 assert_response :success
156
157 assert_equal false, User.find_by_login('jsmith').must_change_passwd?
158 end
159
131 def test_register_with_automatic_activation
160 def test_register_with_automatic_activation
132 Setting.self_registration = '3'
161 Setting.self_registration = '3'
133
162
General Comments 0
You need to be logged in to leave comments. Login now