Handle authentication request.
(&mut self, seq: u64, fields: &RequestFields)
| 458 | |
| 459 | /// Handle authentication request. |
| 460 | async fn handle_auth(&mut self, seq: u64, fields: &RequestFields) -> NativeResponse { |
| 461 | // Re-authentication is not supported on the native protocol. Once a |
| 462 | // session has assembled its three-level admission permit, the identity |
| 463 | // is fixed for the connection's lifetime — allowing re-auth would let |
| 464 | // a client silently swap to a different (database, tenant) scope while |
| 465 | // still holding the original scope's connection slots. |
| 466 | if self.identity.is_some() || self.connection_permit.is_some() { |
| 467 | return NativeResponse::error( |
| 468 | seq, |
| 469 | "0A000", |
| 470 | "already authenticated; reconnect to switch identity", |
| 471 | ); |
| 472 | } |
| 473 | |
| 474 | let auth = match fields { |
| 475 | RequestFields::Text(f) => match &f.auth { |
| 476 | Some(a) => a, |
| 477 | None => { |
| 478 | return NativeResponse::error(seq, "28000", "missing 'auth' field"); |
| 479 | } |
| 480 | }, |
| 481 | _ => { |
| 482 | return NativeResponse::error(seq, "0A000", "unsupported request fields variant"); |
| 483 | } |
| 484 | }; |
| 485 | |
| 486 | match dispatch::handle_auth( |
| 487 | &self.state, |
| 488 | &self.auth_mode, |
| 489 | auth, |
| 490 | &self.peer_addr.to_string(), |
| 491 | ) |
| 492 | .await |
| 493 | { |
| 494 | Ok((identity, warning)) => { |
| 495 | // Phase 2 admission: acquire per-database and per-tenant permits |
| 496 | // now that we know the identity. The database scope is the |
| 497 | // identity's default database (or DEFAULT if none is set). |
| 498 | let db_id = identity |
| 499 | .default_database |
| 500 | .unwrap_or(nodedb_types::DatabaseId::DEFAULT); |
| 501 | let tenant_id = identity.tenant_id; |
| 502 | |
| 503 | let db_permit = match self.admission_registry.try_acquire_database(db_id) { |
| 504 | Ok(p) => p, |
| 505 | Err(e) => { |
| 506 | return NativeResponse::error( |
| 507 | seq, |
| 508 | nodedb_types::error::sqlstate::QUOTA_EXCEEDED, |
| 509 | format!("{e}"), |
| 510 | ); |
| 511 | } |
| 512 | }; |
| 513 | let tenant_permit = |
| 514 | match self.admission_registry.try_acquire_tenant(db_id, tenant_id) { |
| 515 | Ok(p) => p, |
| 516 | Err(e) => { |
| 517 | // db_permit is dropped here, releasing the DB slot. |
no test coverage detected