Permalink
Browse files

support for selective (based on url accessed) expiration of cookies

  • Loading branch information...
1 parent d1abcb5 commit c668f232e06d2d71aced0ea1066f8bbbe278e675 @witlessbird witlessbird committed Mar 18, 2013
@@ -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
@@ -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"
@@ -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 :url_constrained_cookie_store,
+ :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
@@ -1,6 +1,5 @@
# Be sure to restart your server when you modify this file.
-
-Src::Application.config.session_store :cookie_store, :key => '_src_session', :expire_after => 1.hour
+#Src::Application.config.session_store :cookie_store, :key => '_katello_session', :expire_after => 1.hour
# Use the database for sessions instead of the cookie-based default,
# which shouldn't be used to store highly confidential information
@@ -0,0 +1,54 @@
+#
+# 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.
+
+class Katello::UrlConstrainedCookieStore < ActionDispatch::Session::CookieStore
+ DEFAULT_OPTIONS.merge!(:expiration_exceptions => nil)
+
+ def call(env)
+ prepare!(env)
+ response = @app.call(env)
+
+ session_data = env[ENV_SESSION_KEY]
+ options = env[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 = { :value => value }
+ unless options[:expire_after].nil?
+ cookie[:value]['created_at'] ||= Time.now
+ if expiration_exceptions(options).any? { |e| Regexp.new(e).match(request.fullpath) }
+ cookie[:expires] = cookie[:value]['created_at'] + options.delete(:expire_after)
+ else
+ cookie[:value]['created_at'] = Time.now
+ cookie[:expires] = cookie[:value]['created_at'] + options.delete(:expire_after)
+ end
+ end
+
+ set_cookie(request, cookie.merge!(options))
+ end
+
+ response
+ end
+
+ def expiration_exceptions(options)
+ exceptions = options.delete(:expiration_exceptions) or []
+ exceptions.instance_of?(Array) ? exceptions : [exceptions]
+ end
+end
@@ -0,0 +1,100 @@
+#
+# 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 'time'
+require 'minitest_helper'
+require File.expand_path('../../../lib/katello/url_constrained_cookie_store', __FILE__)
+
+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
+
+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 => ActiveSupport::SecureRandom.hex(16))
+
+ class TestController < ActionController::Base
+ def no_expiration
+ render :text => session[:session_id]
+ end
+
+ def with_expiration
+ render :text => session[:session_id]
+ end
+ end
+
+ 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
+ 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
+
+ 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

0 comments on commit c668f23

Please sign in to comment.