##// END OF EJS Templates
Login link unexpected logs you out (#12611)....
Jean-Philippe Lang -
r10892:7c2490c6fc92
parent child
Show More
@@ -1,296 +1,298
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class AccountController < ApplicationController
19 19 helper :custom_fields
20 20 include CustomFieldsHelper
21 21
22 22 # prevents login action to be filtered by check_if_login_required application scope filter
23 23 skip_before_filter :check_if_login_required
24 24
25 25 # Login request and validation
26 26 def login
27 27 if request.get?
28 logout_user
28 if User.current.logged?
29 redirect_to home_url
30 end
29 31 else
30 32 authenticate_user
31 33 end
32 34 rescue AuthSourceException => e
33 35 logger.error "An error occured when authenticating #{params[:username]}: #{e.message}"
34 36 render_error :message => e.message
35 37 end
36 38
37 39 # Log out current user and redirect to welcome page
38 40 def logout
39 41 logout_user
40 42 redirect_to home_url
41 43 end
42 44
43 45 # Lets user choose a new password
44 46 def lost_password
45 47 redirect_to(home_url) && return unless Setting.lost_password?
46 48 if params[:token]
47 49 @token = Token.find_by_action_and_value("recovery", params[:token].to_s)
48 50 if @token.nil? || @token.expired?
49 51 redirect_to home_url
50 52 return
51 53 end
52 54 @user = @token.user
53 55 unless @user && @user.active?
54 56 redirect_to home_url
55 57 return
56 58 end
57 59 if request.post?
58 60 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
59 61 if @user.save
60 62 @token.destroy
61 63 flash[:notice] = l(:notice_account_password_updated)
62 64 redirect_to signin_path
63 65 return
64 66 end
65 67 end
66 68 render :template => "account/password_recovery"
67 69 return
68 70 else
69 71 if request.post?
70 72 user = User.find_by_mail(params[:mail].to_s)
71 73 # user not found or not active
72 74 unless user && user.active?
73 75 flash.now[:error] = l(:notice_account_unknown_email)
74 76 return
75 77 end
76 78 # user cannot change its password
77 79 unless user.change_password_allowed?
78 80 flash.now[:error] = l(:notice_can_t_change_password)
79 81 return
80 82 end
81 83 # create a new token for password recovery
82 84 token = Token.new(:user => user, :action => "recovery")
83 85 if token.save
84 86 Mailer.lost_password(token).deliver
85 87 flash[:notice] = l(:notice_account_lost_email_sent)
86 88 redirect_to signin_path
87 89 return
88 90 end
89 91 end
90 92 end
91 93 end
92 94
93 95 # User self-registration
94 96 def register
95 97 redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
96 98 if request.get?
97 99 session[:auth_source_registration] = nil
98 100 @user = User.new(:language => current_language.to_s)
99 101 else
100 102 user_params = params[:user] || {}
101 103 @user = User.new
102 104 @user.safe_attributes = user_params
103 105 @user.admin = false
104 106 @user.register
105 107 if session[:auth_source_registration]
106 108 @user.activate
107 109 @user.login = session[:auth_source_registration][:login]
108 110 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
109 111 if @user.save
110 112 session[:auth_source_registration] = nil
111 113 self.logged_user = @user
112 114 flash[:notice] = l(:notice_account_activated)
113 115 redirect_to my_account_path
114 116 end
115 117 else
116 118 @user.login = params[:user][:login]
117 119 unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank?
118 120 @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation]
119 121 end
120 122
121 123 case Setting.self_registration
122 124 when '1'
123 125 register_by_email_activation(@user)
124 126 when '3'
125 127 register_automatically(@user)
126 128 else
127 129 register_manually_by_administrator(@user)
128 130 end
129 131 end
130 132 end
131 133 end
132 134
133 135 # Token based account activation
134 136 def activate
135 137 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
136 138 token = Token.find_by_action_and_value('register', params[:token])
137 139 redirect_to(home_url) && return unless token and !token.expired?
138 140 user = token.user
139 141 redirect_to(home_url) && return unless user.registered?
140 142 user.activate
141 143 if user.save
142 144 token.destroy
143 145 flash[:notice] = l(:notice_account_activated)
144 146 end
145 147 redirect_to signin_path
146 148 end
147 149
148 150 private
149 151
150 152 def authenticate_user
151 153 if Setting.openid? && using_open_id?
152 154 open_id_authenticate(params[:openid_url])
153 155 else
154 156 password_authentication
155 157 end
156 158 end
157 159
158 160 def password_authentication
159 161 user = User.try_to_login(params[:username], params[:password])
160 162
161 163 if user.nil?
162 164 invalid_credentials
163 165 elsif user.new_record?
164 166 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
165 167 else
166 168 # Valid user
167 169 successful_authentication(user)
168 170 end
169 171 end
170 172
171 173 def open_id_authenticate(openid_url)
172 174 authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url, :method => :post) do |result, identity_url, registration|
173 175 if result.successful?
174 176 user = User.find_or_initialize_by_identity_url(identity_url)
175 177 if user.new_record?
176 178 # Self-registration off
177 179 redirect_to(home_url) && return unless Setting.self_registration?
178 180
179 181 # Create on the fly
180 182 user.login = registration['nickname'] unless registration['nickname'].nil?
181 183 user.mail = registration['email'] unless registration['email'].nil?
182 184 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
183 185 user.random_password
184 186 user.register
185 187
186 188 case Setting.self_registration
187 189 when '1'
188 190 register_by_email_activation(user) do
189 191 onthefly_creation_failed(user)
190 192 end
191 193 when '3'
192 194 register_automatically(user) do
193 195 onthefly_creation_failed(user)
194 196 end
195 197 else
196 198 register_manually_by_administrator(user) do
197 199 onthefly_creation_failed(user)
198 200 end
199 201 end
200 202 else
201 203 # Existing record
202 204 if user.active?
203 205 successful_authentication(user)
204 206 else
205 207 account_pending
206 208 end
207 209 end
208 210 end
209 211 end
210 212 end
211 213
212 214 def successful_authentication(user)
213 215 logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
214 216 # Valid user
215 217 self.logged_user = user
216 218 # generate a key and set cookie if autologin
217 219 if params[:autologin] && Setting.autologin?
218 220 set_autologin_cookie(user)
219 221 end
220 222 call_hook(:controller_account_success_authentication_after, {:user => user })
221 223 redirect_back_or_default my_page_path
222 224 end
223 225
224 226 def set_autologin_cookie(user)
225 227 token = Token.create(:user => user, :action => 'autologin')
226 228 cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
227 229 cookie_options = {
228 230 :value => token.value,
229 231 :expires => 1.year.from_now,
230 232 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
231 233 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
232 234 :httponly => true
233 235 }
234 236 cookies[cookie_name] = cookie_options
235 237 end
236 238
237 239 # Onthefly creation failed, display the registration form to fill/fix attributes
238 240 def onthefly_creation_failed(user, auth_source_options = { })
239 241 @user = user
240 242 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
241 243 render :action => 'register'
242 244 end
243 245
244 246 def invalid_credentials
245 247 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
246 248 flash.now[:error] = l(:notice_account_invalid_creditentials)
247 249 end
248 250
249 251 # Register a user for email activation.
250 252 #
251 253 # Pass a block for behavior when a user fails to save
252 254 def register_by_email_activation(user, &block)
253 255 token = Token.new(:user => user, :action => "register")
254 256 if user.save and token.save
255 257 Mailer.register(token).deliver
256 258 flash[:notice] = l(:notice_account_register_done)
257 259 redirect_to signin_path
258 260 else
259 261 yield if block_given?
260 262 end
261 263 end
262 264
263 265 # Automatically register a user
264 266 #
265 267 # Pass a block for behavior when a user fails to save
266 268 def register_automatically(user, &block)
267 269 # Automatic activation
268 270 user.activate
269 271 user.last_login_on = Time.now
270 272 if user.save
271 273 self.logged_user = user
272 274 flash[:notice] = l(:notice_account_activated)
273 275 redirect_to my_account_path
274 276 else
275 277 yield if block_given?
276 278 end
277 279 end
278 280
279 281 # Manual activation by the administrator
280 282 #
281 283 # Pass a block for behavior when a user fails to save
282 284 def register_manually_by_administrator(user, &block)
283 285 if user.save
284 286 # Sends an email to the administrators
285 287 Mailer.account_activation_request(user).deliver
286 288 account_pending
287 289 else
288 290 yield if block_given?
289 291 end
290 292 end
291 293
292 294 def account_pending
293 295 flash[:notice] = l(:notice_account_pending)
294 296 redirect_to signin_path
295 297 end
296 298 end
@@ -1,260 +1,268
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2012 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class AccountControllerTest < ActionController::TestCase
21 21 fixtures :users, :roles
22 22
23 23 def setup
24 24 User.current = nil
25 25 end
26 26
27 27 def test_get_login
28 28 get :login
29 29 assert_response :success
30 30 assert_template 'login'
31 31
32 32 assert_select 'input[name=username]'
33 33 assert_select 'input[name=password]'
34 34 end
35 35
36 def test_get_login_while_logged_in_should_redirect_to_home
37 @request.session[:user_id] = 2
38
39 get :login
40 assert_redirected_to '/'
41 assert_equal 2, @request.session[:user_id]
42 end
43
36 44 def test_login_should_redirect_to_back_url_param
37 45 # request.uri is "test.host" in test environment
38 46 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http://test.host/issues/show/1'
39 47 assert_redirected_to '/issues/show/1'
40 48 end
41 49
42 50 def test_login_should_not_redirect_to_another_host
43 51 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => 'http://test.foo/fake'
44 52 assert_redirected_to '/my/page'
45 53 end
46 54
47 55 def test_login_with_wrong_password
48 56 post :login, :username => 'admin', :password => 'bad'
49 57 assert_response :success
50 58 assert_template 'login'
51 59
52 60 assert_select 'div.flash.error', :text => /Invalid user or password/
53 61 assert_select 'input[name=username][value=admin]'
54 62 assert_select 'input[name=password]'
55 63 assert_select 'input[name=password][value]', 0
56 64 end
57 65
58 66 def test_login_should_rescue_auth_source_exception
59 67 source = AuthSource.create!(:name => 'Test')
60 68 User.find(2).update_attribute :auth_source_id, source.id
61 69 AuthSource.any_instance.stubs(:authenticate).raises(AuthSourceException.new("Something wrong"))
62 70
63 71 post :login, :username => 'jsmith', :password => 'jsmith'
64 72 assert_response 500
65 73 assert_error_tag :content => /Something wrong/
66 74 end
67 75
68 76 def test_login_should_reset_session
69 77 @controller.expects(:reset_session).once
70 78
71 79 post :login, :username => 'jsmith', :password => 'jsmith'
72 80 assert_response 302
73 81 end
74 82
75 83 def test_logout
76 84 @request.session[:user_id] = 2
77 85 get :logout
78 86 assert_redirected_to '/'
79 87 assert_nil @request.session[:user_id]
80 88 end
81 89
82 90 def test_logout_should_reset_session
83 91 @controller.expects(:reset_session).once
84 92
85 93 @request.session[:user_id] = 2
86 94 get :logout
87 95 assert_response 302
88 96 end
89 97
90 98 def test_get_register_with_registration_on
91 99 with_settings :self_registration => '3' do
92 100 get :register
93 101 assert_response :success
94 102 assert_template 'register'
95 103 assert_not_nil assigns(:user)
96 104
97 105 assert_select 'input[name=?]', 'user[password]'
98 106 assert_select 'input[name=?]', 'user[password_confirmation]'
99 107 end
100 108 end
101 109
102 110 def test_get_register_should_detect_user_language
103 111 with_settings :self_registration => '3' do
104 112 @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
105 113 get :register
106 114 assert_response :success
107 115 assert_not_nil assigns(:user)
108 116 assert_equal 'fr', assigns(:user).language
109 117 assert_select 'select[name=?]', 'user[language]' do
110 118 assert_select 'option[value=fr][selected=selected]'
111 119 end
112 120 end
113 121 end
114 122
115 123 def test_get_register_with_registration_off_should_redirect
116 124 with_settings :self_registration => '0' do
117 125 get :register
118 126 assert_redirected_to '/'
119 127 end
120 128 end
121 129
122 130 # See integration/account_test.rb for the full test
123 131 def test_post_register_with_registration_on
124 132 with_settings :self_registration => '3' do
125 133 assert_difference 'User.count' do
126 134 post :register, :user => {
127 135 :login => 'register',
128 136 :password => 'secret123',
129 137 :password_confirmation => 'secret123',
130 138 :firstname => 'John',
131 139 :lastname => 'Doe',
132 140 :mail => 'register@example.com'
133 141 }
134 142 assert_redirected_to '/my/account'
135 143 end
136 144 user = User.first(:order => 'id DESC')
137 145 assert_equal 'register', user.login
138 146 assert_equal 'John', user.firstname
139 147 assert_equal 'Doe', user.lastname
140 148 assert_equal 'register@example.com', user.mail
141 149 assert user.check_password?('secret123')
142 150 assert user.active?
143 151 end
144 152 end
145 153
146 154 def test_post_register_with_registration_off_should_redirect
147 155 with_settings :self_registration => '0' do
148 156 assert_no_difference 'User.count' do
149 157 post :register, :user => {
150 158 :login => 'register',
151 159 :password => 'test',
152 160 :password_confirmation => 'test',
153 161 :firstname => 'John',
154 162 :lastname => 'Doe',
155 163 :mail => 'register@example.com'
156 164 }
157 165 assert_redirected_to '/'
158 166 end
159 167 end
160 168 end
161 169
162 170 def test_get_lost_password_should_display_lost_password_form
163 171 get :lost_password
164 172 assert_response :success
165 173 assert_select 'input[name=mail]'
166 174 end
167 175
168 176 def test_lost_password_for_active_user_should_create_a_token
169 177 Token.delete_all
170 178 ActionMailer::Base.deliveries.clear
171 179 assert_difference 'ActionMailer::Base.deliveries.size' do
172 180 assert_difference 'Token.count' do
173 181 with_settings :host_name => 'mydomain.foo', :protocol => 'http' do
174 182 post :lost_password, :mail => 'JSmith@somenet.foo'
175 183 assert_redirected_to '/login'
176 184 end
177 185 end
178 186 end
179 187
180 188 token = Token.order('id DESC').first
181 189 assert_equal User.find(2), token.user
182 190 assert_equal 'recovery', token.action
183 191
184 192 assert_select_email do
185 193 assert_select "a[href=?]", "http://mydomain.foo/account/lost_password?token=#{token.value}"
186 194 end
187 195 end
188 196
189 197 def test_lost_password_for_unknown_user_should_fail
190 198 Token.delete_all
191 199 assert_no_difference 'Token.count' do
192 200 post :lost_password, :mail => 'invalid@somenet.foo'
193 201 assert_response :success
194 202 end
195 203 end
196 204
197 205 def test_lost_password_for_non_active_user_should_fail
198 206 Token.delete_all
199 207 assert User.find(2).lock!
200 208
201 209 assert_no_difference 'Token.count' do
202 210 post :lost_password, :mail => 'JSmith@somenet.foo'
203 211 assert_response :success
204 212 end
205 213 end
206 214
207 215 def test_get_lost_password_with_token_should_display_the_password_recovery_form
208 216 user = User.find(2)
209 217 token = Token.create!(:action => 'recovery', :user => user)
210 218
211 219 get :lost_password, :token => token.value
212 220 assert_response :success
213 221 assert_template 'password_recovery'
214 222
215 223 assert_select 'input[type=hidden][name=token][value=?]', token.value
216 224 end
217 225
218 226 def test_get_lost_password_with_invalid_token_should_redirect
219 227 get :lost_password, :token => "abcdef"
220 228 assert_redirected_to '/'
221 229 end
222 230
223 231 def test_post_lost_password_with_token_should_change_the_user_password
224 232 user = User.find(2)
225 233 token = Token.create!(:action => 'recovery', :user => user)
226 234
227 235 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
228 236 assert_redirected_to '/login'
229 237 user.reload
230 238 assert user.check_password?('newpass123')
231 239 assert_nil Token.find_by_id(token.id), "Token was not deleted"
232 240 end
233 241
234 242 def test_post_lost_password_with_token_for_non_active_user_should_fail
235 243 user = User.find(2)
236 244 token = Token.create!(:action => 'recovery', :user => user)
237 245 user.lock!
238 246
239 247 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
240 248 assert_redirected_to '/'
241 249 assert ! user.check_password?('newpass123')
242 250 end
243 251
244 252 def test_post_lost_password_with_token_and_password_confirmation_failure_should_redisplay_the_form
245 253 user = User.find(2)
246 254 token = Token.create!(:action => 'recovery', :user => user)
247 255
248 256 post :lost_password, :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'wrongpass'
249 257 assert_response :success
250 258 assert_template 'password_recovery'
251 259 assert_not_nil Token.find_by_id(token.id), "Token was deleted"
252 260
253 261 assert_select 'input[type=hidden][name=token][value=?]', token.value
254 262 end
255 263
256 264 def test_post_lost_password_with_invalid_token_should_redirect
257 265 post :lost_password, :token => "abcdef", :new_password => 'newpass', :new_password_confirmation => 'newpass'
258 266 assert_redirected_to '/'
259 267 end
260 268 end
General Comments 0
You need to be logged in to leave comments. Login now