Skip to content

Commit 21e2c36

Browse files
authored
Recognise macaroons as access tokens from Synapse (#3797)
1 parent 9247885 commit 21e2c36

File tree

5 files changed

+42
-2
lines changed

5 files changed

+42
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ version = "0.7.9"
8282
version = "0.9.6"
8383
features = ["cookie-private", "cookie-key-expansion", "typed-header"]
8484

85+
# Constant-time base64
86+
[workspace.dependencies.base64ct]
87+
version = "1.6.0"
88+
8589
# Bytes
8690
[workspace.dependencies.bytes]
8791
version = "1.9.0"

crates/data-model/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ publish = false
1212
workspace = true
1313

1414
[dependencies]
15+
base64ct.workspace = true
1516
chrono.workspace = true
1617
thiserror.workspace = true
1718
serde.workspace = true

crates/data-model/src/tokens.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// SPDX-License-Identifier: AGPL-3.0-only
55
// Please see LICENSE in the repository root for full details.
66

7+
use base64ct::{Base64Url, Encoding};
78
use chrono::{DateTime, Utc};
89
use crc::{Crc, CRC_32_ISO_HDLC};
910
use mas_iana::oauth::OAuthTokenTypeHint;
@@ -294,7 +295,7 @@ impl TokenType {
294295
pub fn check(token: &str) -> Result<TokenType, TokenFormatError> {
295296
// these are legacy tokens imported from Synapse
296297
// we don't do any validation on them and continue as is
297-
if token.starts_with("syt_") {
298+
if token.starts_with("syt_") || is_likely_synapse_macaroon(token) {
298299
return Ok(TokenType::CompatAccessToken);
299300
}
300301
if token.starts_with("syr_") {
@@ -344,6 +345,20 @@ impl PartialEq<OAuthTokenTypeHint> for TokenType {
344345
}
345346
}
346347

348+
/// Returns true if and only if a token looks like it may be a macaroon.
349+
///
350+
/// Macaroons are a standard for tokens that support attenuation.
351+
/// Synapse used them for old sessions and for guest sessions.
352+
///
353+
/// We won't bother to decode them fully, but we can check to see if the first
354+
/// constraint is the `location` constraint.
355+
fn is_likely_synapse_macaroon(token: &str) -> bool {
356+
let Ok(decoded) = Base64Url::decode_vec(token) else {
357+
return false;
358+
};
359+
decoded.get(4..13) == Some(b"location ")
360+
}
361+
347362
const NUM: [u8; 62] = *b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
348363

349364
fn base62_encode(mut num: u32) -> String {
@@ -420,6 +435,25 @@ mod tests {
420435
);
421436
}
422437

438+
#[test]
439+
fn test_is_likely_synapse_macaroon() {
440+
// This is just the prefix of a Synapse macaroon, but it's enough to make the
441+
// sniffing work
442+
assert!(is_likely_synapse_macaroon(
443+
"MDAxYmxvY2F0aW9uIGxpYnJlcHVzaC5uZXQKMDAx"
444+
));
445+
446+
// Whilst this is a macaroon, it's not a Synapse macaroon
447+
assert!(! is_likely_synapse_macaroon("MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAyZnNpZ25hdHVyZSDj2eApCFJsTAA5rhURQRXZf91ovyujebNCqvD2F9BVLwo"));
448+
449+
// None of these are macaroons
450+
assert!(!is_likely_synapse_macaroon(
451+
"eyJARTOhearotnaeisahtoarsnhiasra.arsohenaor.oarnsteao"
452+
));
453+
assert!(!is_likely_synapse_macaroon("...."));
454+
assert!(!is_likely_synapse_macaroon("aaa"));
455+
}
456+
423457
#[test]
424458
fn test_generate_and_check() {
425459
const COUNT: usize = 500; // Generate 500 of each token type

crates/handlers/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pbkdf2 = { version = "0.12.2", features = [
6868
zeroize = "1.8.1"
6969

7070
# Various data types and utilities
71-
base64ct = "1.6.0"
71+
base64ct.workspace = true
7272
camino.workspace = true
7373
chrono.workspace = true
7474
elliptic-curve.workspace = true

0 commit comments

Comments
 (0)