Skip to content
Browse files

Merge pull request #1731 from witlessbird/session-timeout

enabled http session expiration in production environment. Notifications do not have affect on session expiration.
  • Loading branch information...
2 parents cd0d8a2 + f02420c commit 78424d07d7d2f106a4f0e17a72623b3dafb83e50 @witlessbird witlessbird committed Apr 4, 2013
View
1 src/config/application.rb
@@ -11,6 +11,7 @@
$LOAD_PATH << path unless $LOAD_PATH.include? path
require 'katello/load_configuration'
require 'katello/logging'
+require 'katello/url_constrained_cookie_store'
# If you have a Gemfile, require the gems listed there, including any gems
View
3 src/config/environments/development.rb
@@ -18,6 +18,9 @@
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
+ # Be sure to restart your server when you modify this file.
+ config.session_store :cookie_store, :key => '_katello_session_development'
+
#support for reloadable Runcible
#config.autoload_paths += %W(#{Rails.root}/../../runcible/lib)
#ActiveSupport::Dependencies.explicitly_unloadable_constants << "::Runcible::Resources"
View
4 src/config/environments/production.rb
@@ -50,6 +50,10 @@
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
+ # Be sure to restart your server when you modify this setting.
+ config.session_store ::Katello::UrlConstrainedCookieStore,
+ :key => '_katello_session', :expire_after => 1.hour, :expiration_exceptions => "/notices"
+
# Do not update compass SASS files in production (we precompile them)
Sass::Plugin.options[:never_update] = true
end
View
10 src/config/initializers/session_store.rb
@@ -1,8 +1,6 @@
# Be sure to restart your server when you modify this file.
-Src::Application.config.session_store :cookie_store, :key => '_src_session'
-
-# Use the database for sessions instead of the cookie-based default,
-# which shouldn't be used to store highly confidential information
-# (create the session table with "rake db:sessions:create")
-# Src::Application.config.session_store :active_record_store
+# This file is not being used to configure Katello session store
+# See environment-specific initialization in
+# config/environments/development.rb and config/environments/production.rb
+# under "config.session_store" key
View
96 src/lib/katello/url_constrained_cookie_store.rb
@@ -0,0 +1,96 @@
+#
+# Copyright 2013 Red Hat, Inc.
+#
+# This software is licensed to you under the GNU General Public
+# License as published by the Free Software Foundation; either version
+# 2 of the License (GPLv2) or (at your option) any later version.
+# There is NO WARRANTY for this software, express or implied,
+# including the implied warranties of MERCHANTABILITY,
+# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
+# have received a copy of GPLv2 along with this software; if not, see
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+
+module Katello::UrlConstrainedCookieStoreV30X
+ # This is almost entirely based on ActionDispatch::Session::AbstractStore#call.
+ # Unfortunately, there isn't a good way not to duplicate all this logic.
+ def call(env)
+ prepare!(env)
+ response = @app.call(env)
+
+ session_data = env[ActionDispatch::Session::AbstractStore::ENV_SESSION_KEY]
+ options = env[ActionDispatch::Session::AbstractStore::ENV_SESSION_OPTIONS_KEY]
+
+ if !session_data.is_a?(ActionDispatch::Session::AbstractStore::SessionHash) || session_data.loaded? || options[:expire_after]
+ session_data.send(:load!) if session_data.is_a?(ActionDispatch::Session::AbstractStore::SessionHash) && !session_data.loaded?
+
+ sid = options[:id] || generate_sid
+ session_data = session_data.to_hash
+
+ value = set_session(env, sid, session_data)
+ return response unless value
+
+ request = ActionDispatch::Request.new(env)
+ cookie = create_cookie(request, value, options)
+ set_cookie(request, cookie.merge!(options))
+ end
+
+ response
+ end
+end
+
+module Katello::UrlConstrainedCookieStoreV32X
+ def commit_session(env, status, headers, body)
+ session = env['rack.session']
+ options = env['rack.session.options']
+
+ if options[:drop] || options[:renew]
+ session_id = destroy_session(env, options[:id] || generate_sid, options)
+ return [status, headers, body] unless session_id
+ end
+
+ return [status, headers, body] unless commit_session?(env, session, options)
+
+ session.send(:load!) unless loaded_session?(session)
+ session = session.to_hash
+ session_id ||= options[:id] || generate_sid
+
+ if not data = set_session(env, session_id, session, options)
+ env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.")
+ elsif options[:defer] and not options[:renew]
+ env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE
+ else
+ cookie = create_cookie(ActionDispatch::Request.new(env), data, options)
+ set_cookie(env, headers, cookie.merge!(options))
+ end
+
+ [status, headers, body]
+ end
+end
+
+class Katello::UrlConstrainedCookieStore < ActionDispatch::Session::CookieStore
+ include Katello::UrlConstrainedCookieStoreV30X if Rails::VERSION::STRING < "3.2"
+ include Katello::UrlConstrainedCookieStoreV32X if Rails::VERSION::STRING >= "3.2"
+
+ DEFAULT_OPTIONS.merge!(:expiration_exceptions => nil)
+
+ def expiration_exceptions(options)
+ exceptions = options[:expiration_exceptions] or []
+ exceptions.instance_of?(Array) ? exceptions : [exceptions]
+ end
+
+ def create_cookie(request, cookie_data, options)
+ cookie = Hash.new
+ cookie[:value] = cookie_data
+ if options[:expire_after]
+ cookie[:value]['created_at'] ||= Time.now
+ if expiration_exceptions(options).any? { |e| request.fullpath.include?(e) }
+ cookie[:expires] = cookie[:value]['created_at'] + options[:expire_after]
+ else
+ cookie[:value]['created_at'] = Time.now
+ cookie[:expires] = cookie[:value]['created_at'] + options[:expire_after]
+ end
+ end
+
+ cookie
+ end
+end
View
102 src/test/lib/url_constrained_cookie_store_test.rb
@@ -0,0 +1,102 @@
+#
+# Copyright 2013 Red Hat, Inc.
+#
+# This software is licensed to you under the GNU General Public
+# License as published by the Free Software Foundation; either version
+# 2 of the License (GPLv2) or (at your option) any later version.
+# There is NO WARRANTY for this software, express or implied,
+# including the implied warranties of MERCHANTABILITY,
+# NON-INFRINGEMENT, or FITNESS FOR A PARTICULAR PURPOSE. You should
+# have received a copy of GPLv2 along with this software; if not, see
+# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+
+require 'securerandom'
+require 'time'
+require 'minitest_helper'
+require File.expand_path('../../../lib/katello/url_constrained_cookie_store', __FILE__)
+
+class UrlConstrainedCookieStoreTest < ActionController::IntegrationTest
+ SessionKey = '_test_session'
+ SessionSecret = '16a7078c778fb1e28d062c6d1a26e864'
+
+ Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
+ SignedBar = Verifier.generate(:foo => "bar", :created_at => (Time.now - 2.minute),
+ :session_id => SecureRandom.hex(16))
+
+ def test_doesnt_update_expiraton_date_for_excluded_urls
+ with_test_route_set(:expire_after => 1.minute, :expiration_exceptions => "/no_expiration") do
+ cookies[SessionKey] = SignedBar
+ get '/no_expiration'
+ assert_response :success
+ assert /expires=(.+)\;/ =~ headers['Set-Cookie']
+ assert Time.parse($1) < Time.now
+ end
+ end
+
+ def test_updates_expiraton_date
+ with_test_route_set(:expire_after => 1.minute, :expiration_exceptions => "/no_expiration") do
+ cookies[SessionKey] = SignedBar
+ get '/with_expiration'
+ assert_response :success
+ assert /expires=(.+)\;/ =~ headers['Set-Cookie']
+ assert Time.parse($1) > Time.now
+ end
+ end
+
+ def get(path, parameters = nil, env = {})
+ env["action_dispatch.secret_token"] ||= SessionSecret
+ super
+ end
+
+ class TestController < ActionController::Base
+ def no_expiration
+ render :text => session[:session_id]
+ end
+
+ def with_expiration
+ render :text => session[:session_id]
+ end
+ end
+
+ def with_test_route_set(options = {})
+ with_routing do |set|
+ set.draw do
+ match ':action', :to => ::UrlConstrainedCookieStoreTest::TestController
+ end
+
+ options = { :key => SessionKey }.merge!(options)
+
+ @app = build_app(set) do |middleware|
+ middleware.use ::Katello::UrlConstrainedCookieStore, options
+ middleware.delete "ActionDispatch::ShowExceptions"
+ end
+
+ yield
+ end
+ end
+
+ def build_app(routes = nil)
+ RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
+ middleware.use "ActionDispatch::ShowExceptions"
+ middleware.use "ActionDispatch::Callbacks"
+ middleware.use "ActionDispatch::ParamsParser"
+ middleware.use "ActionDispatch::Cookies"
+ middleware.use "ActionDispatch::Flash"
+ middleware.use "ActionDispatch::Head"
+ yield(middleware) if block_given?
+ end
+ end
+end
+
+class RoutedRackApp
+ attr_reader :routes
+
+ def initialize(routes, &blk)
+ @routes = routes
+ @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
+ end
+
+ def call(env)
+ @stack.call(env)
+ end
+end

0 comments on commit 78424d0

Please sign in to comment.
Something went wrong with that request. Please try again.