16.2.1.3. Audit log

16.2.1.3.1. Base class

This is the BaseClass for audit trails

The audit is supposed to work like this. First we need to create an audit object. E.g. this can be done in the before_request:

g.audit_object = getAudit(file_config)

During the request, the g.audit_object can be used to add audit information:

g.audit_object.log({"client": "123.2.3.4", "action": "validate/check"})

Thus, at many different places in the code, audit information can be added to the audit object. Finally, the audit_object needs to be stored to the audit storage. So we call:

g.audit_object.finalize_log()

which creates a signature of the audit data and writes the data to the audit storage.

class privacyidea.lib.auditmodules.base.Audit(config=None, startdate=None)[source]

Create a new audit object.

Parameters:
  • config (dict) – The web config is passed to the audit module, so that the special module implementation can get its configuration.

  • startdate (datetime.datetime) – The datetime of the beginning of the request

Returns:

Audit object

add_policy(policy_names: set | list | str)[source]

This method adds triggered policy names to the list of triggered policies.

Parameters:

policy_names – A set, list or single policy name(s)

Returns:

add_to_log(param, add_with_comma=False)[source]

Add to existing log entry.

Parameters:
  • param

  • add_with_comma – If set to true, new values will be appended comma separated

Returns:

audit_entry_to_dict(audit_entry)[source]

If the search_query returns an iterator with elements that are not a dictionary, the audit module needs to provide this function, to convert the audit entry to a dictionary.

property available_audit_columns
csv_generator(param: dict | None = None, admin_params: dict | None = None, user=None, timelimit: timedelta | None = None)[source]

A generator that can be used to stream the audit log

Parameters:

param

Returns:

finalize_log()[source]

This method is called to finalize the audit_data. I.e. sign the data and write it to the database. It should hash the data and do a hash chain and sign the data

get_audit_id()[source]
get_count(search_dict, timedelta=None, success=None)[source]

Returns the number of found log entries. E.g. used for checking the timelimit.

Parameters:

param – List of filter parameters

Returns:

number of found entries

get_total(param: dict, admin_params: dict | None = None, AND: bool = True, display_error: bool = True, timelimit: timedelta | None = None) int[source]

This method returns the total number of audit entries in the audit store

property has_data
initialize_log(param)[source]

This method initialized the log state. The fact, that the log state was initialized, also needs to be logged. Therefor the same parameters are passed as in the log method.

is_readable = False
log(param)[source]

This method is used to log the data. During a request this method can be called several times to fill the internal audit_data dictionary.

Add new log details in param to the internal log data self.audit_data.

Parameters:

param (dict) – Log data that is to be added

Returns:

None

log_token_num(count)[source]

Log the number of the tokens. Can be passed like log_token_num(get_tokens(count=True))

Parameters:

count (int) – Number of tokens

Returns:

read_keys(pub, priv)[source]

Set the private and public key for the audit class. This is achieved by passing the values:

priv = config.get("privacyideaAudit.key.private")
pub = config.get("privacyideaAudit.key.public")
Parameters:
  • pub (string with filename) – Public key, used for verifying the signature

  • priv (string with filename) – Private key, used to sign the audit entry

Returns:

None

search(search_dict: dict, admin_params: dict | None = None, page_size: int = 15, page: int = 1, sortorder: str = 'asc', timelimit: timedelta | None = None)[source]

This function is used to search audit events.

Parameters:
  • search_dict – Filter parameters that are concatenated with a logical AND

  • admin_params

    Optional admin parameters containing the admin name, admin realm and a list of realms the admin is allowed to see, such as

    {"admin": "admin_name",
     "admin_realm": "realm_of_the_admin",
     "allowed_audit_realms": ["realm1", "realm2"]}
    

  • page_size – Number of entries per page

  • page – The page number

  • sortorder – “asc” - ascending or “desc” - descending

  • timelimit – Only audit entries newer than this timedelta will be searched

search_query(search_dict: dict, admin_params: dict | None = None, page_size: int = 15, page: int = 1, sortorder: str = 'asc', sortname: str = 'number', timelimit: timedelta | None = None)[source]

This function returns the audit log as an iterator on the result

class privacyidea.lib.auditmodules.base.Paginate[source]

This is a pagination object, that is used for searching audit trails.

16.2.1.3.2. SQL Audit module

The SQL Audit Module is used to write audit entries to an SQL database. The SQL Audit Module is configured like this:

PI_AUDIT_MODULE = "privacyidea.lib.auditmodules.sqlaudit"
PI_AUDIT_KEY_PRIVATE = "tests/testdata/private.pem"
PI_AUDIT_KEY_PUBLIC = "tests/testdata/public.pem"
PI_AUDIT_SERVERNAME = "your choice"

Optional:

PI_AUDIT_SQL_URI = "sqlite://"
PI_AUDIT_SQL_TRUNCATE = True | False
PI_AUDIT_SQL_COLUMN_LENGTH = {"user": 60, "info": 10 ...}

If the PI_AUDIT_SQL_URI is omitted the Audit data is written to the token database.

class privacyidea.lib.auditmodules.sqlaudit.Audit(config=None, startdate=None)[source]

This is the SQLAudit module, which writes the audit entries to an SQL database table.

It requires the following configuration parameters in The Config File:

  • PI_AUDIT_KEY_PUBLIC

  • PI_AUDIT_KEY_PRIVATE

If you want to host the SQL Audit database in another DB than the token DB, you can use:

  • PI_AUDIT_SQL_URI and

  • PI_AUDIT_SQL_OPTIONS

With PI_AUDIT_SQL_OPTIONS = {} You can pass options to the DB engine creation. If PI_AUDIT_SQL_OPTIONS is not set, SQLALCHEMY_ENGINE_OPTIONS will be used.

This module also takes the following optional parameters:

  • PI_AUDIT_POOL_SIZE

  • PI_AUDIT_POOL_RECYCLE

  • PI_AUDIT_SQL_TRUNCATE

  • PI_AUDIT_NO_SIGN

  • PI_CHECK_OLD_SIGNATURES

You can use PI_AUDIT_NO_SIGN = True to avoid signing of the audit log.

If PI_CHECK_OLD_SIGNATURES = True old style signatures (text-book RSA) will be checked as well, otherwise they will be marked as FAIL.

Create a new audit object.

Parameters:
  • config (dict) – The web config is passed to the audit module, so that the special module implementation can get its configuration.

  • startdate (datetime.datetime) – The datetime of the beginning of the request

Returns:

Audit object

audit_entry_to_dict(audit_entry)[source]

If the search_query returns an iterator with elements that are not a dictionary, the audit module needs to provide this function, to convert the audit entry to a dictionary.

clear()[source]

Deletes all entries in the database table. This is only used for test cases! :return:

csv_generator(param: dict | None = None, admin_params: dict | None = None, user=None, timelimit: timedelta | None = None)[source]

Returns the audit log as csv file.

Parameters:
  • timelimit – Limit the number of dumped entries by time

  • param – The request parameters

  • admin_params

    Optional admin parameters containing the admin name, admin realm and a list of realms the admin is allowed to see, such as

    {"admin": "admin_name",
     "admin_realm": "realm_of_the_admin",
     "allowed_audit_realms": ["realm1", "realm2"]}
    

  • user – The user, who issued the request

Returns:

None. It yields results as a generator

finalize_log()[source]

This method is used to log the data. It should hash the data and do a hash chain and sign the data

get_count(search_dict, timedelta=None, success=None)[source]

Returns the number of found log entries. E.g. used for checking the timelimit.

Parameters:

param – List of filter parameters

Returns:

number of found entries

get_total(param: dict, admin_params: dict | None = None, AND: bool = True, display_error: bool = True, timelimit: timedelta | None = None) int[source]

This method returns the total number of audit entries in the audit store

is_readable = True
search(search_dict: dict, admin_params: dict | None = None, page_size: int = 15, page: int = 1, sortorder: str = 'asc', timelimit: timedelta | None = None)[source]

This function returns the audit log as a Pagination object.

Parameters:
  • search_dict – Filter parameters that are concatenated with a logical AND

  • admin_params

    Optional admin parameters containing the admin name, admin realm and a list of realms the admin is allowed to see, such as

    {"admin": "admin_name",
     "admin_realm": "realm_of_the_admin",
     "allowed_audit_realms": ["realm1", "realm2"]}
    

  • page_size – Number of entries per page

  • page – The page number

  • sortorder – “asc” - ascending or “desc” - descending

  • timelimit – Only audit entries newer than this timedelta will be searched

search_query(search_dict: dict, admin_params: dict | None = None, page_size: int = 15, page: int = 1, sortorder: str = 'asc', sortname: str = 'number', timelimit: timedelta | None = None)[source]

This function returns the audit log as an iterator on the result

Parameters:
  • search_dict – Filter parameters that are concatenated with a logical AND

  • admin_params

    Optional admin parameters containing the admin name, admin realm and a list of realms the admin is allowed to see, such as

    {"admin": "admin_name",
     "admin_realm": "realm_of_the_admin",
     "allowed_audit_realms": ["realm1", "realm2"]}
    

  • page_size – Number of entries per page

  • page – The page number

  • sortorder – “asc” - ascending or “desc” - descending

  • sortname – The column name to sort after. E.g. “number”, “date”, “user”, …

  • timelimit (timedelta) – Only audit entries newer than this timedelta will be searched

privacyidea.lib.auditmodules.sqlaudit.fn_to_isodate(element, compiler, **kw)[source]
class privacyidea.lib.auditmodules.sqlaudit.to_isodate(*clauses, **kwargs)[source]

Construct a FunctionElement.

Parameters:
  • *clauses – list of column expressions that form the arguments of the SQL function call.

  • **kwargs – additional kwargs are typically consumed by subclasses.

See also

func

Function

inherit_cache = True

Indicate if this HasCacheKey instance should make use of the cache key generation scheme used by its immediate superclass.

The attribute defaults to None, which indicates that a construct has not yet taken into account whether or not its appropriate for it to participate in caching; this is functionally equivalent to setting the value to False, except that a warning is also emitted.

This flag can be set to True on a particular class, if the SQL that corresponds to the object does not change based on attributes which are local to this class, and not its superclass.

See also

compilerext_caching - General guideslines for setting the HasCacheKey.inherit_cache attribute for third-party or user defined SQL constructs.

name = 'to_isodate'

16.2.1.3.3. Container Audit module

The Container Audit Module allows to write audit information to several different audit modules at the same time. E.g. it can write audit information to the SQL Audit Module and to the Logger Audit Module. This way audit information can be saved in the SQL database and at the same time be passed to a file or external services via the Python logging facility.

The Container Audit Module is configured like this:

PI_AUDIT_MODULE = ‘privacyidea.lib.auditmodules.containeraudit’ PI_AUDIT_CONTAINER_WRITE = [‘privacyidea.lib.auditmodules.sqlaudit’,’privacyidea.lib.auditmodules.loggeraudit’] PI_AUDIT_CONTAINER_READ = ‘privacyidea.lib.auditmodules.sqlaudit’

You also have to provide the configuration parameters for the referenced audit modules.

class privacyidea.lib.auditmodules.containeraudit.Audit(config=None, startdate=None)[source]

This is the ContainerAudit module, which writes the audit entries to a list of audit modules.

Create a new audit object.

Parameters:
  • config (dict) – The web config is passed to the audit module, so that the special module implementation can get its configuration.

  • startdate (datetime.datetime) – The datetime of the beginning of the request

Returns:

Audit object

add_policy(policy_names: set | list | str)[source]

Call the add_policy method for all writeable modules

add_to_log(param, add_with_comma=False)[source]

Call the add_to_log method for all writeable modules

csv_generator(param: dict | None = None, admin_params: dict | None = None, user=None, timelimit: timedelta | None = None)[source]

Call the csv_generator method for the one readable module

finalize_log()[source]

Call the finalize method of all writeable audit modules

get_count(search_dict, timedelta=None, success=None)[source]

Call the count method for the one readable module

get_total(param: dict, admin_params: dict | None = None, AND: bool = True, display_error: bool = True, timelimit: timedelta | None = None) int[source]

Call the total method for the one readable module

property has_data
log(param)[source]

Call the log method for all writeable modules

search(search_dict: dict, admin_params: dict | None = None, page_size: int = 15, page: int = 1, sortorder: str = 'asc', timelimit: timedelta | None = None)[source]

Call the search method for the one readable module

16.2.1.3.4. Logger Audit module

The Logger Audit Module is used to write audit entries to the Python logging module.

The Logger Audit Module is configured like this:

PI_AUDIT_MODULE = “privacyidea.lib.auditmodules.loggeraudit” PI_AUDIT_SERVERNAME = “your choice”

PI_LOGCONFIG = “/etc/privacyidea/logging.cfg”

The LoggerAudit Class uses the same PI logging config as you could use anyways. To explicitly write audit logs, you need to add something like the following to the logging.cfg

Example:

[handlers] keys=file,audit

[loggers] keys=root,privacyidea,audit

[logger_audit] handlers=audit qualname=privacyidea.lib.auditmodules.loggeraudit level=INFO

[handler_audit] class=logging.handlers.RotatingFileHandler backupCount=14 maxBytes=10000000 formatter=detail level=INFO args=(‘/var/log/privacyidea/audit.log’,)

class privacyidea.lib.auditmodules.loggeraudit.Audit(config=None, startdate=None)[source]

This is the LoggerAudit module, which writes the audit entries to the Python logging

Note

This audit module does not provide a Read capability.

Create a new audit object.

Parameters:
  • config (dict) – The web config is passed to the audit module, so that the special module implementation can get its configuration.

  • startdate (datetime.datetime) – The datetime of the beginning of the request

Returns:

Audit object

finalize_log()[source]

This method is used to log the data e.g. write the data to a file.