Source code for privacyidea.models.audit

# SPDX-FileCopyrightText: (C) 2025 NetKnights GmbH <https://netknights.it>
# SPDX-FileCopyrightText: (C) 2025 Paul Lettich <paul.lettich@netknights.it>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# This code is free software; you can redistribute it and/or
# modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
# as published by the Free Software Foundation; either
# version 3 of the License, or any later version.
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU AFFERO GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see <http://www.gnu.org/licenses/>.

from datetime import datetime

from sqlalchemy import (
    Integer,
    Sequence,
    Interval,
    Unicode,
    BigInteger,
)
from sqlalchemy.dialects import sqlite
from sqlalchemy.orm import Mapped, mapped_column

from privacyidea.models import db
from privacyidea.models.utils import MethodsMixin

# Use a variant type for sqlite since it does not allow auto-increment with BigInteger type.
# (See https://docs.sqlalchemy.org/en/20/dialects/sqlite.html#allowing-autoincrement-behavior-sqlalchemy-types-other-than-integer-integer)
BigIntegerType = BigInteger()
BigIntegerType = BigIntegerType.with_variant(sqlite.INTEGER(), "sqlite")

audit_column_length = {"signature": 1100,
                       "action": 200,
                       "serial": 40,
                       "token_type": 12,
                       "user": 100,
                       "realm": 255,
                       "resolver": 255,
                       "administrator": 100,
                       "action_detail": 500,
                       "info": 500,
                       "privacyidea_server": 255,
                       "client": 50,
                       "loglevel": 12,
                       "clearance_level": 12,
                       "thread_id": 20,
                       "authentication": 12,
                       "user_agent": 50,
                       "user_agent_version": 20,
                       "policies": 255,
                       "container_serial": 40,
                       "container_type": 100}

AUDIT_TABLE_NAME = 'pidea_audit'


[docs] class Audit(MethodsMixin, db.Model): __tablename__ = AUDIT_TABLE_NAME id: Mapped[int] = mapped_column(BigIntegerType, Sequence("audit_seq", data_type=BigInteger), primary_key=True) date: Mapped[datetime | None] = mapped_column(default=datetime.now, index=True) startdate: Mapped[datetime | None] duration: Mapped[Interval | None] = mapped_column(Interval(second_precision=6)) signature: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("signature")), default="") action: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("action")), default="") success: Mapped[int | None] = mapped_column(Integer, default=0) authentication: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("authentication")), default="") serial: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("serial")), default="") token_type: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("token_type")), default="") container_serial: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("container_serial")), default="") container_type: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("container_type")), default="") user: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("user")), default="", index=True) realm: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("realm")), default="") resolver: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("resolver")), default="") administrator: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("administrator")), default="") action_detail: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("action_detail")), default="") info: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("info")), default="") privacyidea_server: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("privacyidea_server")), default="") client: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("client")), default="") user_agent: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("user_agent")), default="") user_agent_version: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("user_agent_version")), default="") loglevel: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("loglevel")), default="default") clearance_level: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("clearance_level")), default="default") thread_id: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("thread_id")), default="0") policies: Mapped[str | None] = mapped_column(Unicode(audit_column_length.get("policies")), default="")