Redeem website login keycards over SASL
All checks were successful
CI / check (push) Successful in 3m52s
All checks were successful
CI / check (push) Successful in 3m52s
A member already authenticated on tchatou.fr connects with a single-use kc_… keycard instead of their password (the m_apiauth module that used to validate it was retired in the Anope->echo cutover, so these logins had started failing as "wrong password"). The SASL PLAIN handler now recognises a kc_-prefixed credential and emits NetAction::DeferKeycard; the link layer redeems it off the engine lock — a localhost round-trip to Django's login-token endpoint via keycard::redeem — and completes the login exactly like a password auth. Config: [keycard] url + api_key; absent, kc_ credentials are simply not honoured.
This commit is contained in:
parent
bad17a184e
commit
f2fd80694d
9 changed files with 359 additions and 4 deletions
14
src/link.rs
14
src/link.rs
|
|
@ -71,7 +71,7 @@ fn redact(line: &str) -> Cow<'_, str> {
|
|||
// One uplink session: connect, handshake + burst, then translate lines forever.
|
||||
// The engine is shared with the gossip layer, so it is locked per operation and
|
||||
// never held across the registration key-stretching await.
|
||||
pub async fn run(mut proto: Box<dyn Protocol>, engine: Arc<Mutex<Engine>>, addr: &str, mut irc_rx: mpsc::UnboundedReceiver<NetAction>, email: Option<crate::config::Email>) -> Result<()> {
|
||||
pub async fn run(mut proto: Box<dyn Protocol>, engine: Arc<Mutex<Engine>>, addr: &str, mut irc_rx: mpsc::UnboundedReceiver<NetAction>, email: Option<crate::config::Email>, keycard: Option<crate::config::Keycard>) -> Result<()> {
|
||||
let stream = TcpStream::connect(addr).await?;
|
||||
let (read, mut write) = stream.into_split();
|
||||
let mut lines = BufReader::new(read).lines();
|
||||
|
|
@ -131,6 +131,18 @@ pub async fn run(mut proto: Box<dyn Protocol>, engine: Arc<Mutex<Engine>>, addr:
|
|||
.await?;
|
||||
engine.lock().await.complete_authenticate(ok, then)
|
||||
}
|
||||
NetAction::DeferKeycard { token, account, then } => {
|
||||
// Redeem a website login keycard off the reactor (a localhost
|
||||
// HTTP round-trip), then finish the login under the lock — the
|
||||
// completion is identical to a password auth once we know the
|
||||
// outcome.
|
||||
let kc = keycard.clone();
|
||||
let ok = tokio::task::spawn_blocking(move || {
|
||||
crate::keycard::redeem(kc.as_ref(), &account, &token)
|
||||
})
|
||||
.await?;
|
||||
engine.lock().await.complete_authenticate(ok, then)
|
||||
}
|
||||
action => vec![action],
|
||||
};
|
||||
for act in outs {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue