Packages
ash_authentication
5.0.0-rc.0
5.0.0-rc.12
5.0.0-rc.11
5.0.0-rc.10
5.0.0-rc.9
5.0.0-rc.8
5.0.0-rc.7
5.0.0-rc.6
5.0.0-rc.5
5.0.0-rc.4
5.0.0-rc.3
5.0.0-rc.2
5.0.0-rc.1
5.0.0-rc.0
4.14.1
4.14.0
4.13.7
4.13.6
4.13.5
4.13.4
4.13.3
4.13.2
retired
4.13.1
retired
4.13.0
4.12.0
4.11.0
4.10.0
4.9.9
4.9.8
4.9.7
4.9.6
4.9.5
4.9.4
4.9.3
4.9.2
4.9.1
4.9.0
4.8.7
4.8.6
4.8.5
4.8.3
4.8.2
4.8.1
4.8.0
4.7.6
4.7.5
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.6.4
4.6.3
4.6.2
4.6.1
4.6.0
4.5.6
4.5.5
4.5.4
4.5.3
4.5.2
4.5.1
4.5.0
4.4.9
4.4.8
4.4.7
4.4.6
4.4.5
4.4.4
4.4.3
4.4.2
4.4.1
4.4.0
4.3.12
4.3.11
4.3.10
4.3.9
4.3.8
4.3.7
4.3.6
4.3.5
4.3.4
4.3.3
4.3.2
4.3.1
4.3.0
4.2.7
4.2.6
4.2.5
4.2.4
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.4
4.0.3
4.0.2
4.0.1
4.0.0
4.0.0-rc.6
4.0.0-rc.5
4.0.0-rc.3
4.0.0-rc.2
4.0.0-rc.1
4.0.0-rc.0
3.12.4
3.12.3
3.12.2
3.12.1
3.12.0
3.11.16
3.11.15
3.11.14
3.11.13
3.11.12
3.11.11
3.11.10
3.11.9
3.11.8
3.11.7
3.11.6
3.11.5
3.11.4
3.11.3
3.11.2
3.11.1
3.11.0
3.10.8
3.10.7
3.10.6
3.10.5
3.10.4
3.10.3
3.10.2
3.10.1
3.10.0
3.9.6
3.9.5
3.9.4
3.9.3
3.9.2
3.9.1
3.9.0
3.8.0
3.7.9
3.7.8
3.7.6
3.7.5
3.7.4
3.7.3
3.7.2
3.7.1
3.7.0
3.6.1
3.6.0
3.5.3
3.5.2
3.5.1
3.5.0
3.3.1
3.3.0
3.2.2
3.2.1
3.2.0
3.1.0
3.0.3
Authentication extension for the Ash Framework.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/ash_authentication/strategies/totp/audit_log_helpers.ex
# SPDX-FileCopyrightText: 2025 Alembic Pty Ltd
#
# SPDX-License-Identifier: MIT
defmodule AshAuthentication.Strategy.Totp.AuditLogHelpers do
@moduledoc """
Shared helpers for audit log-based brute force protection.
This module provides common functionality used by both `AuditLogChange` and
`AuditLogPreparation` to count failed TOTP attempts from the audit log.
"""
require Ash.Query
import Ash.Expr
alias AshAuthentication.AuditLogResource
@doc """
Counts failed TOTP attempts for a subject within a time window.
Queries the audit log resource for entries matching:
- The given subject (user identifier)
- Strategy = :totp
- Status = :failure
- Logged at or after the cutoff time
Uses a `FOR UPDATE` lock to prevent race conditions where multiple concurrent
requests could slip past the brute force limit. While this creates some
contention, it ensures accurate rate limiting enforcement.
Returns `{:ok, count}` or `{:error, reason}`.
"""
@spec count_failures(struct(), String.t(), DateTime.t()) ::
{:ok, non_neg_integer()} | {:error, any()}
def count_failures(audit_log, subject, cutoff) do
audit_log_resource = audit_log.audit_log_resource
subject_attr = AuditLogResource.Info.audit_log_attributes_subject!(audit_log_resource)
strategy_attr = AuditLogResource.Info.audit_log_attributes_strategy!(audit_log_resource)
status_attr = AuditLogResource.Info.audit_log_attributes_status!(audit_log_resource)
logged_at_attr = AuditLogResource.Info.audit_log_attributes_logged_at!(audit_log_resource)
query =
audit_log_resource
|> Ash.Query.new()
|> Ash.Query.set_context(%{private: %{ash_authentication?: true}})
|> Ash.Query.filter(^ref(subject_attr) == ^subject)
|> Ash.Query.filter(^ref(strategy_attr) == :totp)
|> Ash.Query.filter(^ref(status_attr) == :failure)
|> Ash.Query.filter(^ref(logged_at_attr) >= ^cutoff)
# Lock prevents race conditions where concurrent requests slip past the brute force limit
|> Ash.Query.lock("FOR UPDATE")
Ash.count(query)
end
end