17.3.1. The database model¶
- class privacyidea.models.Admin(**kwargs)[source]¶
The administrators for managing the system. To manage the administrators use the command pi-manage.
In addition, certain realms can be defined to be administrative realms.
- Parameters:
username (basestring) – The username of the admin
password (basestring) – The password of the admin (stored using PBKDF2, salt and pepper)
email (basestring) – The email address of the admin (not used at the moment)
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Audit(**kwargs)[source]¶
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.AuthCache(username, realm, resolver, authentication, first_auth=None, last_auth=None)[source]¶
- class privacyidea.models.AuthenticationLog(**kwargs)[source]¶
Append-only log of authentication events: every authenticated HTTP request produces a row, and normally exactly one (a
push_waitrequest writes two, since it triggers the challenge and awaits the answer within the one request). Several rows may share atransaction_idto correlate the multiple requests of one logical authentication attempt (e.g. a challenge trigger and its later response) at query time. Rows of one logical attempt - including a multi-challenge flow where answering one challenge triggers another - share anattempt_id; ordering an attempt’s rows by(timestamp, id)reconstructs the full chain, and each row’s owntransaction_idstill links back to the challenge table.timestampleads that order rather thanid, and carries microsecond precision for it, becauseidis a plain autoincrement: it is the insertion order of a single writer only. A multi-master cluster (Galera withwsrep_auto_increment_control) gives each node its own offset and applies remote writes asynchronously, so a row committed later on one node can carry a loweridthan one committed earlier on another - which would let a counted failure vanish or a counter reset be missed.timestampis generated by the application, so it orders across writer nodes;idstays the tiebreaker and is exact for the rows of one flush. The residual limit is the clock offset between privacyIDEA instances: events that fall within it are ordered byid, i.e. arbitrarily - which is no worse than they are distinguishable.The client of a request is recorded as what was decided and how it was decided:
source_ipis the effective client IP - the one authorization is evaluated against and the only one the conditional-access engine counts and enforces on. It is unchanged by the provenance columns below.peer_ipis the TCP peer the request actually arrived from (request.remote_addr), which is the same address unless a proxy mapping moved it. It is indexed, because “what came from this machine” is the second question a forensic query asks.source_ip_sourcenames wheresource_ipwas taken from, as aClientIpSourcevalue.REMOTE_ADDR_UNMAPPEDis deliberately distinct fromREMOTE_ADDR: the peer was used despite anOverrideAuthorizationClientbeing configured.ip_chainis the whole path that was considered, recorded even when no override is configured and theX-Forwarded-Forheader is therefore ignored - recording what a request claimed is not trusting it. Everything pastpeer_ipis client-supplied and must never gate a decision.client_labelis theclient_idparameter or the User-Agent, andclient_label_sourcesays which.
NULL in any of the four provenance columns means the row predates them, and nothing may be inferred from it - in particular a NULL
source_ip_sourcemust never be rendered as “direct connection”.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- property aware_timestamp: datetime¶
Return
timestampas a timezone-aware UTC datetime.The column itself is stored as a naive datetime because timezone-aware DateTime columns are not portable across all supported databases (they are ignored or handled differently per backend). We therefore store UTC and re-attach the timezone on read.
- to_dict(include_outcomes: bool = False, include_reasons: bool = False) dict[source]¶
Serialize the entry for the API response, with the timestamp as an ISO-8601 UTC string.
include_outcomes adds the conditional-access history of this request as
conditional_access_outcomes. It is off by default and only the paginated listing turns it on, because the relationship islazy="raise": reading it on an entry that was not loaded with its outcomes must fail loudly rather than emit a query per entry.include_reasons adds the classified reasons as the
reasonslist, in the order they were recorded, under the same rule and for the same reason: that relationship islazy="raise"too.
- class privacyidea.models.AuthenticationLogReason(**kwargs)[source]¶
Why an authentication-log row came out the way it did: one row per
AuthEventReasonthe request produced, in the order the vocabulary declares them (seeorder_request_reasons()) as their ids ascend.A request rarely fails for exactly one reason - a user with three tokens can have one revoked, one past its failcount and one that simply got the wrong OTP - so the reasons are a list, and no reason is picked over another: each is recorded and each is filterable on its own. Kept in a table of its own rather than as a column on the parent for the reason the parent’s column existed at all: “every NO_USABLE_TOKEN caused by the failcounter” has to be a plain indexed predicate, and neither a separator-joined string (
LIKEscans, a length limit) nor a JSON array (predicates differ per backend) offers one. What is specific to one request - the deciding policy’s name, which serial failed for which reason - still stays in the parent’sother_info.Like
ConditionalAccessOutcome, a row belongs to itsauthentication_logrow (auth_log_id, a real foreign key that cascades), is only ever read together with it - viaselectinload, never aJOIN, which would multiply the parent row and break bothLIMITand the pagination count - and repeats nothing the parent already holds.Deliberately without
MethodsMixin, for the reason the outcome model is: the mixin’ssave()/delete()commitdb.session, while these rows are written on the conditional-access session so that a failure to record them cannot roll back the request’s own work.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.BlockList(**kwargs)[source]¶
A blocked source identity (currently a source IP), written by the
BLOCK_IPconditional-access action and consulted by the authentication pre-check on the next inbound request — exactly the live-state pattern ofUserLockState, but keyed by the request’s source IP rather than by the user.The IP is the natural primary key.
block_expires_atis the load-bearing field: a row exists only while the IP is blocked, and a row whoseblock_expires_atlies in the future means the IP is currently blocked, while aNULLvalue means a permanent block (only an admin reset, which deletes the row, clears it). Timestamps are naive UTC, seeutc_now().Like
UserLockStatethe row records the block itself, not which policy produced it; that is the conditional-access history (ConditionalAccessOutcome). It does recordblock_cause, i.e. whether a policy or an administrator imposed the block now in force.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.CAConnector(name, catype)[source]¶
The table “caconnector” contains the names and types of the defined CA connectors. Each connector has a different configuration, that is stored in the table “caconnectorconfig”.
- class privacyidea.models.CAConnectorConfig(caconnector_id=None, Key=None, Value=None, caconnector=None, Type='', Description='')[source]¶
Each CAConnector can have multiple configuration entries. Each CA Connector type can have different required config values. Therefore, the configuration is stored in simple key/value pairs. If the type of config entry is set to “password” the value of this config entry is stored encrypted.
The config entries are referenced by the id of the resolver.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Challenge(**kwds)[source]¶
Table for handling of the generic challenges.
- property data¶
Return the decrypted challenge data as a JSON string, or empty string.
- property encrypted_data: str¶
Return the stored ciphertext of
data, without decrypting it.For a caller that has to persist the very same value somewhere else - the Redis cache stores this challenge instead of the row - so that it does not have to decrypt and re-encrypt what is already encrypted here.
- get(timestamp=False)[source]¶
return a dictionary of all vars in the challenge class
- Parameters:
timestamp (bool) – if true, the timestamp will be returned in a readable format like “2014-11-29 21:56:43.057293”
- Returns:
dict of vars
- get_data() dict[source]¶
Get the decrypted challenge data as a dict.
- Returns:
The challenge data as a dict. Returns
{}if no data is stored.- Return type:
dict
- get_otp_status()[source]¶
This returns how many OTPs were already received for this challenge. and if a valid OTP was received.
- Returns:
tuple of count and True/False
- Return type:
tuple
- is_open() bool[source]¶
Returns true if the challenge can still be answered: it is not expired, has not been answered yet, and has not been refused (declined or cancelled). This is the guard the answering endpoints use before mutating a challenge.
- Returns:
True if the challenge is still open
- Return type:
bool
- class privacyidea.models.Client(**kwargs)[source]¶
The clients table holds API clients that authenticate against privacyIDEA with an API key (sent in the
X-API-Keyheader). Each client represents an external integration such as a Windows credential provider, a Keycloak plugin or an Entra ID connector.An API key has the form
<prefix>_<key_id>_<secret>. Thekey_idis a non-secret, unique identifier that is stored in plaintext and used to look up the client; only thesecrethalf is hashed intokey_hash. This way the plaintext key is never stored, the lookup is a direct indexed match onkey_id(no scanning), and the publicly shownkey_idreveals nothing about the secret.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ClientApplication(**kwargs)[source]¶
This table stores the clients, which sent an authentication request to privacyIDEA. This table is filled automatically by authentication requests.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ClientStatus(value, names=<not given>, *values, module=None, qualname=None, type=None, start=1, boundary=None)[source]¶
The states a client may be in. Only
ACTIVEclients can authenticate;SUSPENDEDis a reversible off-switch. Permanent removal is a delete, and a compromised key is handled by rotation - so there is deliberately no separate “revoked” state.Inherits from
strso members compare equal to their plain string value (e.g.ClientStatus.ACTIVE == "active") and serialise to it in JSON.
- class privacyidea.models.ConditionalAccessOutcome(**kwargs)[source]¶
History of what conditional access did: one row per action the engine executed for one request, plus dry-run rows recording what a dry-run policy would have done.
This is the queryable counterpart of the live state in
user_lock_stateandblock_list, which show the restriction currently in force and then forget it. Only this table can answer “when was this user locked, by which policy, and for how long”.Each row belongs to the
authentication_logrow of the request that caused it (auth_log_id, mandatory) and is only ever read together with it. The table therefore holds only what it alone knows: the subject (resolver, uid, realm, username, source IP) and when it happened are on the parent row and are not repeated here. Using the parent’stimestampis exact enough by construction - the engine evaluates a request against a single reference instant, so every outcome of one request shares it, a few milliseconds after the row itself was written.“Read together with” is a batched second
SELECT(selectinload), not aJOIN: the log listing pages the parent rows and then fetchesWHERE auth_log_id IN (<the page's ids>). A join would multiply each parent row by its outcomes and break bothLIMITand the pagination count.Nothing on the authentication path ever reads this table - the engine counts over
authentication_logand writes outcomes without reading them back - so the relationship that exposes them is declaredlazy="raise"and only the paginated log query opts in.The policy is identified by name only, denormalized, with no id and no foreign key: an outcome must survive the deletion of the policy that produced it, and a stored
policy_idcould not be acted on afterwards. Ids are not reused on PostgreSQL or Oracle (a sequence), but SQLite hands outmax(rowid)+1and MySQL/MariaDB recompute theAUTO_INCREMENTcounter asmax(id)+1on restart (MySQL persists it only from 8.0), so a deleted policy’s id can turn up on a different policy - and finding the logged id on a policy with another name is indistinguishable from a rename, which is the one case an id was worth keeping for. Matching on the name an admin chose can at worst hit a policy deliberately recreated under that name; matching on a recycled surrogate key attributes history to a policy that never produced it.Whether the policy still exists is therefore a lookup by name (unique on
conditional_access_policies).auth_log_id, in contrast, is a real foreign key and cascades: the history of a request is deleted with the request.There is deliberately no stage id:
update_conditional_access_policy()replaces a policy’s stages as a whole, so every edit gives them fresh ids and a stored one would dangle. The stage is identified by its natural key instead: a stage is unique per policy by its threshold (uq_ca_stage_policy_threshold) and that survives edits, and the threshold is what a human reads anyway.Everything a triggered stage knows is therefore mandatory -
policy_name,threshold,event_count- because the engine always has all three when it records an outcome. Only two columns are nullable, each meaning something:stage_name(the admin never named the stage) andinfo(the action had nothing of its own to record).The string columns use
case_sensitive_unicode()for the same reason the authentication log does: matching must behave identically on every backend. MySQL/MariaDB’s server-default collation is typically case-insensitive (*_ci) while SQLite, PostgreSQL and Oracle compare case-sensitively, so an unpinned column would makeaction_type == "lock_user"match on one database and not on another.Deliberately without
MethodsMixin, unlike its sibling models: the mixin’ssave()anddelete()commitdb.session, and an outcome must be written on the conditional-access session so that a failure to record history cannot roll back the request’s own work. Rows are created byrecord_outcomes()and removed with their parent by the authentication log’s delete paths; not offering the two methods is cheaper than documenting that they are wrong.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- to_dict() dict[source]¶
Serialize the outcome for the API response.
Every column is emitted, including the ones the WebUI does not display (
info,event_count): what to show is the view’s decision, and a client querying the history needs the rest. There is no timestamp of its own - the entry this is nested under carries it.
- class privacyidea.models.ConditionalAccessPolicy(**kwargs)[source]¶
Container for a set of conditional-access lock rules.
A policy defines which failure counter(s) to track (e.g.
MFA_FAIL,PASSWORD_FAIL) within a sliding time window. The tracked types live in the relatedConditionalAccessPolicyCounterTyperows;counter_types_to_trackis the list-of-strings view over them used throughout the code and tests (assignable as a plain list). Their events are counted together (a single combined count over all listed types) against the stage thresholds, andreset_on_successdecides whether a completed login clears what has been counted so far. Admins can define multiple policies (e.g. “Admin Policy” vs “Default User Policy”); policies are evaluated by ascendingpriority(a lower number means higher precedence, matching privacyIDEA’s policy engine). Thepriorityis unique across policies so the evaluation order - and thus which policy wins an allow/deny decision - is always unambiguous.The actual thresholds and reactions live in the related
ConditionalAccessPolicyStageandConditionalAccessStageActionrows, and the relatedConditionalAccessPolicyConditionrows restrict to whom the policy applies at all.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ConditionalAccessPolicyCondition(**kwargs)[source]¶
One restriction on which requests a
ConditionalAccessPolicyapplies to, e.g. “only for users of the realms sales and support” or “not for admins”.This is the applicability axis, orthogonal to the counting one: conditions decide whether a policy is evaluated for a request, while the counter types, the count mode and the stage thresholds decide what trips it. Keeping them separate is what lets the two compose - a policy can restrict itself to a realm and still require a threshold of failures.
All of a policy’s conditions must match (AND); a policy with no conditions applies to everyone, which is why adding this table leaves existing policies behaving exactly as before.
The row is deliberately generic so a new kind of condition is a new
condition_typein the registry rather than a schema change:condition_typenames what to read from the request context (e.g.USER_REALM,USER_ROLE). A policy carries at most one condition of each type, enforced by the unique constraint: two conditions on the same value could only narrow to a contradiction, since they are ANDed.operatornames how to compare, and determines the shape ofvalue: a list for the set-membership operators (IN/NOT_IN), a scalar for future comparison operators,NULLfor future zero-arity ones.valueis JSON rather than a normalized child table because nothing filters on it in SQL - conditions are evaluated in Python against the request context - so normalizing would only add a join.
A condition type with an open key space (an HTTP header name, a userinfo attribute) would need a
keycolumn alongsidecondition_type, and the unique constraint widened to include it. None of the types defined today is keyed, so the column is deliberately absent rather than carried empty; adding it later is a column plus a constraint rebuild.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ConditionalAccessPolicyCounterType(**kwargs)[source]¶
One failure counter type tracked by a
ConditionalAccessPolicy, normalized out of the formercounter_types_to_trackJSON column.A policy has one row here per tracked
AuthEventTypevalue. Keeping the types in their own indexed table lets the authentication hot path select just the policies that track the current event type with a single equality filter, instead of loading every enabled policy and filtering the JSON list in Python (which grew the per-request DB work with the total policy count).A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ConditionalAccessPolicyStage(**kwargs)[source]¶
A failure threshold within a
ConditionalAccessPolicy. Each policy has N stages (e.g. 5, 10 and 15 failures).Post-response, each of a stage’s actions fires when the failure count reaches the stage’s
failure_threshold(seeConditionalAccessStageAction.retrigger_above_thresholdfor the per-action fire-once vs re-trigger choice); escalation is expressed as separate stages per threshold. Stages are evaluated by descendingfailure_threshold, so the most severe matching stage is the one that acts (and, on the pre-auth path, the one that supplies the DENY verdict). The threshold is unique per policy, so that order is total and needs nothing else configured.A threshold counts failures and therefore starts at 1; the CRUD layer allows 0 only on a stage whose every action is
DENY, the unconditional lockdown idiom.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.ConditionalAccessStageAction(**kwargs)[source]¶
What to do when a
ConditionalAccessPolicyStageis triggered. One stage can have multiple actions (e.g. lock the user and email the admin).action_valueis the action-specific payload, stored as JSON: the restriction duration in seconds forLOCK_USER/BLOCK_IP, the SMTP settings object (smtp_identifier,subject,body, …) forEMAIL_ADMIN/EMAIL_USER, and nothing at all for thePERMANENT_*restrictions and theDENYdecision. The authoritative per-action contract - what the engine reads, and what the write path therefore rejects - is_ACTION_VALUE_VALIDATORS.retrigger_above_thresholdcontrols how this action fires as the failure count crosses its stage’s threshold. False: fire once, when the count equals the threshold exactly. True: keep firing while the count stays at or above the threshold and below the next stage’s, so escalation ends it for good (the classic re-triggering lock; de-dup still throttles repeats within one incident). Because it is per action, one stage can e.g. email once at its threshold while re-triggering the user lock. The CRUD layer picks an action-aware default when the client omits it (the DENY decision defaults to True, the lock/email/block effects to False); see_validate_stages()and_action_fires().A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Config(Key, Value, Type='', Description='')[source]¶
The config table holds all the system configuration in key value pairs. Additional configuration for realms, resolvers and machine resolvers is stored in specific tables.
- class privacyidea.models.CustomUserAttribute(user_id, resolver, realm_id, Key, Value, Type=None)[source]¶
The table “customuserattribute” is used to store additional, custom attributes for users.
A user is identified by the user_id, the resolver_id and the realm_id.
The additional attributes are stored in Key and Value. The Type can hold extra information like e.g. an encrypted value / password.
- Note: Since the users are external, i.e. no objects in this database,
there is no logic reference on a database level. Since users could be deleted from user stores without privacyIDEA realizing that, this table could pile up with remnants of attributes.
Create a new customuserattribute for a user tuple
- class privacyidea.models.EventCounter(name, value=0, node='')[source]¶
This table stores counters of the event handler “Counter”.
Note that an event counter name does not correspond to just one, but rather several table rows, because we store event counters for each privacyIDEA node separately. This is intended to improve the performance of replicated setups, because each privacyIDEA node then only writes to its own “private” table row. This way, we avoid locking issues that would occur if all nodes write to the same table row.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.EventHandler(name, event, handlermodule, action, condition='', ordering=0, options=None, id=None, conditions=None, active=True, position='post', abort_on_error=False)[source]¶
This model holds the list of defined events and actions of this eventhandler. A handler module can be bound to an event with the corresponding condition and action.
- class privacyidea.models.EventHandlerCondition(eventhandler_id, Key, Value, comparator='equal')[source]¶
Each EventHandler entry can have additional conditions according to the handler module
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.EventHandlerOption(eventhandler_id, Key, Value, Type='', Description='')[source]¶
Each EventHandler entry can have additional options according to the handler module.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.InternalUserAttribute(user_id, resolver, realm_id, Key, Value=None, node=None)[source]¶
Generic key-value store for internal per-user state written by privacyIDEA itself (not by admins or resolvers).
Use this table for things like cached FIDO2 user IDs or the last-used token type per client. The
customuserattributetable is reserved for admin/resolver-facing attributes that may be referenced from policy conditions; do not put internal state there.Values are stored as JSON, so a single row can hold a structured dict instead of synthesizing keys with prefixes.
- class privacyidea.models.MachineResolver(name, rtype)[source]¶
This model holds the definition to the machinestore. Machines could be located in flat files, LDAP directory or in puppet services or other…
The usual MachineResolver just holds a name and a type and a reference to its config
- class privacyidea.models.MachineResolverConfig(resolver_id=None, Key=None, Value=None, resolver=None, Type='', Description='')[source]¶
Each Machine Resolver can have multiple configuration entries. The config entries are referenced by the id of the machine resolver
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.MachineToken(**kwds)[source]¶
The MachineToken assigns a Token and an application type to a machine. The Machine is represented as the tuple of machineresolver.id and the machine_id. The machine_id is defined by the machineresolver.
This can be an n:m mapping.
- class privacyidea.models.MachineTokenOptions(machinetoken_id, key, value)[source]¶
This class holds an Option for the token assigned to a certain client machine. Each Token-Clientmachine-Combination can have several options.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.MetricAggregate(**kwargs)[source]¶
Rolling counter / histogram bucket for a metric in a 5-minute window.
For counters only
countis used. For histogramscount,sum_value,max_valueand thebucket_le_*columns hold the sample distribution. Buckets follow the prom-style_bucket{le="..."}convention: each column stores the count of observations whose value is <= that boundary (inclusive, cumulative).A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.MonitoringStats(timestamp, key, value)[source]¶
This is the table that stores measured, arbitrary statistic points in time. This could be used to store time series but also to store current values, by simply fetching the last value from the database.
- class privacyidea.models.NodeName(**kwargs)[source]¶
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.PasswordReset(**kwds)[source]¶
Table for handling password resets. This table stores the recoverycodes sent to a given user The application should save the HASH of the recovery code. Just like the password for the Admins the application shall salt and pepper the hash of the recoverycode. A database admin will not be able to inject a rogue recovery code. A user can get several recoverycodes. A recovery code has a validity period Optional: The email to which the recoverycode was sent, can be stored.
- class privacyidea.models.PeriodicTask(name, active, interval, node_list, taskmodule, ordering, options=None, id=None, retry_if_failed=True)[source]¶
This class stores tasks that should be run periodically.
- Parameters:
name – Unique name of the periodic task as Unicode
active – a boolean
retry_if_failed
interval – a Unicode specifying the periodicity of the task
node_list – a list of unicodes, denoting the node names that should execute that task. If we update an existing PeriodicTask entry, PeriodicTaskLastRun entries referring to nodes that are not present in
node_listanymore will be deleted.taskmodule – a Unicode
ordering – an integer. Lower tasks are executed first.
options – a dictionary of options, mapping Unicode keys to values. Values will be converted to Unicode. If we update an existing PeriodicTask entry, all options that have been set previously but are not present in
optionswill be deleted.id – the ID of an existing entry, if any
- property aware_last_update¶
Return self.last_update with attached UTC tzinfo
- class privacyidea.models.PeriodicTaskLastRun(periodictask_id, node, timestamp)[source]¶
Each PeriodicTask entry stores, for each node, the timestamp of the last successful run.
- Parameters:
periodictask_id – ID of the periodic task we are referring to
node – Node name as unicode
timestamp – Time of the last run as a datetime. A timezone must not be set! We require the time to be given in UTC.
- property aware_timestamp¶
Return self.timestamp with attached UTC tzinfo
- class privacyidea.models.PeriodicTaskOption(periodictask_id, key, value)[source]¶
Each PeriodicTask entry can have additional options according to the task module.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Policy(name, active=True, scope='', action='', realm='', adminrealm='', adminuser='', resolver='', user='', client='', time='', pinode='', priority=1, check_all_resolvers=False, conditions=None, user_case_insensitive=False, user_agents=None)[source]¶
The policy table contains the policy definitions.
- The Policies control the behaviour in the scopes
enrollment
authentication
authorization
administration
user actions
webui
- get(key=None)[source]¶
Either returns the complete policy entry or a single value :param key: return the value for this key :type key: string :return: complete dict or single value :rytpe: dict or value
- class privacyidea.models.PolicyCondition(section, Key, comparator, Value, active=True, handle_missing_data=None)[source]¶
- class privacyidea.models.PolicyDescription(object_id, name='', object_type='', description='')[source]¶
The description table is used to store the description of policy
- class privacyidea.models.PrivacyIDEAServer(**kwargs)[source]¶
This table can store remote privacyIDEA server definitions
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.RADIUSServer(**kwargs)[source]¶
This table can store configurations of RADIUS servers. https://github.com/privacyidea/privacyidea/issues/321
It saves * a unique name * a description * an IP address a * a Port * a secret * timeout in seconds (default 5) * retries (default 3)
These RADIUS server definitions can be used in RADIUS tokens or in a radius passthru policy.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Realm(**kwds)[source]¶
The realm table contains the defined realms. User Resolvers can be grouped to realms. This very table contains just contains the names of the realms. The linking to resolvers is stored in the table “resolverrealm”.
- class privacyidea.models.RememberedDevice(**kwds)[source]¶
A persistent (“remember this device”) authentication device bound to a specific API client.
The device implements a rotating-token scheme: the client stores a cookie of the form
series_id:counter. On every use the counter is incremented both in the cookie and in this row. If a request presents the correctseries_idbut a stalecounter, the token has been replayed (the cookie was stolen), the whole series is deleted and authentication fails.The cookie never contains the API key; the binding to the client is stored server-side in
client_idand checked againstg.client_id.The remembered user is bound by the resolver-stable identity
(resolver, user_id, realm_id)- not by the login name. The login is a mutable, reusable label in an external user store: binding to it would drop the remembered device on a rename and, worse, could recognise a different account that later reuses a freed login.user_idis therefore the resolver’s immutable id (as inTokenOwner), andrealm_idis a foreign key so a deleted realm cascades its devices away.The composite
(client_id, resolver, user_id, realm_id)index serves the two lookups done on every remember-device request:get_valid_device()(cookie validation) andcount_user_devices()(the per-user device cap at issuance), both of which filter on all four columns at once. Atutf8mb4this composite is 1908 bytes, under MySQL’s 3072-byte index-key limit, so - unlikeusersetting’ssubject_hash- no hashed column is needed here. The individual single-column indexes stay: they are still required byrevoke_devices(), the client-independent bulk revoke that filters by realm/user without aclient_id.The composite
(client_id, created_at)index serves the paginated, newest-first listing inget_client_devices():(client_id, resolver, user_id, realm_id)above cannot help that query order rows bycreated_at, so without this a client with a very large number of devices would need every one of its rows collected and sorted before a single page could be returned.
- class privacyidea.models.Resolver(name, rtype)[source]¶
The table “resolver” contains the names and types of the defined User Resolvers. As each Resolver can have different required config values the configuration of the resolvers is stored in the table “resolverconfig”.
- class privacyidea.models.ResolverConfig(resolver_id=None, Key=None, Value=None, resolver=None, Type='', Description='')[source]¶
Each Resolver can have multiple configuration entries. Each Resolver type can have different required config values. Therefore, the configuration is stored in simple key/value pairs. If the type of a config entry is set to “password” the value of this config entry is stored encrypted.
The config entries are referenced by the id of the resolver.
- class privacyidea.models.ResolverRealm(resolver_id=None, realm_id=None, resolver_name=None, realm_name=None, priority=None, node_uuid=None, node_name=None)[source]¶
This table stores which Resolver is located in which realm This is a N:M relation
- class privacyidea.models.SMSGateway(identifier, providermodule, description=None)[source]¶
This table stores the SMS Gateway definitions. See https://github.com/privacyidea/privacyidea/wiki/concept:-Delivery-Gateway
It saves the * unique name * a description * the SMS provider module
All options and parameters are saved in other tables.
- class privacyidea.models.SMSGatewayOption(gateway_id, Key, Value, Type=None, Encrypted=False)[source]¶
This table stores the options, parameters and headers for an SMS Gateway definition.
Create a new gateway_option for the gateway_id
- class privacyidea.models.SMTPServer(**kwargs)[source]¶
This table can store configurations for SMTP servers. Each entry represents an SMTP server. EMail Token, SMS SMTP Gateways or Notifications like PIN handlers are supposed to use a reference to a server definition. Each Machine Resolver can have multiple configuration entries. The config entries are referenced by the id of the machine resolver
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Serviceid(**kwds)[source]¶
The serviceid table contains the defined service IDs. These service ID describe services like “webservers” or “dbservers” which e.g. request SSH keys from the privacyIDEA system.
- class privacyidea.models.Subscription(**kwargs)[source]¶
This table stores the imported subscription files.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.Token(serial, tokentype='', isactive=True, otplen=6, otpkey='', **kwargs)[source]¶
The “Token” table contains the basic token data.
- It contains data like
serial number
secret key
PINs
…
The table
privacyidea.models.TokenOwnercontains the owner information of the specified token. The tableprivacyidea.models.TokenInfocontains additional information that is specific to the tokentype.- get(key=None, fallback=None, save=False)[source]¶
simulate the dict behaviour to make challenge processing easier, as this will have to deal as well with ‘dict only challenges’
- Parameters:
key – the attribute name - in case of key is not provided, a dict of all class attributes are returned
fallback – if the attribute is not found, the fallback is returned
save – in case of all attributes and save==True, the timestamp is converted to a string representation
- get_hashed_pin(pin)[source]¶
Calculate a hash from a pin Fix for working with MS SQL servers MS SQL servers sometimes return a ‘<space>’ when the column is empty: ‘’
- Parameters:
pin (str) – the pin to hash
- Returns:
hashed pin with current pin_seed
- Return type:
str
- get_realms()[source]¶
return a list of the assigned realms
- Returns:
the realms of the token
- Return type:
list
- set_hashed_pin(pin)[source]¶
Set the pin of the token in hashed format
- Parameters:
pin (str) – the pin to hash
- Returns:
the hashed pin
- Return type:
str
- class privacyidea.models.TokenContainer(serial, container_type='Generic', tokens=None, description='', states=None)[source]¶
The “Tokencontainer” table contains the containers and their associated tokens.
- class privacyidea.models.TokenContainerInfo(container_id, key, value, type=None, description=None)[source]¶
The table “tokencontainerinfo” is used to store additional, long information that is specific to the containertype.
Create a new tokencontainerinfo for a given token_id
- class privacyidea.models.TokenContainerOwner(container_id=None, container_serial=None, resolver=None, user_id=None, realm_id=None, realm_name=None)[source]¶
Create a new TokenContainerOwner assignment.
- class privacyidea.models.TokenContainerRealm(**kwargs)[source]¶
This table stores to which realms a container is assigned.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.TokenContainerTemplate(name, container_type='generic', options='', default=False)[source]¶
- class privacyidea.models.TokenContainerToken(**kwargs)[source]¶
Association table to link tokens to containers.
A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.TokenInfo(token_id, Key, Value, Type=None, Description=None)[source]¶
The table “tokeninfo” is used to store additional, long information that is specific to the tokentype. E.g. the tokentype “TOTP” has additional entries in the tokeninfo table for “timeStep” and “timeWindow”, which are stored in the column “Key” and “Value”.
The tokeninfo is reference by the foreign key to the “token” table.
Create a new tokeninfo for a given token_id
- class privacyidea.models.TokenOwner(token_id=None, serial=None, user_id=None, resolver=None, realm_id=None, realmname=None)[source]¶
This tables stores the owner of a token. A token can be assigned to several users.
Create a new token assignment to a user.
- Parameters:
token_id – The database ID of the token
serial – The alternate serial number of the token
resolver – The identifying name of the resolver
realm_id – The database ID of the realm
realmname – The alternate name of realm
- class privacyidea.models.TokenRealm(realm_id=0, token_id=0, realmname=None)[source]¶
This table stores to which realms a token is assigned. A token is in the realm of the user it is assigned to. But a token can also be put into many additional realms.
- class privacyidea.models.TokenTokengroup(tokengroup_id=0, token_id=0, tokengroupname=None)[source]¶
This table stores the assignment of tokens to tokengroups. A token can be assigned to several different token groups.
Create a new TokenTokengroup assignment :param tokengroup_id: The id of the token group :param tokengroupname: the name of the tokengroup :param token_id: The id of the token
- class privacyidea.models.Tokengroup(**kwds)[source]¶
The tokengroup table contains the definition of available token groups. A token can then be assigned to several of these tokengroups.
- class privacyidea.models.UserCache(username, used_login, resolver, user_id, timestamp)[source]¶
This class stores the cached information for a user to improve lookup performance.
- class privacyidea.models.UserLockState(**kwargs)[source]¶
The current lock status of a single user, keyed by the same
(resolver, uid, realm)tuple used inAuthenticationLog.There is deliberately no failure counter stored here: failure counts are derived on demand by querying
authentication_logover a policy’s time window. That keeps the data flexible (per-policy windows, easy reset, automatic decay) and avoids stale counters on user objects.lock_expires_atis the load-bearing field: a row exists only while the user is locked, and a row whoselock_expires_atlies in the future (or isNULLfor a permanent lock) means the user is currently locked; an admin lifts a lock by deleting the row (timestamps are naive UTC, seeutc_now()).A local database admin is locked here too, and has none of those three values - only a login name. Their row carries the login name as the
uidwith an emptyresolverandrealm, which cannot collide with a user’s: a user row is only ever written for a principal that has all three.user_rolesays which of the two a row is, so nothing has to infer it from what the row lacks; seeLockSubject, which is what builds both shapes.The row records the lock itself, not which policy produced it: what a stage did, and to whom, is the conditional-access history (
ConditionalAccessOutcome). It does recordlock_cause, i.e. whether a policy or an administrator imposed the lock now in force - a manual lock has no authentication request, so it can have no history row of its own.A simple constructor that allows initialization from kwargs.
Sets attributes on the constructed instance using the names and values in
kwargs.Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.
- class privacyidea.models.UserSetting(subject_type, username='', user_id='', resolver='', realm_id=None, settings=None, node=None)[source]¶
Per-principal frontend settings (one row per principal, the whole settings document stored as a single JSON value).
The backend does not interpret these settings; it stores and serves them for the WebUI. A “principal” is whoever logged in, which is not always a resolver user:
subject_type='local_admin'— an internal admin from theadmintable. Identified byusernamealone;user_id,resolverandrealm_idare empty/NULL.subject_type='user'— a resolver user (this also covers realm-admins). Identified by the(user_id, resolver, realm_id)tuple, the same stable identity used bytokenowner;usernameis kept only as a convenience for logging/lookups.
Only principals that deviate from the defaults get a row, so the table stays small even with a large user base.
The
realm_idforeign key isON DELETE CASCADE: deleting a realm removes its users’ settings, since those users are gone with it. Rows orphaned by user or resolver removal (which the FK does not cover) are pruned by thepi-tokenjanitor user-settingsCLI command.
- privacyidea.models.cleanup_challenges(serial)[source]¶
Delete all challenges, that have expired.
- Returns:
None
- privacyidea.models.get_machineresolver_id(resolvername)[source]¶
Return the database ID of the machine resolver :param resolvername: :return:
- privacyidea.models.get_machinetoken_ids(machine_id, resolver_name, serial, application)[source]¶
Returns a list of the ID in the machinetoken table
- Parameters:
machine_id (basestring) – The resolverdependent machine_id
resolver_name (basestring) – The name of the resolver
serial (basestring) – the serial number of the token
application (basestring) – The application type
- Returns:
A list of IDs of the machinetoken entry
- Return type:
list of int