MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / authenticate

Function authenticate

nodedb/src/control/server/session_auth/native.rs:47–263  ·  view source on GitHub ↗

Authenticate a native protocol connection from the first JSON frame. Returns `(identity, warning)` on success. The `warning` string is non-empty when the account is in password grace period or `must_change_password` is set — the caller should forward it to the client as a notice/warning. All failure paths on the `"password"` method enforce a constant-time floor equal to [`AUTH_FLOOR`]: the funct

(
    state: &SharedState,
    auth_mode: &AuthMode,
    body: &serde_json::Value,
    peer_addr: &str,
)

Source from the content-addressed store, hash-verified

45/// distinguish rate-limit rejection from credential rejection or reveal user
46/// existence.
47pub async fn authenticate(
48 state: &SharedState,
49 auth_mode: &AuthMode,
50 body: &serde_json::Value,
51 peer_addr: &str,
52) -> crate::Result<(AuthenticatedIdentity, Option<String>)> {
53 let method = body["method"].as_str().unwrap_or("trust");
54
55 match method {
56 "trust" => {
57 if *auth_mode != AuthMode::Trust {
58 state.audit_record(
59 AuditEvent::AuthFailure,
60 None,
61 peer_addr,
62 "trust auth rejected: server requires authentication",
63 );
64 return Err(crate::Error::RejectedAuthz {
65 tenant_id: TenantId::new(0),
66 resource: "trust mode not enabled".into(),
67 });
68 }
69
70 let username = body["username"].as_str().unwrap_or("anonymous");
71 let identity = trust_identity(state, username);
72
73 state.audit_record(
74 AuditEvent::AuthSuccess,
75 Some(identity.tenant_id),
76 peer_addr,
77 &format!("native trust auth: {username}"),
78 );
79 state.auth_metrics.record_auth_success("trust");
80
81 Ok((identity, None))
82 }
83
84 "password" => {
85 let username = body["username"]
86 .as_str()
87 .ok_or_else(|| crate::Error::BadRequest {
88 detail: "missing 'username' for password auth".into(),
89 })?;
90 let password = body["password"]
91 .as_str()
92 .ok_or_else(|| crate::Error::BadRequest {
93 detail: "missing 'password' for password auth".into(),
94 })?;
95
96 // Record the auth start time for constant-time floor enforcement.
97 // All failure returns below sleep until `auth_start + AUTH_FLOOR`
98 // so the reject latency is indistinguishable from a real Argon2
99 // verification, regardless of which gate tripped.
100 let auth_start = std::time::Instant::now();
101
102 // Pre-authentication login rate-limit check (before lockout and
103 // Argon2 verification — cheap exit path). Both the per-IP and
104 // per-username buckets are consulted.

Callers 3

handle_frameMethod · 0.85
handle_authFunction · 0.85
native_password_loginFunction · 0.85

Calls 15

trust_identityFunction · 0.85
nowFunction · 0.85
ArcAuditEmitterClass · 0.85
enforce_auth_floorFunction · 0.85
verify_api_key_identityFunction · 0.85
verify_bearer_tokenFunction · 0.85
audit_recordMethod · 0.80
to_stringMethod · 0.80
check_loginMethod · 0.80
check_lockoutMethod · 0.80
record_login_failureMethod · 0.80

Tested by 1

native_password_loginFunction · 0.68