@@ -0,0 +1,5 | |||||
|
1 | class AddPasswordChangedAtToUser < ActiveRecord::Migration | |||
|
2 | def change | |||
|
3 | add_column :users, :passwd_changed_on, :datetime | |||
|
4 | end | |||
|
5 | end |
@@ -49,7 +49,7 class ApplicationController < ActionController::Base | |||||
49 | end |
|
49 | end | |
50 | end |
|
50 | end | |
51 |
|
51 | |||
52 | before_filter :session_expiration, :user_setup, :check_if_login_required, :check_password_change, :set_localization |
|
52 | before_filter :session_expiration, :user_setup, :force_logout_if_password_changed, :check_if_login_required, :check_password_change, :set_localization | |
53 |
|
53 | |||
54 | rescue_from ::Unauthorized, :with => :deny_access |
|
54 | rescue_from ::Unauthorized, :with => :deny_access | |
55 | rescue_from ::ActionView::MissingTemplate, :with => :missing_template |
|
55 | rescue_from ::ActionView::MissingTemplate, :with => :missing_template | |
@@ -145,6 +145,18 class ApplicationController < ActionController::Base | |||||
145 | user |
|
145 | user | |
146 | end |
|
146 | end | |
147 |
|
147 | |||
|
148 | def force_logout_if_password_changed | |||
|
149 | passwd_changed_on = User.current.passwd_changed_on || Time.at(0) | |||
|
150 | # Make sure we force logout only for web browser sessions, not API calls | |||
|
151 | # if the password was changed after the session creation. | |||
|
152 | if session[:user_id] && passwd_changed_on.utc.to_i > session[:ctime].to_i | |||
|
153 | reset_session | |||
|
154 | set_localization | |||
|
155 | flash[:error] = l(:error_session_expired) | |||
|
156 | redirect_to signin_url | |||
|
157 | end | |||
|
158 | end | |||
|
159 | ||||
148 | def autologin_cookie_name |
|
160 | def autologin_cookie_name | |
149 | Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' |
|
161 | Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' | |
150 | end |
|
162 | end |
@@ -100,6 +100,9 class MyController < ApplicationController | |||||
100 | @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 |
|
101 | @user.must_change_passwd = false | |
102 | if @user.save |
|
102 | if @user.save | |
|
103 | # Reset the session creation time to not log out this session on next | |||
|
104 | # request due to ApplicationController#force_logout_if_password_changed | |||
|
105 | session[:ctime] = Time.now.utc.to_i | |||
103 | flash[:notice] = l(:notice_account_password_updated) |
|
106 | flash[:notice] = l(:notice_account_password_updated) | |
104 | redirect_to my_account_path |
|
107 | redirect_to my_account_path | |
105 | end |
|
108 | end |
@@ -279,6 +279,7 class User < Principal | |||||
279 | def salt_password(clear_password) |
|
279 | def salt_password(clear_password) | |
280 | self.salt = User.generate_salt |
|
280 | self.salt = User.generate_salt | |
281 | self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") |
|
281 | self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") | |
|
282 | self.passwd_changed_on = Time.now | |||
282 | end |
|
283 | end | |
283 |
|
284 | |||
284 | # Does the backend storage allow this user to change their password? |
|
285 | # Does the backend storage allow this user to change their password? |
@@ -185,6 +185,18 class MyControllerTest < ActionController::TestCase | |||||
185 | assert User.try_to_login('jsmith', 'secret123') |
|
185 | assert User.try_to_login('jsmith', 'secret123') | |
186 | end |
|
186 | end | |
187 |
|
187 | |||
|
188 | def test_change_password_kills_other_sessions | |||
|
189 | @request.session[:ctime] = (Time.now - 30.minutes).utc.to_i | |||
|
190 | ||||
|
191 | jsmith = User.find(2) | |||
|
192 | jsmith.passwd_changed_on = Time.now | |||
|
193 | jsmith.save! | |||
|
194 | ||||
|
195 | get 'account' | |||
|
196 | assert_response 302 | |||
|
197 | assert flash[:error].match(/Your session has expired/) | |||
|
198 | end | |||
|
199 | ||||
188 | def test_change_password_should_redirect_if_user_cannot_change_its_password |
|
200 | def test_change_password_should_redirect_if_user_cannot_change_its_password | |
189 | User.find(2).update_attribute(:auth_source_id, 1) |
|
201 | User.find(2).update_attribute(:auth_source_id, 1) | |
190 |
|
202 |
General Comments 0
You need to be logged in to leave comments.
Login now