##// END OF EJS Templates
Fixed that OpenID authentication fails with 422 error due to token verification (#15735)....
Jean-Philippe Lang -
r12163:5ee277fa22e9
parent child
Show More
@@ -1,343 +1,351
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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, :check_password_change
24 24
25 # Overrides ApplicationController#verify_authenticity_token to disable
26 # token verification on openid callbacks
27 def verify_authenticity_token
28 unless using_open_id?
29 super
30 end
31 end
32
25 33 # Login request and validation
26 34 def login
27 35 if request.get?
28 36 if User.current.logged?
29 37 redirect_to home_url
30 38 end
31 39 else
32 40 authenticate_user
33 41 end
34 42 rescue AuthSourceException => e
35 43 logger.error "An error occured when authenticating #{params[:username]}: #{e.message}"
36 44 render_error :message => e.message
37 45 end
38 46
39 47 # Log out current user and redirect to welcome page
40 48 def logout
41 49 if User.current.anonymous?
42 50 redirect_to home_url
43 51 elsif request.post?
44 52 logout_user
45 53 redirect_to home_url
46 54 end
47 55 # display the logout form
48 56 end
49 57
50 58 # Lets user choose a new password
51 59 def lost_password
52 60 (redirect_to(home_url); return) unless Setting.lost_password?
53 61 if params[:token]
54 62 @token = Token.find_token("recovery", params[:token].to_s)
55 63 if @token.nil? || @token.expired?
56 64 redirect_to home_url
57 65 return
58 66 end
59 67 @user = @token.user
60 68 unless @user && @user.active?
61 69 redirect_to home_url
62 70 return
63 71 end
64 72 if request.post?
65 73 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
66 74 if @user.save
67 75 @token.destroy
68 76 flash[:notice] = l(:notice_account_password_updated)
69 77 redirect_to signin_path
70 78 return
71 79 end
72 80 end
73 81 render :template => "account/password_recovery"
74 82 return
75 83 else
76 84 if request.post?
77 85 user = User.find_by_mail(params[:mail].to_s)
78 86 # user not found
79 87 unless user
80 88 flash.now[:error] = l(:notice_account_unknown_email)
81 89 return
82 90 end
83 91 unless user.active?
84 92 handle_inactive_user(user, lost_password_path)
85 93 return
86 94 end
87 95 # user cannot change its password
88 96 unless user.change_password_allowed?
89 97 flash.now[:error] = l(:notice_can_t_change_password)
90 98 return
91 99 end
92 100 # create a new token for password recovery
93 101 token = Token.new(:user => user, :action => "recovery")
94 102 if token.save
95 103 Mailer.lost_password(token).deliver
96 104 flash[:notice] = l(:notice_account_lost_email_sent)
97 105 redirect_to signin_path
98 106 return
99 107 end
100 108 end
101 109 end
102 110 end
103 111
104 112 # User self-registration
105 113 def register
106 114 (redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration]
107 115 if request.get?
108 116 session[:auth_source_registration] = nil
109 117 @user = User.new(:language => current_language.to_s)
110 118 else
111 119 user_params = params[:user] || {}
112 120 @user = User.new
113 121 @user.safe_attributes = user_params
114 122 @user.admin = false
115 123 @user.register
116 124 if session[:auth_source_registration]
117 125 @user.activate
118 126 @user.login = session[:auth_source_registration][:login]
119 127 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
120 128 if @user.save
121 129 session[:auth_source_registration] = nil
122 130 self.logged_user = @user
123 131 flash[:notice] = l(:notice_account_activated)
124 132 redirect_to my_account_path
125 133 end
126 134 else
127 135 @user.login = params[:user][:login]
128 136 unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank?
129 137 @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation]
130 138 end
131 139
132 140 case Setting.self_registration
133 141 when '1'
134 142 register_by_email_activation(@user)
135 143 when '3'
136 144 register_automatically(@user)
137 145 else
138 146 register_manually_by_administrator(@user)
139 147 end
140 148 end
141 149 end
142 150 end
143 151
144 152 # Token based account activation
145 153 def activate
146 154 (redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present?
147 155 token = Token.find_token('register', params[:token].to_s)
148 156 (redirect_to(home_url); return) unless token and !token.expired?
149 157 user = token.user
150 158 (redirect_to(home_url); return) unless user.registered?
151 159 user.activate
152 160 if user.save
153 161 token.destroy
154 162 flash[:notice] = l(:notice_account_activated)
155 163 end
156 164 redirect_to signin_path
157 165 end
158 166
159 167 # Sends a new account activation email
160 168 def activation_email
161 169 if session[:registered_user_id] && Setting.self_registration == '1'
162 170 user_id = session.delete(:registered_user_id).to_i
163 171 user = User.find_by_id(user_id)
164 172 if user && user.registered?
165 173 register_by_email_activation(user)
166 174 return
167 175 end
168 176 end
169 177 redirect_to(home_url)
170 178 end
171 179
172 180 private
173 181
174 182 def authenticate_user
175 183 if Setting.openid? && using_open_id?
176 184 open_id_authenticate(params[:openid_url])
177 185 else
178 186 password_authentication
179 187 end
180 188 end
181 189
182 190 def password_authentication
183 191 user = User.try_to_login(params[:username], params[:password], false)
184 192
185 193 if user.nil?
186 194 invalid_credentials
187 195 elsif user.new_record?
188 196 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
189 197 else
190 198 # Valid user
191 199 if user.active?
192 200 successful_authentication(user)
193 201 else
194 202 handle_inactive_user(user)
195 203 end
196 204 end
197 205 end
198 206
199 207 def open_id_authenticate(openid_url)
200 208 back_url = signin_url(:autologin => params[:autologin])
201 209 authenticate_with_open_id(
202 210 openid_url, :required => [:nickname, :fullname, :email],
203 211 :return_to => back_url, :method => :post
204 212 ) do |result, identity_url, registration|
205 213 if result.successful?
206 214 user = User.find_or_initialize_by_identity_url(identity_url)
207 215 if user.new_record?
208 216 # Self-registration off
209 217 (redirect_to(home_url); return) unless Setting.self_registration?
210 218 # Create on the fly
211 219 user.login = registration['nickname'] unless registration['nickname'].nil?
212 220 user.mail = registration['email'] unless registration['email'].nil?
213 221 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
214 222 user.random_password
215 223 user.register
216 224 case Setting.self_registration
217 225 when '1'
218 226 register_by_email_activation(user) do
219 227 onthefly_creation_failed(user)
220 228 end
221 229 when '3'
222 230 register_automatically(user) do
223 231 onthefly_creation_failed(user)
224 232 end
225 233 else
226 234 register_manually_by_administrator(user) do
227 235 onthefly_creation_failed(user)
228 236 end
229 237 end
230 238 else
231 239 # Existing record
232 240 if user.active?
233 241 successful_authentication(user)
234 242 else
235 243 handle_inactive_user(user)
236 244 end
237 245 end
238 246 end
239 247 end
240 248 end
241 249
242 250 def successful_authentication(user)
243 251 logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
244 252 # Valid user
245 253 self.logged_user = user
246 254 # generate a key and set cookie if autologin
247 255 if params[:autologin] && Setting.autologin?
248 256 set_autologin_cookie(user)
249 257 end
250 258 call_hook(:controller_account_success_authentication_after, {:user => user })
251 259 redirect_back_or_default my_page_path
252 260 end
253 261
254 262 def set_autologin_cookie(user)
255 263 token = Token.create(:user => user, :action => 'autologin')
256 264 cookie_options = {
257 265 :value => token.value,
258 266 :expires => 1.year.from_now,
259 267 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
260 268 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
261 269 :httponly => true
262 270 }
263 271 cookies[autologin_cookie_name] = cookie_options
264 272 end
265 273
266 274 # Onthefly creation failed, display the registration form to fill/fix attributes
267 275 def onthefly_creation_failed(user, auth_source_options = { })
268 276 @user = user
269 277 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
270 278 render :action => 'register'
271 279 end
272 280
273 281 def invalid_credentials
274 282 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
275 283 flash.now[:error] = l(:notice_account_invalid_creditentials)
276 284 end
277 285
278 286 # Register a user for email activation.
279 287 #
280 288 # Pass a block for behavior when a user fails to save
281 289 def register_by_email_activation(user, &block)
282 290 token = Token.new(:user => user, :action => "register")
283 291 if user.save and token.save
284 292 Mailer.register(token).deliver
285 293 flash[:notice] = l(:notice_account_register_done, :email => user.mail)
286 294 redirect_to signin_path
287 295 else
288 296 yield if block_given?
289 297 end
290 298 end
291 299
292 300 # Automatically register a user
293 301 #
294 302 # Pass a block for behavior when a user fails to save
295 303 def register_automatically(user, &block)
296 304 # Automatic activation
297 305 user.activate
298 306 user.last_login_on = Time.now
299 307 if user.save
300 308 self.logged_user = user
301 309 flash[:notice] = l(:notice_account_activated)
302 310 redirect_to my_account_path
303 311 else
304 312 yield if block_given?
305 313 end
306 314 end
307 315
308 316 # Manual activation by the administrator
309 317 #
310 318 # Pass a block for behavior when a user fails to save
311 319 def register_manually_by_administrator(user, &block)
312 320 if user.save
313 321 # Sends an email to the administrators
314 322 Mailer.account_activation_request(user).deliver
315 323 account_pending(user)
316 324 else
317 325 yield if block_given?
318 326 end
319 327 end
320 328
321 329 def handle_inactive_user(user, redirect_path=signin_path)
322 330 if user.registered?
323 331 account_pending(user, redirect_path)
324 332 else
325 333 account_locked(user, redirect_path)
326 334 end
327 335 end
328 336
329 337 def account_pending(user, redirect_path=signin_path)
330 338 if Setting.self_registration == '1'
331 339 flash[:error] = l(:notice_account_not_activated_yet, :url => activation_email_path)
332 340 session[:registered_user_id] = user.id
333 341 else
334 342 flash[:error] = l(:notice_account_pending)
335 343 end
336 344 redirect_to redirect_path
337 345 end
338 346
339 347 def account_locked(user, redirect_path=signin_path)
340 348 flash[:error] = l(:notice_account_locked)
341 349 redirect_to redirect_path
342 350 end
343 351 end
@@ -1,165 +1,175
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2013 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 AccountControllerOpenidTest < ActionController::TestCase
21 21 tests AccountController
22 22 fixtures :users, :roles
23 23
24 24 def setup
25 25 User.current = nil
26 26 Setting.openid = '1'
27 27 end
28 28
29 29 def teardown
30 30 Setting.openid = '0'
31 31 end
32 32
33 33 if Object.const_defined?(:OpenID)
34 34
35 35 def test_login_with_openid_for_existing_user
36 36 Setting.self_registration = '3'
37 37 existing_user = User.new(:firstname => 'Cool',
38 38 :lastname => 'User',
39 39 :mail => 'user@somedomain.com',
40 40 :identity_url => 'http://openid.example.com/good_user')
41 41 existing_user.login = 'cool_user'
42 42 assert existing_user.save!
43 43
44 44 post :login, :openid_url => existing_user.identity_url
45 45 assert_redirected_to '/my/page'
46 46 end
47 47
48 48 def test_login_with_invalid_openid_provider
49 49 Setting.self_registration = '0'
50 50 post :login, :openid_url => 'http;//openid.example.com/good_user'
51 51 assert_redirected_to home_url
52 52 end
53 53
54 54 def test_login_with_openid_for_existing_non_active_user
55 55 Setting.self_registration = '2'
56 56 existing_user = User.new(:firstname => 'Cool',
57 57 :lastname => 'User',
58 58 :mail => 'user@somedomain.com',
59 59 :identity_url => 'http://openid.example.com/good_user',
60 60 :status => User::STATUS_REGISTERED)
61 61 existing_user.login = 'cool_user'
62 62 assert existing_user.save!
63 63
64 64 post :login, :openid_url => existing_user.identity_url
65 65 assert_redirected_to '/login'
66 66 end
67 67
68 68 def test_login_with_openid_with_new_user_created
69 69 Setting.self_registration = '3'
70 70 post :login, :openid_url => 'http://openid.example.com/good_user'
71 71 assert_redirected_to '/my/account'
72 72 user = User.find_by_login('cool_user')
73 73 assert user
74 74 assert_equal 'Cool', user.firstname
75 75 assert_equal 'User', user.lastname
76 76 end
77 77
78 78 def test_login_with_openid_with_new_user_and_self_registration_off
79 79 Setting.self_registration = '0'
80 80 post :login, :openid_url => 'http://openid.example.com/good_user'
81 81 assert_redirected_to home_url
82 82 user = User.find_by_login('cool_user')
83 83 assert_nil user
84 84 end
85 85
86 86 def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token
87 87 Setting.self_registration = '1'
88 88 post :login, :openid_url => 'http://openid.example.com/good_user'
89 89 assert_redirected_to '/login'
90 90 user = User.find_by_login('cool_user')
91 91 assert user
92 92
93 93 token = Token.find_by_user_id_and_action(user.id, 'register')
94 94 assert token
95 95 end
96 96
97 97 def test_login_with_openid_with_new_user_created_with_manual_activation
98 98 Setting.self_registration = '2'
99 99 post :login, :openid_url => 'http://openid.example.com/good_user'
100 100 assert_redirected_to '/login'
101 101 user = User.find_by_login('cool_user')
102 102 assert user
103 103 assert_equal User::STATUS_REGISTERED, user.status
104 104 end
105 105
106 106 def test_login_with_openid_with_new_user_with_conflict_should_register
107 107 Setting.self_registration = '3'
108 108 existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com')
109 109 existing_user.login = 'cool_user'
110 110 assert existing_user.save!
111 111
112 112 post :login, :openid_url => 'http://openid.example.com/good_user'
113 113 assert_response :success
114 114 assert_template 'register'
115 115 assert assigns(:user)
116 116 assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url]
117 117 end
118 118
119 119 def test_login_with_openid_with_new_user_with_missing_information_should_register
120 120 Setting.self_registration = '3'
121 121
122 122 post :login, :openid_url => 'http://openid.example.com/good_blank_user'
123 123 assert_response :success
124 124 assert_template 'register'
125 125 assert assigns(:user)
126 126 assert_equal 'http://openid.example.com/good_blank_user', assigns(:user)[:identity_url]
127 127
128 128 assert_select 'input[name=?]', 'user[login]'
129 129 assert_select 'input[name=?]', 'user[password]'
130 130 assert_select 'input[name=?]', 'user[password_confirmation]'
131 131 assert_select 'input[name=?][value=?]', 'user[identity_url]', 'http://openid.example.com/good_blank_user'
132 132 end
133 133
134 def test_post_login_should_not_verify_token_when_using_open_id
135 ActionController::Base.allow_forgery_protection = true
136 AccountController.any_instance.stubs(:using_open_id?).returns(true)
137 AccountController.any_instance.stubs(:authenticate_with_open_id).returns(true)
138 post :login
139 assert_response 200
140 ensure
141 ActionController::Base.allow_forgery_protection = false
142 end
143
134 144 def test_register_after_login_failure_should_not_require_user_to_enter_a_password
135 145 Setting.self_registration = '3'
136 146
137 147 assert_difference 'User.count' do
138 148 post :register, :user => {
139 149 :login => 'good_blank_user',
140 150 :password => '',
141 151 :password_confirmation => '',
142 152 :firstname => 'Cool',
143 153 :lastname => 'User',
144 154 :mail => 'user@somedomain.com',
145 155 :identity_url => 'http://openid.example.com/good_blank_user'
146 156 }
147 157 assert_response 302
148 158 end
149 159
150 160 user = User.first(:order => 'id DESC')
151 161 assert_equal 'http://openid.example.com/good_blank_user', user.identity_url
152 162 assert user.hashed_password.blank?, "Hashed password was #{user.hashed_password}"
153 163 end
154 164
155 165 def test_setting_openid_should_return_true_when_set_to_true
156 166 assert_equal true, Setting.openid?
157 167 end
158 168
159 169 else
160 170 puts "Skipping openid tests."
161 171
162 172 def test_dummy
163 173 end
164 174 end
165 175 end
General Comments 0
You need to be logged in to leave comments. Login now