@@ -0,0 +1,10 | |||||
|
1 | class AddTokensUpdatedOn < ActiveRecord::Migration | |||
|
2 | def self.up | |||
|
3 | add_column :tokens, :updated_on, :timestamp | |||
|
4 | Token.update_all("updated_on = created_on") | |||
|
5 | end | |||
|
6 | ||||
|
7 | def self.down | |||
|
8 | remove_column :tokens, :updated_on | |||
|
9 | end | |||
|
10 | end |
@@ -0,0 +1,97 | |||||
|
1 | # Redmine - project management software | |||
|
2 | # Copyright (C) 2006-2015 Jean-Philippe Lang | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or | |||
|
5 | # modify it under the terms of the GNU General Public License | |||
|
6 | # as published by the Free Software Foundation; either version 2 | |||
|
7 | # of the License, or (at your option) any later version. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU General Public License | |||
|
15 | # along with this program; if not, write to the Free Software | |||
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
17 | ||||
|
18 | require File.expand_path('../../test_helper', __FILE__) | |||
|
19 | ||||
|
20 | class SessionsTest < Redmine::IntegrationTest | |||
|
21 | fixtures :users, :email_addresses, :roles | |||
|
22 | ||||
|
23 | def setup | |||
|
24 | Rails.application.config.redmine_verify_sessions = true | |||
|
25 | end | |||
|
26 | ||||
|
27 | def teardown | |||
|
28 | Rails.application.config.redmine_verify_sessions = false | |||
|
29 | end | |||
|
30 | ||||
|
31 | def test_change_password_kills_sessions | |||
|
32 | log_user('jsmith', 'jsmith') | |||
|
33 | ||||
|
34 | jsmith = User.find(2) | |||
|
35 | jsmith.password = "somenewpassword" | |||
|
36 | jsmith.save! | |||
|
37 | ||||
|
38 | get '/my/account' | |||
|
39 | assert_response 302 | |||
|
40 | assert flash[:error].match(/Your session has expired/) | |||
|
41 | end | |||
|
42 | ||||
|
43 | def test_lock_user_kills_sessions | |||
|
44 | log_user('jsmith', 'jsmith') | |||
|
45 | ||||
|
46 | jsmith = User.find(2) | |||
|
47 | assert jsmith.lock! | |||
|
48 | assert jsmith.activate! | |||
|
49 | ||||
|
50 | get '/my/account' | |||
|
51 | assert_response 302 | |||
|
52 | assert flash[:error].match(/Your session has expired/) | |||
|
53 | end | |||
|
54 | ||||
|
55 | def test_update_user_does_not_kill_sessions | |||
|
56 | log_user('jsmith', 'jsmith') | |||
|
57 | ||||
|
58 | jsmith = User.find(2) | |||
|
59 | jsmith.firstname = 'Robert' | |||
|
60 | jsmith.save! | |||
|
61 | ||||
|
62 | get '/my/account' | |||
|
63 | assert_response 200 | |||
|
64 | end | |||
|
65 | ||||
|
66 | def test_change_password_generates_a_new_token_for_current_session | |||
|
67 | log_user('jsmith', 'jsmith') | |||
|
68 | assert_not_nil token = session[:tk] | |||
|
69 | ||||
|
70 | get '/my/password' | |||
|
71 | assert_response 200 | |||
|
72 | post '/my/password', :password => 'jsmith', | |||
|
73 | :new_password => 'secret123', | |||
|
74 | :new_password_confirmation => 'secret123' | |||
|
75 | assert_response 302 | |||
|
76 | assert_not_equal token, session[:tk] | |||
|
77 | ||||
|
78 | get '/my/account' | |||
|
79 | assert_response 200 | |||
|
80 | end | |||
|
81 | ||||
|
82 | def test_simultaneous_sessions_should_be_valid | |||
|
83 | first = open_session do |session| | |||
|
84 | session.post "/login", :username => 'jsmith', :password => 'jsmith' | |||
|
85 | end | |||
|
86 | other = open_session do |session| | |||
|
87 | session.post "/login", :username => 'jsmith', :password => 'jsmith' | |||
|
88 | end | |||
|
89 | ||||
|
90 | first.get '/my/account' | |||
|
91 | assert_equal 200, first.response.response_code | |||
|
92 | first.post '/logout' | |||
|
93 | ||||
|
94 | other.get '/my/account' | |||
|
95 | assert_equal 200, other.response.response_code | |||
|
96 | end | |||
|
97 | end |
@@ -51,7 +51,7 class ApplicationController < ActionController::Base | |||||
51 | end |
|
51 | end | |
52 | end |
|
52 | end | |
53 |
|
53 | |||
54 |
before_filter :session_expiration, :user_setup |
|
54 | before_filter :session_expiration, :user_setup, :check_if_login_required, :check_password_change, :set_localization | |
55 |
|
55 | |||
56 | rescue_from ::Unauthorized, :with => :deny_access |
|
56 | rescue_from ::Unauthorized, :with => :deny_access | |
57 | rescue_from ::ActionView::MissingTemplate, :with => :missing_template |
|
57 | rescue_from ::ActionView::MissingTemplate, :with => :missing_template | |
@@ -63,36 +63,23 class ApplicationController < ActionController::Base | |||||
63 | include Redmine::SudoMode::Controller |
|
63 | include Redmine::SudoMode::Controller | |
64 |
|
64 | |||
65 | def session_expiration |
|
65 | def session_expiration | |
66 | if session[:user_id] |
|
66 | if session[:user_id] && Rails.application.config.redmine_verify_sessions != false | |
67 | if session_expired? && !try_to_autologin |
|
67 | if session_expired? && !try_to_autologin | |
68 | set_localization(User.active.find_by_id(session[:user_id])) |
|
68 | set_localization(User.active.find_by_id(session[:user_id])) | |
69 | self.logged_user = nil |
|
69 | self.logged_user = nil | |
70 | flash[:error] = l(:error_session_expired) |
|
70 | flash[:error] = l(:error_session_expired) | |
71 | require_login |
|
71 | require_login | |
72 | else |
|
|||
73 | session[:atime] = Time.now.utc.to_i |
|
|||
74 | end |
|
72 | end | |
75 | end |
|
73 | end | |
76 | end |
|
74 | end | |
77 |
|
75 | |||
78 | def session_expired? |
|
76 | def session_expired? | |
79 | if Setting.session_lifetime? |
|
77 | ! User.verify_session_token(session[:user_id], session[:tk]) | |
80 | unless session[:ctime] && (Time.now.utc.to_i - session[:ctime].to_i <= Setting.session_lifetime.to_i * 60) |
|
|||
81 | return true |
|
|||
82 | end |
|
|||
83 | end |
|
|||
84 | if Setting.session_timeout? |
|
|||
85 | unless session[:atime] && (Time.now.utc.to_i - session[:atime].to_i <= Setting.session_timeout.to_i * 60) |
|
|||
86 | return true |
|
|||
87 | end |
|
|||
88 | end |
|
|||
89 | false |
|
|||
90 | end |
|
78 | end | |
91 |
|
79 | |||
92 | def start_user_session(user) |
|
80 | def start_user_session(user) | |
93 | session[:user_id] = user.id |
|
81 | session[:user_id] = user.id | |
94 | session[:ctime] = Time.now.utc.to_i |
|
82 | session[:tk] = user.generate_session_token | |
95 | session[:atime] = Time.now.utc.to_i |
|
|||
96 | if user.must_change_password? |
|
83 | if user.must_change_password? | |
97 | session[:pwd] = '1' |
|
84 | session[:pwd] = '1' | |
98 | end |
|
85 | end | |
@@ -149,18 +136,6 class ApplicationController < ActionController::Base | |||||
149 | user |
|
136 | user | |
150 | end |
|
137 | end | |
151 |
|
138 | |||
152 | def force_logout_if_password_changed |
|
|||
153 | passwd_changed_on = User.current.passwd_changed_on || Time.at(0) |
|
|||
154 | # Make sure we force logout only for web browser sessions, not API calls |
|
|||
155 | # if the password was changed after the session creation. |
|
|||
156 | if session[:user_id] && passwd_changed_on.utc.to_i > session[:ctime].to_i |
|
|||
157 | reset_session |
|
|||
158 | set_localization |
|
|||
159 | flash[:error] = l(:error_session_expired) |
|
|||
160 | redirect_to signin_url |
|
|||
161 | end |
|
|||
162 | end |
|
|||
163 |
|
||||
164 | def autologin_cookie_name |
|
139 | def autologin_cookie_name | |
165 | Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' |
|
140 | Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' | |
166 | end |
|
141 | end | |
@@ -193,6 +168,7 class ApplicationController < ActionController::Base | |||||
193 | if User.current.logged? |
|
168 | if User.current.logged? | |
194 | cookies.delete(autologin_cookie_name) |
|
169 | cookies.delete(autologin_cookie_name) | |
195 | Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) |
|
170 | Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) | |
|
171 | Token.delete_all(["user_id = ? AND action = ? AND value = ?", User.current.id, 'session', session[:tk]]) | |||
196 | self.logged_user = nil |
|
172 | self.logged_user = nil | |
197 | end |
|
173 | end | |
198 | end |
|
174 | end |
@@ -103,9 +103,8 class MyController < ApplicationController | |||||
103 | @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] |
|
103 | @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] | |
104 | @user.must_change_passwd = false |
|
104 | @user.must_change_passwd = false | |
105 | if @user.save |
|
105 | if @user.save | |
106 | # Reset the session creation time to not log out this session on next |
|
106 | # The session token was destroyed by the password change, generate a new one | |
107 | # request due to ApplicationController#force_logout_if_password_changed |
|
107 | session[:tk] = @user.generate_session_token | |
108 | session[:ctime] = User.current.passwd_changed_on.utc.to_i |
|
|||
109 | flash[:notice] = l(:notice_account_password_updated) |
|
108 | flash[:notice] = l(:notice_account_password_updated) | |
110 | redirect_to my_account_path |
|
109 | redirect_to my_account_path | |
111 | end |
|
110 | end |
@@ -36,7 +36,7 class Token < ActiveRecord::Base | |||||
36 |
|
36 | |||
37 | # Delete all expired tokens |
|
37 | # Delete all expired tokens | |
38 | def self.destroy_expired |
|
38 | def self.destroy_expired | |
39 | Token.where("action NOT IN (?) AND created_on < ?", ['feeds', 'api'], Time.now - validity_time).delete_all |
|
39 | Token.where("action NOT IN (?) AND created_on < ?", ['feeds', 'api', 'session'], Time.now - validity_time).delete_all | |
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | # Returns the active user who owns the key for the given action |
|
42 | # Returns the active user who owns the key for the given action | |
@@ -79,7 +79,15 class Token < ActiveRecord::Base | |||||
79 | # Removes obsolete tokens (same user and action) |
|
79 | # Removes obsolete tokens (same user and action) | |
80 | def delete_previous_tokens |
|
80 | def delete_previous_tokens | |
81 | if user |
|
81 | if user | |
82 |
Token.where(:user_id => user.id, :action => action) |
|
82 | scope = Token.where(:user_id => user.id, :action => action) | |
|
83 | if action == 'session' | |||
|
84 | ids = scope.order(:updated_on => :desc).offset(9).ids | |||
|
85 | if ids.any? | |||
|
86 | Token.delete(ids) | |||
|
87 | end | |||
|
88 | else | |||
|
89 | scope.delete_all | |||
|
90 | end | |||
83 | end |
|
91 | end | |
84 | end |
|
92 | end | |
85 | end |
|
93 | end |
@@ -394,6 +394,26 class User < Principal | |||||
394 | api_token.value |
|
394 | api_token.value | |
395 | end |
|
395 | end | |
396 |
|
396 | |||
|
397 | # Generates a new session token and returns its value | |||
|
398 | def generate_session_token | |||
|
399 | token = Token.create!(:user_id => id, :action => 'session') | |||
|
400 | token.value | |||
|
401 | end | |||
|
402 | ||||
|
403 | # Returns true if token is a valid session token for the user whose id is user_id | |||
|
404 | def self.verify_session_token(user_id, token) | |||
|
405 | return false if user_id.blank? || token.blank? | |||
|
406 | ||||
|
407 | scope = Token.where(:user_id => user_id, :value => token.to_s, :action => 'session') | |||
|
408 | if Setting.session_lifetime? | |||
|
409 | scope = scope.where("created_on > ?", Setting.session_lifetime.to_i.minutes.ago) | |||
|
410 | end | |||
|
411 | if Setting.session_timeout? | |||
|
412 | scope = scope.where("updated_on > ?", Setting.session_timeout.to_i.minutes.ago) | |||
|
413 | end | |||
|
414 | scope.update_all(:updated_on => Time.now) == 1 | |||
|
415 | end | |||
|
416 | ||||
397 | # Return an array of project ids for which the user has explicitly turned mail notifications on |
|
417 | # Return an array of project ids for which the user has explicitly turned mail notifications on | |
398 | def notified_projects_ids |
|
418 | def notified_projects_ids | |
399 | @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id) |
|
419 | @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id) | |
@@ -764,8 +784,8 class User < Principal | |||||
764 | # This helps to keep the account secure in case the associated email account |
|
784 | # This helps to keep the account secure in case the associated email account | |
765 | # was compromised. |
|
785 | # was compromised. | |
766 | def destroy_tokens |
|
786 | def destroy_tokens | |
767 | if hashed_password_changed? |
|
787 | if hashed_password_changed? || (status_changed? && !active?) | |
768 | tokens = ['recovery', 'autologin'] |
|
788 | tokens = ['recovery', 'autologin', 'session'] | |
769 | Token.where(:user_id => id, :action => tokens).delete_all |
|
789 | Token.where(:user_id => id, :action => tokens).delete_all | |
770 | end |
|
790 | end | |
771 | end |
|
791 | end |
@@ -26,6 +26,9 Rails.application.configure do | |||||
26 | # Disable request forgery protection in test environment. |
|
26 | # Disable request forgery protection in test environment. | |
27 | config.action_controller.allow_forgery_protection = false |
|
27 | config.action_controller.allow_forgery_protection = false | |
28 |
|
28 | |||
|
29 | # Disable sessions verifications in test environment. | |||
|
30 | config.redmine_verify_sessions = false | |||
|
31 | ||||
29 | # Print deprecation notices to stderr and the Rails logger. |
|
32 | # Print deprecation notices to stderr and the Rails logger. | |
30 | config.active_support.deprecation = [:stderr, :log] |
|
33 | config.active_support.deprecation = [:stderr, :log] | |
31 |
|
34 |
@@ -185,18 +185,6 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 |
|
||||
200 | def test_change_password_should_redirect_if_user_cannot_change_its_password |
|
188 | def test_change_password_should_redirect_if_user_cannot_change_its_password | |
201 | User.find(2).update_attribute(:auth_source_id, 1) |
|
189 | User.find(2).update_attribute(:auth_source_id, 1) | |
202 |
|
190 |
@@ -17,95 +17,99 | |||||
17 |
|
17 | |||
18 | require File.expand_path('../../test_helper', __FILE__) |
|
18 | require File.expand_path('../../test_helper', __FILE__) | |
19 |
|
19 | |||
20 |
class Session |
|
20 | class SessionsControllerTest < ActionController::TestCase | |
21 | tests AccountController |
|
21 | include Redmine::I18n | |
|
22 | tests WelcomeController | |||
22 |
|
23 | |||
23 | fixtures :users |
|
24 | fixtures :users, :email_addresses | |
24 |
|
25 | |||
25 | def test_login_should_set_session_timestamps |
|
26 | def setup | |
26 | post :login, :username => 'jsmith', :password => 'jsmith' |
|
27 | Rails.application.config.redmine_verify_sessions = true | |
27 | assert_response 302 |
|
|||
28 | assert_equal 2, session[:user_id] |
|
|||
29 | assert_not_nil session[:ctime] |
|
|||
30 | assert_not_nil session[:atime] |
|
|||
31 | end |
|
28 | end | |
32 | end |
|
|||
33 |
|
29 | |||
34 | class SessionsTest < ActionController::TestCase |
|
30 | def teardown | |
35 | include Redmine::I18n |
|
31 | Rails.application.config.redmine_verify_sessions = false | |
36 | tests WelcomeController |
|
32 | end | |
37 |
|
33 | |||
38 | fixtures :users, :email_addresses |
|
34 | def test_session_token_should_be_updated | |
|
35 | created = 10.hours.ago | |||
|
36 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
39 |
|
37 | |||
40 | def test_atime_from_user_session_should_be_updated |
|
38 | get :index, {}, {:user_id => 2, :tk => token.value} | |
41 | created = 2.hours.ago.utc.to_i |
|
|||
42 | get :index, {}, {:user_id => 2, :ctime => created, :atime => created} |
|
|||
43 | assert_response :success |
|
39 | assert_response :success | |
44 | assert_equal created, session[:ctime] |
|
40 | token.reload | |
45 |
assert_ |
|
41 | assert_equal created, token.created_on | |
46 | assert session[:atime] > created |
|
42 | assert_not_equal created, token.updated_on | |
|
43 | assert token.updated_on > created | |||
47 | end |
|
44 | end | |
48 |
|
45 | |||
49 | def test_user_session_should_not_be_reset_if_lifetime_and_timeout_disabled |
|
46 | def test_user_session_should_not_be_reset_if_lifetime_and_timeout_disabled | |
|
47 | created = 2.years.ago | |||
|
48 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
|
49 | ||||
50 | with_settings :session_lifetime => '0', :session_timeout => '0' do |
|
50 | with_settings :session_lifetime => '0', :session_timeout => '0' do | |
51 | get :index, {}, {:user_id => 2} |
|
51 | get :index, {}, {:user_id => 2, :tk => token.value} | |
52 | assert_response :success |
|
52 | assert_response :success | |
53 | end |
|
53 | end | |
54 | end |
|
54 | end | |
55 |
|
55 | |||
56 |
def test_user_session_without_ |
|
56 | def test_user_session_without_token_should_be_reset | |
57 | with_settings :session_lifetime => '720' do |
|
57 | get :index, {}, {:user_id => 2} | |
58 | get :index, {}, {:user_id => 2} |
|
58 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' | |
59 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' |
|
|||
60 | end |
|
|||
61 | end |
|
59 | end | |
62 |
|
60 | |||
63 |
def test_user_session |
|
61 | def test_expired_user_session_should_be_reset_if_lifetime_enabled | |
|
62 | created = 2.days.ago | |||
|
63 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
|
64 | ||||
64 | with_settings :session_timeout => '720' do |
|
65 | with_settings :session_timeout => '720' do | |
65 |
get :index, {}, {:user_id => 2, : |
|
66 | get :index, {}, {:user_id => 2, :tk => token.value} | |
66 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' |
|
67 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' | |
67 | end |
|
68 | end | |
68 | end |
|
69 | end | |
69 |
|
70 | |||
70 |
def test_user_session |
|
71 | def test_valid_user_session_should_not_be_reset_if_lifetime_enabled | |
|
72 | created = 3.hours.ago | |||
|
73 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
|
74 | ||||
71 | with_settings :session_timeout => '720' do |
|
75 | with_settings :session_timeout => '720' do | |
72 |
get :index, {}, {:user_id => 2, : |
|
76 | get :index, {}, {:user_id => 2, :tk => token.value} | |
73 | assert_response :success |
|
77 | assert_response :success | |
74 | end |
|
78 | end | |
75 | end |
|
79 | end | |
76 |
|
80 | |||
77 |
def test_user_session |
|
81 | def test_expired_user_session_should_be_reset_if_timeout_enabled | |
78 | with_settings :session_timeout => '60' do |
|
82 | created = 4.hours.ago | |
79 | get :index, {}, {:user_id => 2} |
|
83 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |
80 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' |
|
|||
81 | end |
|
|||
82 | end |
|
|||
83 |
|
84 | |||
84 | def test_user_session_with_expired_atime_should_be_reset_if_timeout_enabled |
|
|||
85 | with_settings :session_timeout => '60' do |
|
85 | with_settings :session_timeout => '60' do | |
86 |
get :index, {}, {:user_id => 2, : |
|
86 | get :index, {}, {:user_id => 2, :tk => token.value} | |
87 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' |
|
87 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' | |
88 | end |
|
88 | end | |
89 | end |
|
89 | end | |
90 |
|
90 | |||
91 |
def test_user_session |
|
91 | def test_valid_user_session_should_not_be_reset_if_timeout_enabled | |
|
92 | created = 10.minutes.ago | |||
|
93 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
|
94 | ||||
92 | with_settings :session_timeout => '60' do |
|
95 | with_settings :session_timeout => '60' do | |
93 |
get :index, {}, {:user_id => 2, : |
|
96 | get :index, {}, {:user_id => 2, :tk => token.value} | |
94 | assert_response :success |
|
97 | assert_response :success | |
95 | end |
|
98 | end | |
96 | end |
|
99 | end | |
97 |
|
100 | |||
98 | def test_expired_user_session_should_be_restarted_if_autologin |
|
101 | def test_expired_user_session_should_be_restarted_if_autologin | |
|
102 | created = 2.hours.ago | |||
|
103 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
|
104 | ||||
99 | with_settings :session_lifetime => '720', :session_timeout => '60', :autologin => 7 do |
|
105 | with_settings :session_lifetime => '720', :session_timeout => '60', :autologin => 7 do | |
100 | token = Token.create!(:user_id => 2, :action => 'autologin', :created_on => 1.day.ago) |
|
106 | autologin_token = Token.create!(:user_id => 2, :action => 'autologin', :created_on => 1.day.ago) | |
101 | @request.cookies['autologin'] = token.value |
|
107 | @request.cookies['autologin'] = autologin_token.value | |
102 | created = 2.hours.ago.utc.to_i |
|
|||
103 |
|
108 | |||
104 |
get :index, {}, {:user_id => 2, : |
|
109 | get :index, {}, {:user_id => 2, :tk => token.value} | |
105 | assert_equal 2, session[:user_id] |
|
110 | assert_equal 2, session[:user_id] | |
106 | assert_response :success |
|
111 | assert_response :success | |
107 |
assert_not_equal |
|
112 | assert_not_equal token.value, session[:tk] | |
108 | assert session[:ctime] >= created |
|
|||
109 | end |
|
113 | end | |
110 | end |
|
114 | end | |
111 |
|
115 | |||
@@ -114,9 +118,11 class SessionsTest < ActionController::TestCase | |||||
114 | user = User.find(2) |
|
118 | user = User.find(2) | |
115 | user.language = 'fr' |
|
119 | user.language = 'fr' | |
116 | user.save! |
|
120 | user.save! | |
|
121 | created = 4.hours.ago | |||
|
122 | token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created) | |||
117 |
|
123 | |||
118 | with_settings :session_timeout => '60' do |
|
124 | with_settings :session_timeout => '60' do | |
119 |
get :index, {}, {:user_id => user.id, : |
|
125 | get :index, {}, {:user_id => user.id, :tk => token.value} | |
120 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' |
|
126 | assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F' | |
121 | assert_include "Veuillez vous reconnecter", flash[:error] |
|
127 | assert_include "Veuillez vous reconnecter", flash[:error] | |
122 | assert_equal :fr, current_language |
|
128 | assert_equal :fr, current_language |
@@ -30,35 +30,47 class AccountTest < Redmine::IntegrationTest | |||||
30 | assert_template "my/account" |
|
30 | assert_template "my/account" | |
31 | end |
|
31 | end | |
32 |
|
32 | |||
|
33 | def test_login_should_set_session_token | |||
|
34 | assert_difference 'Token.count' do | |||
|
35 | log_user('jsmith', 'jsmith') | |||
|
36 | ||||
|
37 | assert_equal 2, session[:user_id] | |||
|
38 | assert_not_nil session[:tk] | |||
|
39 | end | |||
|
40 | end | |||
|
41 | ||||
33 | def test_autologin |
|
42 | def test_autologin | |
34 | user = User.find(1) |
|
43 | user = User.find(1) | |
35 | Setting.autologin = "7" |
|
|||
36 | Token.delete_all |
|
44 | Token.delete_all | |
37 |
|
45 | |||
38 | # User logs in with 'autologin' checked |
|
46 | with_settings :autologin => '7' do | |
39 | post '/login', :username => user.login, :password => 'admin', :autologin => 1 |
|
47 | assert_difference 'Token.count', 2 do | |
40 | assert_redirected_to '/my/page' |
|
48 | # User logs in with 'autologin' checked | |
41 | token = Token.first |
|
49 | post '/login', :username => user.login, :password => 'admin', :autologin => 1 | |
42 | assert_not_nil token |
|
50 | assert_redirected_to '/my/page' | |
43 | assert_equal user, token.user |
|
51 | end | |
44 | assert_equal 'autologin', token.action |
|
52 | token = Token.where(:action => 'autologin').order(:id => :desc).first | |
45 | assert_equal user.id, session[:user_id] |
|
53 | assert_not_nil token | |
46 | assert_equal token.value, cookies['autologin'] |
|
54 | assert_equal user, token.user | |
47 |
|
55 | assert_equal 'autologin', token.action | ||
48 | # Session is cleared |
|
56 | assert_equal user.id, session[:user_id] | |
49 | reset! |
|
57 | assert_equal token.value, cookies['autologin'] | |
50 | User.current = nil |
|
58 | ||
51 | # Clears user's last login timestamp |
|
59 | # Session is cleared | |
52 | user.update_attribute :last_login_on, nil |
|
60 | reset! | |
53 | assert_nil user.reload.last_login_on |
|
61 | User.current = nil | |
54 |
|
62 | # Clears user's last login timestamp | ||
55 | # User comes back with user's autologin cookie |
|
63 | user.update_attribute :last_login_on, nil | |
56 | cookies[:autologin] = token.value |
|
64 | assert_nil user.reload.last_login_on | |
57 | get '/my/page' |
|
65 | ||
58 | assert_response :success |
|
66 | # User comes back with user's autologin cookie | |
59 | assert_template 'my/page' |
|
67 | cookies[:autologin] = token.value | |
60 | assert_equal user.id, session[:user_id] |
|
68 | get '/my/page' | |
61 | assert_not_nil user.reload.last_login_on |
|
69 | assert_response :success | |
|
70 | assert_template 'my/page' | |||
|
71 | assert_equal user.id, session[:user_id] | |||
|
72 | assert_not_nil user.reload.last_login_on | |||
|
73 | end | |||
62 | end |
|
74 | end | |
63 |
|
75 | |||
64 | def test_autologin_should_use_autologin_cookie_name |
|
76 | def test_autologin_should_use_autologin_cookie_name | |
@@ -69,7 +81,7 class AccountTest < Redmine::IntegrationTest | |||||
69 | Redmine::Configuration.stubs(:[]).with('sudo_mode_timeout').returns(15) |
|
81 | Redmine::Configuration.stubs(:[]).with('sudo_mode_timeout').returns(15) | |
70 |
|
82 | |||
71 | with_settings :autologin => '7' do |
|
83 | with_settings :autologin => '7' do | |
72 | assert_difference 'Token.count' do |
|
84 | assert_difference 'Token.count', 2 do | |
73 | post '/login', :username => 'admin', :password => 'admin', :autologin => 1 |
|
85 | post '/login', :username => 'admin', :password => 'admin', :autologin => 1 | |
74 | assert_response 302 |
|
86 | assert_response 302 | |
75 | end |
|
87 | end | |
@@ -82,7 +94,7 class AccountTest < Redmine::IntegrationTest | |||||
82 | get '/my/page' |
|
94 | get '/my/page' | |
83 | assert_response :success |
|
95 | assert_response :success | |
84 |
|
96 | |||
85 |
assert_difference 'Token.count', - |
|
97 | assert_difference 'Token.count', -2 do | |
86 | post '/logout' |
|
98 | post '/logout' | |
87 | end |
|
99 | end | |
88 | assert cookies['custom_autologin'].blank? |
|
100 | assert cookies['custom_autologin'].blank? | |
@@ -119,7 +131,7 class AccountTest < Redmine::IntegrationTest | |||||
119 | assert_equal 'Password was successfully updated.', flash[:notice] |
|
131 | assert_equal 'Password was successfully updated.', flash[:notice] | |
120 |
|
132 | |||
121 | log_user('jsmith', 'newpass123') |
|
133 | log_user('jsmith', 'newpass123') | |
122 | assert_equal 0, Token.count |
|
134 | assert_equal false, Token.exists?(token.id), "Password recovery token was not deleted" | |
123 | end |
|
135 | end | |
124 |
|
136 | |||
125 | def test_user_with_must_change_passwd_should_be_forced_to_change_its_password |
|
137 | def test_user_with_must_change_passwd_should_be_forced_to_change_its_password |
@@ -36,6 +36,19 class TokenTest < ActiveSupport::TestCase | |||||
36 | assert Token.exists?(t2.id) |
|
36 | assert Token.exists?(t2.id) | |
37 | end |
|
37 | end | |
38 |
|
38 | |||
|
39 | def test_create_session_token_should_keep_last_10_tokens | |||
|
40 | Token.delete_all | |||
|
41 | user = User.find(1) | |||
|
42 | ||||
|
43 | assert_difference 'Token.count', 10 do | |||
|
44 | 10.times { Token.create!(:user => user, :action => 'session') } | |||
|
45 | end | |||
|
46 | ||||
|
47 | assert_no_difference 'Token.count' do | |||
|
48 | Token.create!(:user => user, :action => 'session') | |||
|
49 | end | |||
|
50 | end | |||
|
51 | ||||
39 | def test_destroy_expired_should_not_destroy_feeds_and_api_tokens |
|
52 | def test_destroy_expired_should_not_destroy_feeds_and_api_tokens | |
40 | Token.delete_all |
|
53 | Token.delete_all | |
41 |
|
54 |
General Comments 0
You need to be logged in to leave comments.
Login now