Bug #4457 » 0001-fixes-4457-Session-fixation-new-session-IDs-are-not-.patch
app/controllers/application_controller.rb | ||
---|---|---|
before_filter :require_ssl, :require_login
|
||
before_filter :set_gettext_locale_db, :set_gettext_locale
|
||
before_filter :session_expiry, :update_activity_time, :unless => proc {|c| c.remote_user_provided? || c.api_request? } if SETTINGS[:login]
|
||
before_filter :session_expiry, :update_activity_time, :unless => proc {|c| !SETTINGS[:login] || c.remote_user_provided? || c.api_request? }
|
||
before_filter :set_taxonomy, :require_mail, :check_empty_taxonomy
|
||
before_filter :welcome, :only => :index, :unless => :api_request?
|
||
before_filter :authorize
|
||
... | ... | |
def session_expiry
|
||
if session[:expires_at].blank? or (session[:expires_at].utc - Time.now.utc).to_i < 0
|
||
# Before we expire the session, save the current taxonomies and the originally
|
||
# requested URL so they can be restored later.
|
||
save_items = session.to_hash.slice("organization_id", "location_id").merge("original_uri" => request.fullpath)
|
||
expire_session
|
||
session.merge!(save_items)
|
||
session[:original_uri] = request.fullpath
|
||
backup_session_content { expire_session }
|
||
end
|
||
rescue => e
|
||
logger.warn "failed to determine if user sessions needs to be expired, expiring anyway: #{e}"
|
||
expire_session
|
||
end
|
||
# Backs up some state from a user's session around a supplied block, which
|
||
# will usually expire or reset the session in some way
|
||
def backup_session_content
|
||
save_items = session.to_hash.slice('organization_id', 'location_id', 'original_uri').symbolize_keys
|
||
yield if block_given?
|
||
session.merge!(save_items)
|
||
end
|
||
def update_activity_time
|
||
session[:expires_at] = Setting[:idle_timeout].minutes.from_now.utc
|
||
end
|
app/controllers/concerns/foreman/controller/authentication.rb | ||
---|---|---|
if user.is_a?(User)
|
||
logger.info("Authorized user #{user.login}(#{user.to_label})")
|
||
User.current = user
|
||
session[:user] = User.current.id unless api_request?
|
||
return User.current.present?
|
||
set_current_user user
|
||
else
|
||
if api_request?
|
||
false
|
||
... | ... | |
(redirect_to @available_sso.login_url and return) unless @available_sso.has_rendered
|
||
end
|
||
end
|
||
else
|
||
# We assume we always have a user logged in, if authentication is disabled, the user is the built-in admin account.
|
||
User.current = User.admin
|
||
session[:user] = User.current.id unless api_request?
|
||
true
|
||
# We assume we always have a user logged in
|
||
# if authentication is disabled, the user is the built-in admin account
|
||
set_current_user User.admin
|
||
end
|
||
end
|
||
... | ... | |
return false
|
||
end
|
||
private
|
||
def sso_authentication
|
||
if available_sso.present?
|
||
if available_sso.authenticated?
|
||
... | ... | |
user
|
||
end
|
||
end
|
||
def set_current_user(user)
|
||
User.current = user
|
||
# API access shouldn't modify the session, its authentication should be
|
||
# stateless. Other successful logins should create new session IDs.
|
||
unless api_request?
|
||
backup_session_content { reset_session }
|
||
session[:user] = user.id
|
||
update_activity_time
|
||
end
|
||
user.present?
|
||
end
|
||
end
|
app/controllers/users_controller.rb | ||
---|---|---|
# Called from the login form.
|
||
# Stores the user id in the session and redirects required URL or default homepage
|
||
def login
|
||
session[:user] = User.current = nil
|
||
session[:locale] = nil
|
||
User.current = nil
|
||
if request.post?
|
||
backup_session_content { reset_session }
|
||
user = User.try_to_login(params[:login]['login'].downcase, params[:login]['password'])
|
||
if user.nil?
|
||
#failed to authenticate, and/or to generate the account on the fly
|
config/routes/test.rb | ||
---|---|---|
if Rails.env.test?
|
||
Foreman::Application.routes.draw do
|
||
resources :testable, :only => :index
|
||
namespace :api do
|
||
resources :testable, :only => :index do
|
||
get :raise_error, :on => :collection
|
test/functional/api/base_controller_subclass_test.rb | ||
---|---|---|
end
|
||
end
|
||
context "API authentication" do
|
||
context "API usage when authentication is disabled" do
|
||
setup do
|
||
User.current = nil
|
||
request.env['HTTP_AUTHORIZATION'] = nil
|
||
SETTINGS[:login] = false
|
||
end
|
||
... | ... | |
SETTINGS[:login] = true
|
||
end
|
||
it "does not need an username and password when Settings[:login]=false" do
|
||
it "does not need a username and password" do
|
||
get :index
|
||
assert_response :success
|
||
end
|
||
... | ... | |
end
|
||
end
|
||
context "API usage when authentication is enabled" do
|
||
setup do
|
||
User.current = nil
|
||
request.env['HTTP_AUTHORIZATION'] = nil
|
||
SETTINGS[:login] = true
|
||
end
|
||
it "requires a username and password" do
|
||
@controller.stubs(:available_sso).returns(nil)
|
||
get :index
|
||
assert_response :unauthorized
|
||
end
|
||
context "and SSO (plain) authenticates" do
|
||
setup do
|
||
@sso = mock('dummy_sso')
|
||
@sso.stubs(:authenticated?).returns(true)
|
||
@sso.stubs(:user).returns(users(:admin).login)
|
||
@controller.stubs(:available_sso).returns(@sso)
|
||
end
|
||
it "doesn't escalate privileges in the session" do
|
||
get :index
|
||
refute session[:user], "session contains user #{session[:user]}"
|
||
end
|
||
end
|
||
end
|
||
context 'errors' do
|
||
test "top level key is error, no metadata included" do
|
||
test "top level key is error, no metadata included" do
|
||
get :raise_error
|
||
assert_equal ['error'], ActiveSupport::JSON.decode(@response.body).keys
|
||
end
|
test/functional/application_controller_subclass_test.rb | ||
---|---|---|
require 'test_helper'
|
||
class ::TestableController < ::ApplicationController
|
||
def index
|
||
render :text => 'dummy', :status => 200
|
||
end
|
||
end
|
||
class TestableControllerTest < ActionController::TestCase
|
||
tests ::TestableController
|
||
context "when authentication is disabled" do
|
||
setup do
|
||
User.current = nil
|
||
SETTINGS[:login] = false
|
||
end
|
||
teardown do
|
||
SETTINGS[:login] = true
|
||
end
|
||
it "does not need a username and password" do
|
||
get :index
|
||
assert_response :success
|
||
end
|
||
end
|
||
context "when authentication is enabled" do
|
||
setup do
|
||
User.current = nil
|
||
SETTINGS[:login] = true
|
||
end
|
||
it "requires a username and password" do
|
||
get :index
|
||
assert_response :redirect
|
||
end
|
||
it "retains original request URI in session" do
|
||
get :index
|
||
assert_equal '/testable', session[:original_uri]
|
||
end
|
||
context "and SSO authenticates" do
|
||
setup do
|
||
@sso = mock('dummy_sso')
|
||
@sso.stubs(:authenticated?).returns(true)
|
||
@sso.stubs(:user).returns(users(:admin).login)
|
||
@controller.stubs(:available_sso).returns(@sso)
|
||
end
|
||
it "sets the session user" do
|
||
get :index
|
||
assert_response :success
|
||
assert_equal users(:admin).id, session[:user]
|
||
end
|
||
it "changes the session ID to prevent fixation" do
|
||
@controller.expects(:reset_session)
|
||
get :index
|
||
end
|
||
it "doesn't escalate privileges in the old session" do
|
||
old_session = session
|
||
get :index
|
||
refute old_session.keys.include?(:user), "old session contains user"
|
||
assert session[:user], "new session doesn't contain user"
|
||
end
|
||
it "retains taxonomy session attributes in new session" do
|
||
get :index, {}, {:location_id => taxonomies(:location1).id,
|
||
:organization_id => taxonomies(:organization1).id,
|
||
:foo => 'bar'}
|
||
assert_equal taxonomies(:location1).id, session[:location_id]
|
||
assert_equal taxonomies(:organization1).id, session[:organization_id]
|
||
refute session[:foo], "session contains 'foo', but should have been reset"
|
||
end
|
||
end
|
||
end
|
||
end
|
test/functional/locations_controller_test.rb | ||
---|---|---|
# session is reset, redirected to login, but org id remains
|
||
assert_redirected_to "/users/login"
|
||
assert_match /Your session has expired, please login again/, flash[:warning]
|
||
assert_equal session["location_id"], taxonomies(:location1).id
|
||
assert_equal session[:location_id], taxonomies(:location1).id
|
||
end
|
||
test "should display a warning if current location has been deleted" do
|
test/functional/organizations_controller_test.rb | ||
---|---|---|
# session is reset, redirected to login, but org id remains
|
||
assert_redirected_to "/users/login"
|
||
assert_match /Your session has expired, please login again/, flash[:warning]
|
||
assert_equal session["organization_id"], taxonomies(:organization1).id
|
||
assert_equal session[:organization_id], taxonomies(:organization1).id
|
||
end
|
||
test "should display a warning if current organization has been deleted" do
|
test/functional/users_controller_test.rb | ||
---|---|---|
assert_response :redirect
|
||
end
|
||
test "#login sets the session user" do
|
||
post :login, {:login => {'login' => users(:admin).login, 'password' => 'secret'}}
|
||
assert_redirected_to hosts_path
|
||
assert_equal users(:admin).id, session[:user]
|
||
end
|
||
test "#login resets the session ID to prevent fixation" do
|
||
@controller.expects(:reset_session)
|
||
post :login, {:login => {'login' => users(:admin).login, 'password' => 'secret'}}
|
||
end
|
||
test "#login doesn't escalate privileges in the old session" do
|
||
old_session = session
|
||
post :login, {:login => {'login' => users(:admin).login, 'password' => 'secret'}}
|
||
refute old_session.keys.include?(:user), "old session contains user"
|
||
assert session[:user], "new session doesn't contain user"
|
||
end
|
||
test "#login retains taxonomy session attributes in new session" do
|
||
post :login, {:login => {'login' => users(:admin).login, 'password' => 'secret'}},
|
||
{:location_id => taxonomies(:location1).id,
|
||
:organization_id => taxonomies(:organization1).id,
|
||
:foo => 'bar'}
|
||
assert_equal taxonomies(:location1).id, session[:location_id]
|
||
assert_equal taxonomies(:organization1).id, session[:organization_id]
|
||
refute session[:foo], "session contains 'foo', but should have been reset"
|
||
end
|
||
end
|
test/lib/foreman/access_permissions_test.rb | ||
---|---|---|
# Apipie
|
||
"apipie/apipies/index", "apipie/apipies/apipie_checksum",
|
||
# API app controller stub
|
||
"api/testable/index", "api/testable/raise_error"
|
||
# App controller stubs
|
||
"testable/index", "api/testable/index", "api/testable/raise_error"
|
||
]
|
||
MAY_SKIP_AUTHORIZED = [ "about/index" ]
|
test/test_helper.rb | ||
---|---|---|
def set_api_user
|
||
return unless self.class.to_s[/api/i]
|
||
@request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(users(:apiadmin).login, "secret")
|
||
set_basic_auth(users(:apiadmin), "secret")
|
||
end
|
||
def set_basic_auth(user, password)
|
||
login = user.is_a?(User) ? user.login : user
|
||
@request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(login, password)
|
||
end
|
||
end
|
||
- « Previous
- 1
- 2
- 3
- 4
- Next »