@@ -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