Skip to content

Commit b5ef140

Browse files
progvalspb
authored andcommitted
Allow clients to retry authentication after it failed
eg. because of invalid password
1 parent 9168e04 commit b5ef140

File tree

5 files changed

+29
-13
lines changed

5 files changed

+29
-13
lines changed

sable_ircd/src/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ pub struct PreClient {
8080
pub realname: OnceLock<Realname>,
8181
#[serde_as(as = "WrapOption<Hostname>")]
8282
pub hostname: OnceLock<Hostname>,
83-
#[serde_as(as = "WrapOption<SaslSessionId>")]
84-
pub sasl_session: OnceLock<SaslSessionId>,
83+
#[serde(skip, default = "Default::default")]
84+
pub sasl_session: tokio::sync::Mutex<Option<SaslSessionId>>,
8585
#[serde_as(as = "WrapOption<AccountId>")]
8686
pub sasl_account: OnceLock<AccountId>,
8787

@@ -240,7 +240,7 @@ impl PreClient {
240240
nick: OnceLock::new(),
241241
realname: OnceLock::new(),
242242
hostname: OnceLock::new(),
243-
sasl_session: OnceLock::new(),
243+
sasl_session: tokio::sync::Mutex::new(None),
244244
sasl_account: OnceLock::new(),
245245
progress_flags: AtomicU32::new(0),
246246
}

sable_ircd/src/command/handlers/services/sasl.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ async fn handle_authenticate(
1616
services: Conditional<ServicesTarget<'_>>,
1717
text: &str,
1818
) -> CommandResult {
19-
let authenticate_request = if let Some(session) = source.sasl_session.get() {
19+
let mut session_ref = source.sasl_session.lock().await;
20+
let authenticate_request = if let Some(session) = *session_ref {
2021
// A session already exists, so the argument is "*" or base64-encoded session data
22+
tracing::debug!(?session, "Resuming SASL session");
2123
if text == "*" {
22-
RemoteServicesServerRequestType::AbortAuthenticate(*session)
24+
RemoteServicesServerRequestType::AbortAuthenticate(session)
2325
} else {
24-
let Ok(data) = BASE64_STANDARD.decode(text) else {
25-
response.numeric(make_numeric!(SaslFail));
26-
return Ok(());
27-
};
28-
29-
RemoteServicesServerRequestType::Authenticate(*session, data)
26+
match BASE64_STANDARD.decode(text) {
27+
Err(_) => RemoteServicesServerRequestType::FailAuthenticate(session),
28+
Ok(data) => RemoteServicesServerRequestType::Authenticate(session, data),
29+
}
3030
}
3131
} else {
3232
// No session, so the argument is the mechanism name
@@ -46,13 +46,15 @@ async fn handle_authenticate(
4646

4747
// Special case for EXTERNAL, which we can handle without going to services
4848
if text == "EXTERNAL" {
49+
drop(session_ref); // release lock, which borrows 'source'
4950
return do_sasl_external(source, cmd.connection(), net, response);
5051
}
5152

5253
let mechanism = text.to_owned();
5354

5455
let session = server.ids().next();
55-
source.sasl_session.set(session).ok();
56+
*session_ref = Some(session);
57+
tracing::debug!(?session, "Beginning new SASL session ");
5658

5759
RemoteServicesServerRequestType::BeginAuthenticate(session, mechanism)
5860
};
@@ -88,9 +90,11 @@ async fn handle_authenticate(
8890
response.numeric(make_numeric!(SaslSuccess));
8991
}
9092
Fail => {
93+
*session_ref = None;
9194
response.numeric(make_numeric!(SaslFail));
9295
}
9396
Aborted => {
97+
*session_ref = None;
9498
response.numeric(make_numeric!(SaslAborted));
9599
}
96100
}

sable_network/src/rpc/network_message.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,10 @@ pub enum RemoteServicesServerRequestType {
7272
BeginAuthenticate(SaslSessionId, String),
7373
/// SASL traffic
7474
Authenticate(SaslSessionId, Vec<u8>),
75-
/// Abort a SASL session
75+
/// Abort a SASL session, sends error to client
7676
AbortAuthenticate(SaslSessionId),
77+
/// Abort a SASL session, don't send error to client
78+
FailAuthenticate(SaslSessionId),
7779
/// Register a channel
7880
RegisterChannel(AccountId, ChannelId),
7981
/// Add, modify or remove a channel access (None to delete)

sable_services/src/server/command/sasl_commands.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,9 @@ impl<DB: DatabaseConnection> ServicesServer<DB> {
5050
self.sasl_sessions.remove(&session_id);
5151
Ok(Authenticate(Aborted).into())
5252
}
53+
54+
pub fn fail_authenticate(&self, session_id: SaslSessionId) -> CommandResult {
55+
self.sasl_sessions.remove(&session_id);
56+
Ok(Authenticate(Fail).into())
57+
}
5358
}

sable_services/src/server/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ where
194194

195195
self.abort_authenticate(session)
196196
}
197+
FailAuthenticate(session) => {
198+
tracing::debug!(?session, "Got fail authenticate");
199+
200+
self.fail_authenticate(session)
201+
}
197202
AddAccountFingerprint(acc, fp) => {
198203
tracing::debug!(?acc, ?fp, "Got add fingerprint");
199204

0 commit comments

Comments
 (0)