swarm-nats-auth: give issued user JWTs an exp
The user JWT the callout issues carried no exp, so nats-server armed no expiry timer and a connection kept its grant until the client dropped it: a deleted or re-minted agent queue secret, a removed OIDC client or an expired access token never reached a live connection. Every issued user JWT now expires at the presented OIDC token's exp (read from the introspection answer) or an hour after issue, whichever is sooner; the agent queue-secret path has no exp of its own and gets the hour. Every queue client reconnects through an auth callback that re-reads or re-mints its credential, so the forced reconnect presents a current one. Fixes #5432
This commit is contained in:
parent
de4871cab1
commit
e405c2b098
9 changed files with 245 additions and 69 deletions
|
|
@ -21,7 +21,7 @@ use swarm_secret_client::client::{DEFAULT_CERT_MOUNT, Settings};
|
|||
use swarm_secret_client::path::{Kind, principal_prefix};
|
||||
use tokio::time::Instant;
|
||||
|
||||
use crate::introspect::Answer;
|
||||
use crate::introspect::{Answer, Caller};
|
||||
use crate::keystore::KeyStore;
|
||||
|
||||
/// The path under the store's KV mount holding `client_id`'s secret.
|
||||
|
|
@ -99,7 +99,7 @@ impl OidcSecret {
|
|||
///
|
||||
/// # Errors
|
||||
/// When an attempt could not be made at all; the caller denies.
|
||||
pub async fn introspect<F, Fut>(&self, deadline: Instant, attempt: F) -> Result<Option<String>>
|
||||
pub async fn introspect<F, Fut>(&self, deadline: Instant, attempt: F) -> Result<Option<Caller>>
|
||||
where
|
||||
F: Fn(String) -> Fut,
|
||||
Fut: Future<Output = Result<Answer>>,
|
||||
|
|
@ -165,7 +165,10 @@ mod tests {
|
|||
move |secret| {
|
||||
calls.fetch_add(1, Ordering::SeqCst);
|
||||
std::future::ready(Ok(if secret == registered {
|
||||
Answer::Caller(Some("hive-alpha".to_owned()))
|
||||
Answer::Caller(Some(Caller {
|
||||
client_id: "hive-alpha".to_owned(),
|
||||
expires: None,
|
||||
}))
|
||||
} else {
|
||||
Answer::Refused(reqwest::StatusCode::UNAUTHORIZED)
|
||||
}))
|
||||
|
|
@ -203,7 +206,7 @@ mod tests {
|
|||
.introspect(budget(), idp("old", &calls))
|
||||
.await
|
||||
.expect("answered");
|
||||
assert_eq!(caller.as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(caller.map(|c| c.client_id).as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 1);
|
||||
assert_eq!(reads.load(Ordering::SeqCst), 0);
|
||||
}
|
||||
|
|
@ -219,7 +222,7 @@ mod tests {
|
|||
.introspect(budget(), idp("new", &calls))
|
||||
.await
|
||||
.expect("answered");
|
||||
assert_eq!(caller.as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(caller.map(|c| c.client_id).as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 2);
|
||||
assert_eq!(reads.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
|
@ -279,7 +282,7 @@ mod tests {
|
|||
.introspect(budget(), idp("new", &calls))
|
||||
.await
|
||||
.expect("answered");
|
||||
assert_eq!(caller.as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(caller.map(|c| c.client_id).as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 5);
|
||||
assert_eq!(reads.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
|
@ -307,7 +310,7 @@ mod tests {
|
|||
.introspect(budget(), idp("new", &calls))
|
||||
.await
|
||||
.expect("answered");
|
||||
assert_eq!(next.as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(next.map(|c| c.client_id).as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(calls.load(Ordering::SeqCst), 2);
|
||||
assert_eq!(reads.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
|
|
@ -326,7 +329,7 @@ mod tests {
|
|||
if headers.get(AUTHORIZATION).and_then(|v| v.to_str().ok()) == Some(&*expected) {
|
||||
(
|
||||
StatusCode::OK,
|
||||
r#"{"active":true,"client_id":"hive-alpha"}"#,
|
||||
r#"{"active":true,"client_id":"hive-alpha","exp":1700000000}"#,
|
||||
)
|
||||
} else {
|
||||
(StatusCode::UNAUTHORIZED, "")
|
||||
|
|
@ -369,7 +372,13 @@ mod tests {
|
|||
})
|
||||
.await
|
||||
.expect("answered");
|
||||
assert_eq!(caller.as_deref(), Some("hive-alpha"));
|
||||
assert_eq!(
|
||||
caller,
|
||||
Some(Caller {
|
||||
client_id: "hive-alpha".to_owned(),
|
||||
expires: Some(1_700_000_000),
|
||||
})
|
||||
);
|
||||
assert_eq!(reads.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue