auth: deferred login is authoritative in the account map, not just ircd metadata
All checks were successful
CI / check (push) Successful in 3m46s
All checks were successful
CI / check (push) Successful in 3m46s
This commit is contained in:
parent
75c6537532
commit
e112b8737c
2 changed files with 27 additions and 2 deletions
|
|
@ -275,7 +275,7 @@ impl Engine {
|
||||||
/// ctx helpers the inline path did, so its login side-effects (login, notice,
|
/// ctx helpers the inline path did, so its login side-effects (login, notice,
|
||||||
/// AJOIN, vhost, memo notice) stay identical.
|
/// AJOIN, vhost, memo notice) stay identical.
|
||||||
pub fn complete_authenticate(&mut self, ok: bool, then: AuthThen) -> Vec<NetAction> {
|
pub fn complete_authenticate(&mut self, ok: bool, then: AuthThen) -> Vec<NetAction> {
|
||||||
match then {
|
let actions = match then {
|
||||||
AuthThen::Identify { uid, agent, name, account } => {
|
AuthThen::Identify { uid, agent, name, account } => {
|
||||||
self.db.note_auth(&name, ok);
|
self.db.note_auth(&name, ok);
|
||||||
let mut ctx = ServiceCtx::default();
|
let mut ctx = ServiceCtx::default();
|
||||||
|
|
@ -320,6 +320,14 @@ impl Engine {
|
||||||
self.sasl_deny("SASL PLAIN", &agent, &client, Some(&account), "bad password")
|
self.sasl_deny("SASL PLAIN", &agent, &client, Some(&account), "bad password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
// This runs in the link layer, off the handle() path, so the login's
|
||||||
|
// accountname metadata never reaches track_accounts in handle(). Apply it
|
||||||
|
// here so echo's own account map is authoritative and doesn't depend on the
|
||||||
|
// ircd reflecting the metadata back — which is a no-op when re-authenticating
|
||||||
|
// an already-logged-in user after a services relink, leaving the user unable
|
||||||
|
// to use their access despite a successful login.
|
||||||
|
self.track_accounts(&actions);
|
||||||
|
actions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -673,6 +673,23 @@
|
||||||
assert_eq!(e.network.account_of("000AAAAAB"), None, "empty account is a logout");
|
assert_eq!(e.network.account_of("000AAAAAB"), None, "empty account is a logout");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A login that finishes off the handle() path (the link layer's deferred
|
||||||
|
// password/keycard verify) must still make echo's OWN account map authoritative.
|
||||||
|
// Otherwise re-identifying an already-logged-in user after a services relink —
|
||||||
|
// a no-op accountname on the ircd, so nothing is reflected back — leaves them
|
||||||
|
// unable to use their access despite a successful login.
|
||||||
|
#[test]
|
||||||
|
fn deferred_login_makes_account_authoritative() {
|
||||||
|
let mut e = engine_with("deferlogin", "foo", "sesame");
|
||||||
|
e.handle(NetEvent::UserConnect { uid: "000AAAAAB".into(), nick: "foo".into(), host: "h".into(), ip: "0.0.0.0".into() });
|
||||||
|
assert_eq!(e.network.account_of("000AAAAAB"), None);
|
||||||
|
// Exactly what the link layer does after the off-thread verify — not via handle().
|
||||||
|
let then = echo_api::AuthThen::Identify { uid: "000AAAAAB".into(), agent: "42SAAAAAA".into(), name: "foo".into(), account: "foo".into() };
|
||||||
|
let out = e.complete_authenticate(true, then);
|
||||||
|
assert!(out.iter().any(|a| matches!(a, NetAction::Metadata { key, value, .. } if key == "accountname" && value == "foo")), "emits accountname metadata for the ircd");
|
||||||
|
assert_eq!(e.network.account_of("000AAAAAB"), Some("foo"), "and is authoritative in echo's own map");
|
||||||
|
}
|
||||||
|
|
||||||
// A suspension that arrives by gossip must end local sessions on that account,
|
// A suspension that arrives by gossip must end local sessions on that account,
|
||||||
// just as a local SUSPEND does — the account and its channels stay put.
|
// just as a local SUSPEND does — the account and its channels stay put.
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue