TLA Line data Source code
1 : //! Client authentication mechanisms.
2 :
3 : pub mod backend;
4 : pub use backend::BackendType;
5 :
6 : mod credentials;
7 : pub use credentials::{check_peer_addr_is_in_list, ClientCredentials};
8 :
9 : mod password_hack;
10 : pub use password_hack::parse_endpoint_param;
11 : use password_hack::PasswordHackPayload;
12 :
13 : mod flow;
14 : pub use flow::*;
15 :
16 : use crate::{console, error::UserFacingError};
17 : use std::io;
18 : use thiserror::Error;
19 :
20 : /// Convenience wrapper for the authentication error.
21 : pub type Result<T> = std::result::Result<T, AuthError>;
22 :
23 : /// Common authentication error.
24 CBC 35 : #[derive(Debug, Error)]
25 : pub enum AuthErrorImpl {
26 : #[error(transparent)]
27 : Link(#[from] backend::LinkAuthError),
28 :
29 : #[error(transparent)]
30 : GetAuthInfo(#[from] console::errors::GetAuthInfoError),
31 :
32 : #[error(transparent)]
33 : WakeCompute(#[from] console::errors::WakeComputeError),
34 :
35 : /// SASL protocol errors (includes [SCRAM](crate::scram)).
36 : #[error(transparent)]
37 : Sasl(#[from] crate::sasl::Error),
38 :
39 : #[error("Unsupported authentication method: {0}")]
40 : BadAuthMethod(Box<str>),
41 :
42 : #[error("Malformed password message: {0}")]
43 : MalformedPassword(&'static str),
44 :
45 : #[error(
46 : "Endpoint ID is not specified. \
47 : Either please upgrade the postgres client library (libpq) for SNI support \
48 : or pass the endpoint ID (first part of the domain name) as a parameter: '?options=endpoint%3D<endpoint-id>'. \
49 : See more at https://neon.tech/sni"
50 : )]
51 : MissingEndpointName,
52 :
53 : #[error("password authentication failed for user '{0}'")]
54 : AuthFailed(Box<str>),
55 :
56 : /// Errors produced by e.g. [`crate::stream::PqStream`].
57 : #[error(transparent)]
58 : Io(#[from] io::Error),
59 :
60 : #[error(
61 : "This IP address is not allowed to connect to this endpoint. \
62 : Please add it to the allowed list in the Neon console."
63 : )]
64 : IpAddressNotAllowed,
65 :
66 : #[error("Too many connections to this endpoint. Please try again later.")]
67 : TooManyConnections,
68 : }
69 :
70 35 : #[derive(Debug, Error)]
71 : #[error(transparent)]
72 : pub struct AuthError(Box<AuthErrorImpl>);
73 :
74 : impl AuthError {
75 UBC 0 : pub fn bad_auth_method(name: impl Into<Box<str>>) -> Self {
76 0 : AuthErrorImpl::BadAuthMethod(name.into()).into()
77 0 : }
78 :
79 CBC 3 : pub fn auth_failed(user: impl Into<Box<str>>) -> Self {
80 3 : AuthErrorImpl::AuthFailed(user.into()).into()
81 3 : }
82 :
83 4 : pub fn ip_address_not_allowed() -> Self {
84 4 : AuthErrorImpl::IpAddressNotAllowed.into()
85 4 : }
86 :
87 UBC 0 : pub fn too_many_connections() -> Self {
88 0 : AuthErrorImpl::TooManyConnections.into()
89 0 : }
90 :
91 CBC 3 : pub fn is_auth_failed(&self) -> bool {
92 3 : matches!(self.0.as_ref(), AuthErrorImpl::AuthFailed(_))
93 3 : }
94 : }
95 :
96 : impl<E: Into<AuthErrorImpl>> From<E> for AuthError {
97 18 : fn from(e: E) -> Self {
98 18 : Self(Box::new(e.into()))
99 18 : }
100 : }
101 :
102 : impl UserFacingError for AuthError {
103 11 : fn to_string_client(&self) -> String {
104 11 : use AuthErrorImpl::*;
105 11 : match self.0.as_ref() {
106 UBC 0 : Link(e) => e.to_string_client(),
107 CBC 4 : GetAuthInfo(e) => e.to_string_client(),
108 UBC 0 : WakeCompute(e) => e.to_string_client(),
109 0 : Sasl(e) => e.to_string_client(),
110 CBC 3 : AuthFailed(_) => self.to_string(),
111 UBC 0 : BadAuthMethod(_) => self.to_string(),
112 0 : MalformedPassword(_) => self.to_string(),
113 CBC 1 : MissingEndpointName => self.to_string(),
114 UBC 0 : Io(_) => "Internal error".to_string(),
115 CBC 3 : IpAddressNotAllowed => self.to_string(),
116 UBC 0 : TooManyConnections => self.to_string(),
117 : }
118 CBC 11 : }
119 : }
|