ixtlan-audit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile ADDED
@@ -0,0 +1,4 @@
1
+ h1. Rails Audit Log
2
+
3
+ p. once you have a logged in user in your system, the usual request log can be improved by added the login name of the user to log output. but since you associate data with a "real" person privacy comes into play. the best privacy protection is not to store data, but in our case the compromise is to just define how long the data shall be stored (define an expiration date for the data).
4
+
@@ -0,0 +1,5 @@
1
+ Feature: Generators for Ixtlan Audit
2
+
3
+ Scenario: The slf4r rails template creates a rails application which uses slf4r-wrapper
4
+ Given I create new rails application with template "simple.template"
5
+ Then the output should contain "setup slf4r logger wrapper with ActiveSupport::BufferedLogger"
@@ -0,0 +1,22 @@
1
+ require 'fileutils'
2
+ Given /^I create new rails application with template "(.*)"$/ do |template|
3
+ name = template.sub(/.template$/, '')
4
+ directory = File.join('target', name)
5
+ rails_version = ENV['RAILS_VERSION'] || '3.0.1'
6
+
7
+ ruby = defined?(JRUBY_VERSION) ? "jruby" : "ruby"
8
+ rails_command = "#{ENV['GEM_HOME']}/bin/rails"
9
+ rails_command = "-S rails" unless File.exists?(rails_command)
10
+ command = "#{rails_command} _#{rails_version}_ new #{directory} -f -m templates/#{template}"
11
+ FileUtils.rm_rf(directory)
12
+
13
+ system "#{ruby} #{command}"
14
+
15
+ @result = File.read("target/#{name}/log/development.log")
16
+ puts @result
17
+ end
18
+
19
+ Then /^the output should contain \"(.*)\"$/ do |expected|
20
+ (@result =~ /.*#{expected}.*/).should_not be_nil
21
+ end
22
+
@@ -0,0 +1,31 @@
1
+ require 'rails/generators/base'
2
+ module Ixtlan
3
+ module Generators
4
+ class AuditBase < Rails::Generators::Base
5
+
6
+ argument :name, :type => :string, :required => false
7
+
8
+ protected
9
+ def generator_name
10
+ raise "please overwrite generator_name"
11
+ end
12
+
13
+ public
14
+ def create
15
+ args = []
16
+ if name
17
+ args << ARGV.shift
18
+ else
19
+ args << "audit"
20
+ end
21
+
22
+ args << "created_at:datetime"
23
+ args << "login:string"
24
+ args << "message:string"
25
+ args += ARGV[0, 10000] || []
26
+
27
+ generate generator_name, *args
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ require 'generators/ixtlan/audit_base'
2
+ module Ixtlan
3
+ module Generators
4
+ class AuditModelGenerator < AuditBase
5
+
6
+ protected
7
+ def generator_name
8
+ "model"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'generators/ixtlan/audit_base'
2
+ module Ixtlan
3
+ module Generators
4
+ class AuditScaffoldGenerator < AuditBase
5
+
6
+ protected
7
+ def generator_name
8
+ "scaffold"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Ixtlan
2
+ module Audit
3
+ class AuditRack
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ self.class_eval do
8
+ include Rails.application.routes.url_helpers
9
+ end
10
+ end
11
+
12
+ def call(env)
13
+ result = @app.call(env)
14
+ p audits_path
15
+ ::Rails.application.config.audit_manager.save_all
16
+ result
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,73 @@
1
+ require 'slf4r/logger'
2
+
3
+ module Ixtlan
4
+ module Audit
5
+ class Manager
6
+
7
+ private
8
+
9
+ include ::Slf4r::Logger
10
+
11
+ def list
12
+ Thread.current[:audit] ||= []
13
+ end
14
+
15
+ def model
16
+ @model ||= (::Audit rescue nil)
17
+ end
18
+
19
+ public
20
+
21
+ def initialize
22
+ @username_method = :login
23
+ @keep_log = 90
24
+ end
25
+
26
+ def username_method=(method)
27
+ @username_method = method.to_sym if method
28
+ end
29
+
30
+ def model=(m)
31
+ @model = m if m
32
+ end
33
+
34
+ def keep_log=(days)
35
+ @keep_log = days.to_i
36
+ end
37
+
38
+ def push(message, username)
39
+ list << model.new(:message => message, :login => username) if model
40
+ list.last
41
+ end
42
+
43
+ def save_all
44
+ list.each do |audit|
45
+ audit.save
46
+ end
47
+ list.clear
48
+ end
49
+
50
+ def username_method
51
+ @username_method
52
+ end
53
+
54
+ def daily_cleanup
55
+ if @model
56
+ if(!@last_cleanup.nil? && @last_cleanup < 1.days.ago)
57
+ @last_cleanup = Date.today
58
+ begin
59
+ if defined? ::DataMapper
60
+ @model.all(:date.lt => @keep_log.days.ago).destroy!
61
+ else # ActiveRecord
62
+ @model.all(:conditions => ["date < ?", @keep_log.days.ago]).each(&:delete)
63
+ end
64
+ @logger.info("cleaned audit logs")
65
+ rescue Error
66
+ # TODO log this !!
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,40 @@
1
+ require 'ixtlan/audit/manager'
2
+ require 'ixtlan/audit/audit_rack'
3
+ require 'ixtlan/audit/user_logger'
4
+
5
+
6
+ module Ixtlan
7
+ module Audit
8
+ class Railtie < ::Rails::Railtie
9
+
10
+ config.before_configuration do |app|
11
+ app.config.class.class_eval do
12
+ attr_accessor :audit_manager
13
+ end
14
+ app.config.audit_manager = Manager.new
15
+ ::ActionController::Base.append_after_filter(Ixtlan::Audit::AuditFilter)
16
+ ::ActionController::Base.append_before_filter(Ixtlan::Audit::AuditCleanupFilter)
17
+ app.config.middleware.use Ixtlan::Audit::AuditRack
18
+ end
19
+ end
20
+
21
+ class AuditFilter
22
+
23
+ def self.logger
24
+ @logger ||= UserLogger.new(Rails.application.config.audit_manager)
25
+ end
26
+
27
+ def self.filter(controller)
28
+ logger.log_action(controller)
29
+ end
30
+ end
31
+
32
+
33
+ class AuditCleanupFilter
34
+
35
+ def self.filter(controller)
36
+ Rails.application.config.audit_manager.daily_cleanup
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,59 @@
1
+ require 'slf4r/logger'
2
+
3
+ module Ixtlan
4
+ module Audit
5
+ class UserLogger
6
+
7
+ include ::Slf4r::Logger
8
+
9
+ def initialize(audit_manager)
10
+ @manager = audit_manager
11
+ end
12
+
13
+ private
14
+
15
+ def login_from(controller)
16
+ user = controller.respond_to?(:current_user) ? controller.send(:current_user) : nil
17
+ user.nil? ? nil: user.send(@manager.username_method)
18
+ end
19
+
20
+ public
21
+
22
+ def log(controller, message = nil, &block)
23
+ log_user(login_from(controller), message, &block)
24
+ end
25
+
26
+ def log_action(controller, message = nil)
27
+ log_user(login_from(controller)) do
28
+ as_xml = controller.response.content_type == 'application/xml' ? " - xml" : ""
29
+ if controller.params[:controller]
30
+ audits = controller.instance_variable_get("@#{controller.params[:controller].to_sym}")
31
+ if(audits)
32
+ "#{controller.params[:controller]}##{controller.params[:action]} #{audits.class.name.to_s.pluralize}[#{audits.size}]#{as_xml}#{message}"
33
+ else
34
+ audit = controller.instance_variable_get("@#{controller.params[:controller].singularize.to_sym}")
35
+ if(audit)
36
+ errors = if(audit.respond_to?(:errors) && !audit.errors.empty?)
37
+ " - errors: " + audit.errors.full_messages.join(", ")
38
+ end
39
+ audit_log = audit.respond_to?(:to_log) ? audit.to_log : "#{audit.class.name}(#{audit.id})"
40
+ "#{controller.params[:controller]}##{controller.params[:action]} #{audit_log}#{as_xml}#{message}#{errors}"
41
+ else
42
+ "#{controller.params[:controller]}##{controller.params[:action]}#{as_xml}#{message}"
43
+ end
44
+ end
45
+ else
46
+ "params=#{controller.params.inspect}#{message}"
47
+ end
48
+ end
49
+ end
50
+
51
+ def log_user(user, message = nil, &block)
52
+ user ||= "???"
53
+ msg = "#{message}#{block.call if block}"
54
+ @manager.push( msg, user)
55
+ logger.debug {"[#{user}] #{msg}" }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,3 @@
1
+ if defined?(Rails)
2
+ require 'ixtlan/audit/railtie'
3
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ixtlan-audit
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - mkristian
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-01 00:00:00 +05:30
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 3
29
+ - 0
30
+ - 1
31
+ version: 3.0.1
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 0
44
+ - 1
45
+ version: 2.0.1
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: cucumber
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ - 9
58
+ - 4
59
+ version: 0.9.4
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ - 8
72
+ - 7
73
+ version: 0.8.7
74
+ type: :development
75
+ version_requirements: *id004
76
+ description: audit the controller actions for the current user. log that data into the database and allow to expire this log files (privacy protection) and be able to browse it from the UI
77
+ email:
78
+ - m.kristian@web.de
79
+ executables: []
80
+
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - README.textile
87
+ - features/step_definitions/simple_steps.rb
88
+ - features/generators.feature
89
+ - lib/ixtlan-audit.rb
90
+ - lib/generators/ixtlan/audit_base.rb
91
+ - lib/generators/ixtlan/audit_scaffold/audit_scaffold_generator.rb
92
+ - lib/generators/ixtlan/audit_model/audit_model_generator.rb
93
+ - lib/ixtlan/audit/railtie.rb
94
+ - lib/ixtlan/audit/manager.rb
95
+ - lib/ixtlan/audit/audit_rack.rb
96
+ - lib/ixtlan/audit/user_logger.rb
97
+ has_rdoc: true
98
+ homepage: http://github.com/mkristian/ixtlan-audit
99
+ licenses: []
100
+
101
+ post_install_message:
102
+ rdoc_options:
103
+ - --main
104
+ - README.textile
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project:
124
+ rubygems_version: 1.3.6
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: audit the controller actions for the current user
128
+ test_files: []
129
+