mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-13 16:32:56 +00:00
This patch adds a timed LRU cache implementation and a compute node info cache on top of that. Cache entries might expire on their own (default ttl=5mins) or become invalid due to real-world events, e.g. compute node scale-to-zero event, so we add a connection retry loop with a wake-up call. Solved problems: - [x] Find a decent LRU implementation. - [x] Implement timed LRU on top of that. - [x] Cache results of `proxy_wake_compute` API call. - [x] Don't invalidate newer cache entries for the same key. - [x] Add cmdline configuration knobs (requires some refactoring). - [x] Add failed connection estab metric. - [x] Refactor auth backends to make things simpler (retries, cache placement, etc). - [x] Address review comments (add code comments + cleanup). - [x] Retry `/proxy_wake_compute` if we couldn't connect to a compute (e.g. stalled cache entry). - [x] Add high-level description for `TimedLru`. TODOs (will be addressed later): - [ ] Add cache metrics (hit, spurious hit, miss). - [ ] Synchronize http requests across concurrent per-client tasks (https://github.com/neondatabase/neon/pull/3331#issuecomment-1399216069). - [ ] Cache results of `proxy_get_role_secret` API call.
96 lines
2.6 KiB
Rust
96 lines
2.6 KiB
Rust
//! Client authentication mechanisms.
|
|
|
|
pub mod backend;
|
|
pub use backend::BackendType;
|
|
|
|
mod credentials;
|
|
pub use credentials::ClientCredentials;
|
|
|
|
mod password_hack;
|
|
use password_hack::PasswordHackPayload;
|
|
|
|
mod flow;
|
|
pub use flow::*;
|
|
|
|
use crate::{console, error::UserFacingError};
|
|
use std::io;
|
|
use thiserror::Error;
|
|
|
|
/// Convenience wrapper for the authentication error.
|
|
pub type Result<T> = std::result::Result<T, AuthError>;
|
|
|
|
/// Common authentication error.
|
|
#[derive(Debug, Error)]
|
|
pub enum AuthErrorImpl {
|
|
#[error(transparent)]
|
|
Link(#[from] backend::LinkAuthError),
|
|
|
|
#[error(transparent)]
|
|
GetAuthInfo(#[from] console::errors::GetAuthInfoError),
|
|
|
|
#[error(transparent)]
|
|
WakeCompute(#[from] console::errors::WakeComputeError),
|
|
|
|
/// SASL protocol errors (includes [SCRAM](crate::scram)).
|
|
#[error(transparent)]
|
|
Sasl(#[from] crate::sasl::Error),
|
|
|
|
#[error("Unsupported authentication method: {0}")]
|
|
BadAuthMethod(Box<str>),
|
|
|
|
#[error("Malformed password message: {0}")]
|
|
MalformedPassword(&'static str),
|
|
|
|
#[error(
|
|
"Endpoint ID is not specified. \
|
|
Either please upgrade the postgres client library (libpq) for SNI support \
|
|
or pass the endpoint ID (first part of the domain name) as a parameter: '?options=project%3D<endpoint-id>'. \
|
|
See more at https://neon.tech/sni"
|
|
)]
|
|
MissingProjectName,
|
|
|
|
#[error("password authentication failed for user '{0}'")]
|
|
AuthFailed(Box<str>),
|
|
|
|
/// Errors produced by e.g. [`crate::stream::PqStream`].
|
|
#[error(transparent)]
|
|
Io(#[from] io::Error),
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error(transparent)]
|
|
pub struct AuthError(Box<AuthErrorImpl>);
|
|
|
|
impl AuthError {
|
|
pub fn bad_auth_method(name: impl Into<Box<str>>) -> Self {
|
|
AuthErrorImpl::BadAuthMethod(name.into()).into()
|
|
}
|
|
|
|
pub fn auth_failed(user: impl Into<Box<str>>) -> Self {
|
|
AuthErrorImpl::AuthFailed(user.into()).into()
|
|
}
|
|
}
|
|
|
|
impl<E: Into<AuthErrorImpl>> From<E> for AuthError {
|
|
fn from(e: E) -> Self {
|
|
Self(Box::new(e.into()))
|
|
}
|
|
}
|
|
|
|
impl UserFacingError for AuthError {
|
|
fn to_string_client(&self) -> String {
|
|
use AuthErrorImpl::*;
|
|
match self.0.as_ref() {
|
|
Link(e) => e.to_string_client(),
|
|
GetAuthInfo(e) => e.to_string_client(),
|
|
WakeCompute(e) => e.to_string_client(),
|
|
Sasl(e) => e.to_string_client(),
|
|
AuthFailed(_) => self.to_string(),
|
|
BadAuthMethod(_) => self.to_string(),
|
|
MalformedPassword(_) => self.to_string(),
|
|
MissingProjectName => self.to_string(),
|
|
Io(_) => "Internal error".to_string(),
|
|
}
|
|
}
|
|
}
|