Line data Source code
1 : //! Client authentication mechanisms.
2 :
3 : pub mod backend;
4 : pub use backend::Backend;
5 :
6 : mod credentials;
7 : pub(crate) use credentials::{
8 : ComputeUserInfoMaybeEndpoint, ComputeUserInfoParseError, IpPattern, check_peer_addr_is_in_list,
9 : endpoint_sni,
10 : };
11 :
12 : mod password_hack;
13 : use password_hack::PasswordHackPayload;
14 : pub(crate) use password_hack::parse_endpoint_param;
15 :
16 : mod flow;
17 : use std::io;
18 : use std::net::IpAddr;
19 :
20 : pub(crate) use flow::*;
21 : use thiserror::Error;
22 : use tokio::time::error::Elapsed;
23 :
24 : use crate::auth::backend::jwt::JwtError;
25 : use crate::control_plane;
26 : use crate::error::{ReportableError, UserFacingError};
27 :
28 : /// Convenience wrapper for the authentication error.
29 : pub(crate) type Result<T> = std::result::Result<T, AuthError>;
30 :
31 : /// Common authentication error.
32 : #[derive(Debug, Error)]
33 : pub(crate) enum AuthError {
34 : #[error(transparent)]
35 : ConsoleRedirect(#[from] backend::ConsoleRedirectError),
36 :
37 : #[error(transparent)]
38 : GetAuthInfo(#[from] control_plane::errors::GetAuthInfoError),
39 :
40 : /// SASL protocol errors (includes [SCRAM](crate::scram)).
41 : #[error(transparent)]
42 : Sasl(#[from] crate::sasl::Error),
43 :
44 : #[error("Unsupported authentication method: {0}")]
45 : BadAuthMethod(Box<str>),
46 :
47 : #[error("Malformed password message: {0}")]
48 : MalformedPassword(&'static str),
49 :
50 : #[error(
51 : "Endpoint ID is not specified. \
52 : Either please upgrade the postgres client library (libpq) for SNI support \
53 : or pass the endpoint ID (first part of the domain name) as a parameter: '?options=endpoint%3D<endpoint-id>'. \
54 : See more at https://neon.tech/sni"
55 : )]
56 : MissingEndpointName,
57 :
58 : #[error(
59 : "VPC endpoint ID is not specified. \
60 : This endpoint requires a VPC endpoint ID to connect."
61 : )]
62 : MissingVPCEndpointId,
63 :
64 : #[error("password authentication failed for user '{0}'")]
65 : PasswordFailed(Box<str>),
66 :
67 : /// Errors produced by e.g. [`crate::stream::PqStream`].
68 : #[error(transparent)]
69 : Io(#[from] io::Error),
70 :
71 : #[error(
72 : "This IP address {0} is not allowed to connect to this endpoint. \
73 : Please add it to the allowed list in the Neon console. \
74 : Make sure to check for IPv4 or IPv6 addresses."
75 : )]
76 : IpAddressNotAllowed(IpAddr),
77 :
78 : #[error("This connection is trying to access this endpoint from a blocked network.")]
79 : NetworkNotAllowed,
80 :
81 : #[error(
82 : "This VPC endpoint id {0} is not allowed to connect to this endpoint. \
83 : Please add it to the allowed list in the Neon console."
84 : )]
85 : VpcEndpointIdNotAllowed(String),
86 :
87 : #[error("Too many connections to this endpoint. Please try again later.")]
88 : TooManyConnections,
89 :
90 : #[error("Authentication timed out")]
91 : UserTimeout(Elapsed),
92 :
93 : #[error("Disconnected due to inactivity after {0}.")]
94 : ConfirmationTimeout(humantime::Duration),
95 :
96 : #[error(transparent)]
97 : Jwt(#[from] JwtError),
98 : }
99 :
100 : impl AuthError {
101 0 : pub(crate) fn bad_auth_method(name: impl Into<Box<str>>) -> Self {
102 0 : AuthError::BadAuthMethod(name.into())
103 0 : }
104 :
105 0 : pub(crate) fn password_failed(user: impl Into<Box<str>>) -> Self {
106 0 : AuthError::PasswordFailed(user.into())
107 0 : }
108 :
109 0 : pub(crate) fn ip_address_not_allowed(ip: IpAddr) -> Self {
110 0 : AuthError::IpAddressNotAllowed(ip)
111 0 : }
112 :
113 0 : pub(crate) fn vpc_endpoint_id_not_allowed(id: String) -> Self {
114 0 : AuthError::VpcEndpointIdNotAllowed(id)
115 0 : }
116 :
117 0 : pub(crate) fn too_many_connections() -> Self {
118 0 : AuthError::TooManyConnections
119 0 : }
120 :
121 0 : pub(crate) fn is_password_failed(&self) -> bool {
122 0 : matches!(self, AuthError::PasswordFailed(_))
123 0 : }
124 :
125 0 : pub(crate) fn user_timeout(elapsed: Elapsed) -> Self {
126 0 : AuthError::UserTimeout(elapsed)
127 0 : }
128 :
129 0 : pub(crate) fn confirmation_timeout(timeout: humantime::Duration) -> Self {
130 0 : AuthError::ConfirmationTimeout(timeout)
131 0 : }
132 : }
133 :
134 : impl UserFacingError for AuthError {
135 0 : fn to_string_client(&self) -> String {
136 0 : match self {
137 0 : Self::ConsoleRedirect(e) => e.to_string_client(),
138 0 : Self::GetAuthInfo(e) => e.to_string_client(),
139 0 : Self::Sasl(e) => e.to_string_client(),
140 0 : Self::PasswordFailed(_) => self.to_string(),
141 0 : Self::BadAuthMethod(_) => self.to_string(),
142 0 : Self::MalformedPassword(_) => self.to_string(),
143 0 : Self::MissingEndpointName => self.to_string(),
144 0 : Self::MissingVPCEndpointId => self.to_string(),
145 0 : Self::Io(_) => "Internal error".to_string(),
146 0 : Self::IpAddressNotAllowed(_) => self.to_string(),
147 0 : Self::NetworkNotAllowed => self.to_string(),
148 0 : Self::VpcEndpointIdNotAllowed(_) => self.to_string(),
149 0 : Self::TooManyConnections => self.to_string(),
150 0 : Self::UserTimeout(_) => self.to_string(),
151 0 : Self::ConfirmationTimeout(_) => self.to_string(),
152 0 : Self::Jwt(_) => self.to_string(),
153 : }
154 0 : }
155 : }
156 :
157 : impl ReportableError for AuthError {
158 0 : fn get_error_kind(&self) -> crate::error::ErrorKind {
159 0 : match self {
160 0 : Self::ConsoleRedirect(e) => e.get_error_kind(),
161 0 : Self::GetAuthInfo(e) => e.get_error_kind(),
162 0 : Self::Sasl(e) => e.get_error_kind(),
163 0 : Self::PasswordFailed(_) => crate::error::ErrorKind::User,
164 0 : Self::BadAuthMethod(_) => crate::error::ErrorKind::User,
165 0 : Self::MalformedPassword(_) => crate::error::ErrorKind::User,
166 0 : Self::MissingEndpointName => crate::error::ErrorKind::User,
167 0 : Self::MissingVPCEndpointId => crate::error::ErrorKind::User,
168 0 : Self::Io(_) => crate::error::ErrorKind::ClientDisconnect,
169 0 : Self::IpAddressNotAllowed(_) => crate::error::ErrorKind::User,
170 0 : Self::NetworkNotAllowed => crate::error::ErrorKind::User,
171 0 : Self::VpcEndpointIdNotAllowed(_) => crate::error::ErrorKind::User,
172 0 : Self::TooManyConnections => crate::error::ErrorKind::RateLimit,
173 0 : Self::UserTimeout(_) => crate::error::ErrorKind::User,
174 0 : Self::ConfirmationTimeout(_) => crate::error::ErrorKind::User,
175 0 : Self::Jwt(_) => crate::error::ErrorKind::User,
176 : }
177 0 : }
178 : }
|