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 +4 -0
- data/features/generators.feature +5 -0
- data/features/step_definitions/simple_steps.rb +22 -0
- data/lib/generators/ixtlan/audit_base.rb +31 -0
- data/lib/generators/ixtlan/audit_model/audit_model_generator.rb +12 -0
- data/lib/generators/ixtlan/audit_scaffold/audit_scaffold_generator.rb +12 -0
- data/lib/ixtlan/audit/audit_rack.rb +21 -0
- data/lib/ixtlan/audit/manager.rb +73 -0
- data/lib/ixtlan/audit/railtie.rb +40 -0
- data/lib/ixtlan/audit/user_logger.rb +59 -0
- data/lib/ixtlan-audit.rb +3 -0
- metadata +129 -0
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,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
|
data/lib/ixtlan-audit.rb
ADDED
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
|
+
|