pub struct RotatingNonceCache { /* private fields */ }Expand description
Two-bucket rotating nonce cache for WS-Security replay detection.
Buckets rotate every half_window seconds (default: 150 s → 300 s total window).
A nonce present in either bucket is considered a replay and rejected.
When the current bucket reaches max_entries a forced rotation occurs so the
bucket is replaced by an empty one — legitimate traffic continues but further
nonces from the previous bucket will no longer be detected as replays. This
is preferable to unbounded growth; the trade-off is documented in check_and_insert.
§Thread-safety
check_and_insert takes &mut self, so RotatingNonceCache itself is not
thread-safe. Wrap it in a tokio::sync::Mutex (or std::sync::Mutex for sync
contexts) before sharing across async tasks:
use tokio::sync::Mutex;
use soap_server::RotatingNonceCache;
let cache = Arc::new(Mutex::new(RotatingNonceCache::new(150)));
// Inside an async handler:
let mut cache = cache.lock().await;
cache.check_and_insert(&nonce)?;The soap-server SoapService handles this internally — consumers
using validate_username_token via the server builder
do not need to manage the cache directly. Consider interior-mutability refactoring in v0.2.
Implementations§
Source§impl RotatingNonceCache
impl RotatingNonceCache
Sourcepub fn new(half_window_secs: u64) -> Self
pub fn new(half_window_secs: u64) -> Self
Create a new cache with the given time-window and default entry cap (100 000).
Sourcepub fn with_max_entries(half_window_secs: u64, max_entries: usize) -> Self
pub fn with_max_entries(half_window_secs: u64, max_entries: usize) -> Self
Create a new cache with explicit time-window and per-bucket entry cap.
Sourcepub fn check_and_insert(&mut self, nonce: &str) -> Result<(), SoapFault>
pub fn check_and_insert(&mut self, nonce: &str) -> Result<(), SoapFault>
Check nonce for replay and insert if not seen. Returns Err on replay.
If the current bucket is at capacity (max_entries), a forced rotation
is performed before inserting: the current bucket becomes the previous bucket
and a fresh empty bucket is started. This bounds memory use at the cost of
a narrow window where very recently-rotated nonces are no longer tracked —
a DoS flood that exhausts the cap is still bounded, and normal traffic is
not disrupted.