+2
-3
Cargo.toml
+2
-3
Cargo.toml
···
19
hex = "0.4"
20
jwt-compact = { version = "0.8.0", features = ["es256k"] }
21
scrypt = "0.11"
22
-
#lettre = { version = "0.11.18", default-features = false, features = ["pool", "tokio1-rustls", "smtp-transport", "hostname", "builder"] }
23
-
#lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] }
24
aws-lc-rs = "1.13.0"
25
-
lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] }
26
rustls = { version = "0.23", default-features = false, features = ["tls12", "std", "logging", "aws_lc_rs"] }
27
handlebars = { version = "6.3.2", features = ["rust-embed"] }
28
rust-embed = "8.7.2"
29
axum-template = { version = "3.0.0", features = ["handlebars"] }
···
19
hex = "0.4"
20
jwt-compact = { version = "0.8.0", features = ["es256k"] }
21
scrypt = "0.11"
22
+
#Leaveing these two cause I think it is needed by the
23
aws-lc-rs = "1.13.0"
24
rustls = { version = "0.23", default-features = false, features = ["tls12", "std", "logging", "aws_lc_rs"] }
25
+
lettre = { version = "0.11", default-features = false, features = ["builder", "webpki-roots", "rustls", "aws-lc-rs", "smtp-transport", "tokio1", "tokio1-rustls"] }
26
handlebars = { version = "6.3.2", features = ["rust-embed"] }
27
rust-embed = "8.7.2"
28
axum-template = { version = "3.0.0", features = ["handlebars"] }
+3
src/main.rs
+3
src/main.rs
···
175
.finish()
176
.expect("failed to create governor config. this should not happen and is a bug");
177
178
let create_session_governor_limiter = create_session_governor_conf.limiter().clone();
179
let sign_in_governor_limiter = sign_in_governor_conf.limiter().clone();
180
let interval = Duration::from_secs(60);
···
175
.finish()
176
.expect("failed to create governor config. this should not happen and is a bug");
177
178
+
// let create_account_limiter_time: Option<String> =
179
+
// env::var("GATEKEEPER_CREATE_ACCOUNT_LIMITER_WINDOW").unwrap_or_else(|_| None);
180
+
181
let create_session_governor_limiter = create_session_governor_conf.limiter().clone();
182
let sign_in_governor_limiter = sign_in_governor_conf.limiter().clone();
183
let interval = Duration::from_secs(60);
+40
-17
src/middleware.rs
+40
-17
src/middleware.rs
···
1
use crate::helpers::json_error_response;
2
use axum::extract::Request;
3
use axum::http::{HeaderMap, StatusCode};
4
use axum::middleware::Next;
5
use axum::response::IntoResponse;
···
12
#[derive(Clone, Debug)]
13
pub struct Did(pub Option<String>);
14
15
#[derive(Serialize, Deserialize)]
16
pub struct TokenClaims {
17
pub sub: String,
18
}
19
20
pub async fn extract_did(mut req: Request, next: Next) -> impl IntoResponse {
21
-
let token = extract_bearer(req.headers());
22
23
-
match token {
24
-
Ok(token) => {
25
-
match token {
26
None => json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "")
27
.expect("Error creating an error response"),
28
-
Some(token) => {
29
-
let token = UntrustedToken::new(&token);
30
if token.is_err() {
31
return json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "")
32
.expect("Error creating an error response");
···
49
.expect("Error creating an error response");
50
}
51
let token = token.expect("Already checked for error,");
52
-
//Not going to worry about expiration since it still goes to the PDS
53
req.extensions_mut()
54
.insert(Did(Some(token.claims().custom.sub.clone())));
55
next.run(req).await
56
}
57
}
···
64
}
65
}
66
67
-
fn extract_bearer(headers: &HeaderMap) -> Result<Option<String>, String> {
68
match headers.get(axum::http::header::AUTHORIZATION) {
69
None => Ok(None),
70
-
Some(hv) => match hv.to_str() {
71
-
Err(_) => Err("Authorization header is not valid".into()),
72
-
Ok(s) => {
73
-
// Accept forms like: "Bearer <token>" (case-sensitive for the scheme here)
74
-
let mut parts = s.splitn(2, ' ');
75
-
match (parts.next(), parts.next()) {
76
-
(Some("Bearer"), Some(tok)) if !tok.is_empty() => Ok(Some(tok.to_string())),
77
-
_ => Err("Authorization header must be in format 'Bearer <token>'".into()),
78
}
79
}
80
-
},
81
}
82
}
···
1
use crate::helpers::json_error_response;
2
use axum::extract::Request;
3
+
use axum::http::header::AUTHORIZATION;
4
use axum::http::{HeaderMap, StatusCode};
5
use axum::middleware::Next;
6
use axum::response::IntoResponse;
···
13
#[derive(Clone, Debug)]
14
pub struct Did(pub Option<String>);
15
16
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17
+
pub enum AuthScheme {
18
+
Bearer,
19
+
DPoP,
20
+
}
21
+
22
#[derive(Serialize, Deserialize)]
23
pub struct TokenClaims {
24
pub sub: String,
25
}
26
27
pub async fn extract_did(mut req: Request, next: Next) -> impl IntoResponse {
28
+
let auth = extract_auth(req.headers());
29
30
+
match auth {
31
+
Ok(auth_opt) => {
32
+
match auth_opt {
33
None => json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "")
34
.expect("Error creating an error response"),
35
+
Some((scheme, token_str)) => {
36
+
// For Bearer, validate JWT and extract DID from `sub`.
37
+
// For DPoP, we currently only pass through and do not validate here; insert None DID.
38
+
// match scheme {
39
+
// AuthScheme::Bearer => {
40
+
let token = UntrustedToken::new(&token_str);
41
if token.is_err() {
42
return json_error_response(StatusCode::BAD_REQUEST, "TokenRequired", "")
43
.expect("Error creating an error response");
···
60
.expect("Error creating an error response");
61
}
62
let token = token.expect("Already checked for error,");
63
+
// Not going to worry about expiration since it still goes to the PDS
64
req.extensions_mut()
65
.insert(Did(Some(token.claims().custom.sub.clone())));
66
+
// }
67
+
// AuthScheme::DPoP => {
68
+
// // No DID extraction from DPoP here; leave None
69
+
// req.extensions_mut().insert(Did(None));
70
+
// }
71
+
// }
72
+
73
next.run(req).await
74
}
75
}
···
82
}
83
}
84
85
+
fn extract_auth(headers: &HeaderMap) -> Result<Option<(AuthScheme, String)>, String> {
86
match headers.get(axum::http::header::AUTHORIZATION) {
87
None => Ok(None),
88
+
Some(hv) => {
89
+
match hv.to_str() {
90
+
Err(_) => Err("Authorization header is not valid".into()),
91
+
Ok(s) => {
92
+
// Accept forms like: "Bearer <token>" or "DPoP <token>" (case-sensitive for the scheme here)
93
+
let mut parts = s.splitn(2, ' ');
94
+
match (parts.next(), parts.next()) {
95
+
(Some("Bearer"), Some(tok)) if !tok.is_empty() =>
96
+
Ok(Some((AuthScheme::Bearer, tok.to_string()))),
97
+
(Some("DPoP"), Some(tok)) if !tok.is_empty() =>
98
+
Ok(Some((AuthScheme::DPoP, tok.to_string()))),
99
+
_ => Err("Authorization header must be in format 'Bearer <token>' or 'DPoP <token>'".into()),
100
+
}
101
}
102
}
103
+
}
104
}
105
}