Module: OmniauthOpenidFederation::RateLimiter

Defined in:
lib/omniauth_openid_federation/rate_limiter.rb

Constant Summary collapse

DEFAULT_MAX_REQUESTS =

Default rate limiting configuration

10
DEFAULT_WINDOW_SECONDS =
60

Class Method Summary collapse

Class Method Details

.allow?(key, max_requests: DEFAULT_MAX_REQUESTS, window: DEFAULT_WINDOW_SECONDS) ⇒ Boolean

Check if request should be throttled

Best-effort only: read-modify-write on the cache adapter is not atomic, so parallel workers can briefly exceed the limit. Treat this as a DoS soft guard, not a hard quota.

Parameters:

  • key (String)

    Unique identifier for the rate limit (e.g., jwks_uri)

  • max_requests (Integer) (defaults to: DEFAULT_MAX_REQUESTS)

    Maximum requests allowed in window (default: 10)

  • window (Integer) (defaults to: DEFAULT_WINDOW_SECONDS)

    Time window in seconds (default: 60)

Returns:

  • (Boolean)

    true if request should be allowed, false if throttled



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/omniauth_openid_federation/rate_limiter.rb', line 22

def self.allow?(key, max_requests: DEFAULT_MAX_REQUESTS, window: DEFAULT_WINDOW_SECONDS)
  return true unless CacheAdapter.available?

  cache_key = "omniauth_openid_federation:rate_limit:#{Digest::SHA256.hexdigest(key)}"
  current_time = Time.now.to_i
  window_start = current_time - window

  timestamps = CacheAdapter.read(cache_key) || []
  timestamps = timestamps.select { |ts| ts > window_start }

  if timestamps.length >= max_requests
    OmniauthOpenidFederation::Logger.warn("[RateLimiter] Rate limit exceeded for #{Utils.sanitize_uri(key)}: #{timestamps.length}/#{max_requests} requests in #{window}s")
    return false
  end

  timestamps << current_time
  CacheAdapter.write(cache_key, timestamps, expires_in: window)

  true
end

.reset!(key) ⇒ Object

Reset rate limit for a key (useful for testing or manual override)

Parameters:

  • key (String)

    Unique identifier for the rate limit



46
47
48
49
50
51
# File 'lib/omniauth_openid_federation/rate_limiter.rb', line 46

def self.reset!(key)
  return unless CacheAdapter.available?

  cache_key = "omniauth_openid_federation:rate_limit:#{Digest::SHA256.hexdigest(key)}"
  CacheAdapter.delete(cache_key)
end