aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2006-04-07 22:26:25 +0000
committerDavid Heinemeier Hansson <david@loudthinking.com>2006-04-07 22:26:25 +0000
commit47b74e6e160b6fcbd47caeed6c98ae995e180a80 (patch)
tree9336a17b9f4f6517140c4c57d049e655de111391 /actionpack
parentbbbe4247a58a1354d1661f67a1b4d99ad1a96f61 (diff)
downloadrails-47b74e6e160b6fcbd47caeed6c98ae995e180a80.tar.gz
rails-47b74e6e160b6fcbd47caeed6c98ae995e180a80.tar.bz2
rails-47b74e6e160b6fcbd47caeed6c98ae995e180a80.zip
Added ActionController.filter_parameter_logging that makes it easy to remove passwords, credit card numbers, and other sensitive information from being logged when a request is handled #1897 [jeremye@bsa.ca.gov]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4200 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG5
-rwxr-xr-xactionpack/lib/action_controller/base.rb49
-rw-r--r--actionpack/test/controller/filter_params_test.rb42
3 files changed, 95 insertions, 1 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index e332c9b110..873075d492 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,3 +1,8 @@
+*SVN*
+
+* Added ActionController.filter_parameter_logging that makes it easy to remove passwords, credit card numbers, and other sensitive information from being logged when a request is handled #1897 [jeremye@bsa.ca.gov]
+
+
*1.12.1* (April 6th, 2005)
* Fixed that template extensions would be cached development mode #4624 [Stefan Kaes]
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 751f364aa8..5302ee6cad 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -366,6 +366,53 @@ module ActionController #:nodoc:
def hide_action(*names)
write_inheritable_attribute(:hidden_actions, hidden_actions | names.collect { |n| n.to_s })
end
+
+ # Replace sensitive paramater data from the request log.
+ # Filters paramaters that have any of the arguments as a substring.
+ # Looks in all subhashes of the param hash for keys to filter.
+ # If a block is given, each key and value of the paramater hash and all
+ # subhashes is passed to it, the value or key
+ # can be replaced using String#replace or similar method.
+ #
+ # Examples:
+ # filter_parameter_logging
+ # => Does nothing, just slows the logging process down
+ #
+ # filter_parameter_logging :password
+ # => replaces the value to all keys matching /password/i with "[FILTERED]"
+ #
+ # filter_parameter_logging :foo, "bar"
+ # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
+ #
+ # filter_parameter_logging { |k,v| v.reverse! if k =~ /secret/i }
+ # => reverses the value to all keys matching /secret/i
+ #
+ # filter_parameter_logging(:foo, "bar") { |k,v| v.reverse! if k =~ /secret/i }
+ # => reverses the value to all keys matching /secret/i, and
+ # replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
+ def filter_parameter_logging(*filter_words, &block)
+ parameter_filter = Regexp.new(filter_words.collect{ |s| s.to_s }.join('|'), true) if filter_words.length > 0
+
+ define_method(:filter_parameters) do |unfiltered_parameters|
+ filtered_parameters = {}
+
+ unfiltered_parameters.each do |key, value|
+ if key =~ parameter_filter
+ filtered_parameters[key] = '[FILTERED]'
+ elsif value.is_a?(Hash)
+ filtered_parameters[key] = filter_parameters(value)
+ elsif block_given?
+ key, value = key.dup, value.dup
+ yield key, value
+ filtered_parameters[key] = value
+ else
+ filtered_parameters[key] = value
+ end
+ end
+
+ filtered_parameters
+ end
+ end
end
public
@@ -901,7 +948,7 @@ module ActionController #:nodoc:
if logger
logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
logger.info " Session ID: #{@session.session_id}" if @session and @session.respond_to?(:session_id)
- logger.info " Parameters: #{@params.inspect}"
+ logger.info " Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(@params).inspect : @params.inspect}"
end
end
diff --git a/actionpack/test/controller/filter_params_test.rb b/actionpack/test/controller/filter_params_test.rb
new file mode 100644
index 0000000000..5ad0d7f81d
--- /dev/null
+++ b/actionpack/test/controller/filter_params_test.rb
@@ -0,0 +1,42 @@
+require File.dirname(__FILE__) + '/../abstract_unit'
+
+class FilterParamController < ActionController::Base
+end
+
+class FilterParamTest < Test::Unit::TestCase
+ def setup
+ @controller = FilterParamController.new
+ end
+
+ def test_filter_parameters
+ assert FilterParamController.respond_to?(:filter_parameter_logging)
+ assert !@controller.respond_to?(:filter_parameters)
+
+ FilterParamController.filter_parameter_logging
+ assert @controller.respond_to?(:filter_parameters)
+
+ test_hashes = [[{},{},[]],
+ [{'foo'=>'bar'},{'foo'=>'bar'},[]],
+ [{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
+ [{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],
+ [{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'],
+ [{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
+ [{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
+ [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana']]
+
+ test_hashes.each do |before_filter, after_filter, filter_words|
+ FilterParamController.filter_parameter_logging(*filter_words)
+ assert_equal after_filter, @controller.filter_parameters(before_filter)
+
+ filter_words.push('blah')
+ FilterParamController.filter_parameter_logging(*filter_words) do |key, value|
+ value.reverse! if key =~ /bargain/
+ end
+
+ before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
+ after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
+
+ assert_equal after_filter, @controller.filter_parameters(before_filter)
+ end
+ end
+end