1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
# frozen-string-literal: true
module Rodauth
Feature.define(:audit_logging, :AuditLogging) do
auth_value_method :audit_logging_account_id_column, :account_id
auth_value_method :audit_logging_message_column, :message
auth_value_method :audit_logging_metadata_column, :metadata
auth_value_method :audit_logging_table, :account_authentication_audit_logs
auth_value_method :audit_log_metadata_default, nil
auth_methods(
:add_audit_log,
:audit_log_insert_hash,
:audit_log_message,
:audit_log_message_default,
:audit_log_metadata,
:serialize_audit_log_metadata,
)
configuration_module_eval do
[:audit_log_message_for, :audit_log_metadata_for].each do |method|
define_method(method) do |action, value=nil, &block|
block ||= proc{value}
meth = :"#{method}_#{action}"
@auth.send(:define_method, meth, &block)
@auth.send(:private, meth)
end
end
end
def hook_action(hook_type, action)
super
# In after_logout, session is already cleared, so use before_logout in that case
if (hook_type == :after || action == :logout) && (id = account ? account_id : session_value)
add_audit_log(id, action)
end
end
def add_audit_log(account_id, action)
if hash = audit_log_insert_hash(account_id, action)
audit_log_ds.insert(hash)
end
end
def audit_log_insert_hash(account_id, action)
if message = audit_log_message(action)
{
audit_logging_account_id_column => account_id,
audit_logging_message_column => message,
audit_logging_metadata_column => serialize_audit_log_metadata(audit_log_metadata(action))
}
end
end
def serialize_audit_log_metadata(metadata)
metadata.to_json unless metadata.nil?
end
def audit_log_message_default(action)
action.to_s
end
def audit_log_message(action)
meth = :"audit_log_message_for_#{action}"
if respond_to?(meth, true)
send(meth)
else
audit_log_message_default(action)
end
end
def audit_log_metadata(action)
meth = :"audit_log_metadata_for_#{action}"
if respond_to?(meth, true)
send(meth)
else
audit_log_metadata_default
end
end
private
def audit_log_ds
ds = db[audit_logging_table]
# :nocov:
if db.database_type == :postgres
# :nocov:
# For PostgreSQL, use RETURNING NULL. This allows the feature
# to be used with INSERT but not SELECT permissions on the
# table, useful for audit logging where the database user
# the application is running as should not need to read the
# logs.
ds = ds.returning(nil)
end
ds
end
end
end
|