reifydb_sub_server/
auth.rs1use std::{error::Error as StdError, fmt};
5
6use reifydb_auth::service::AuthService;
7use reifydb_value::value::identity::IdentityId;
8use tracing::error;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum AuthError {
12 InvalidHeader,
13
14 MissingCredentials,
15
16 InvalidToken,
17
18 Expired,
19
20 InsufficientPermissions,
21
22 Internal,
23}
24
25impl fmt::Display for AuthError {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 match self {
28 AuthError::InvalidHeader => write!(f, "Invalid authorization header"),
29 AuthError::MissingCredentials => write!(f, "Authentication required"),
30 AuthError::InvalidToken => write!(f, "Invalid authentication token"),
31 AuthError::Expired => write!(f, "Authentication token expired"),
32 AuthError::InsufficientPermissions => write!(f, "Insufficient permissions"),
33 AuthError::Internal => write!(f, "Authentication could not be completed"),
34 }
35 }
36}
37
38impl StdError for AuthError {}
39
40pub type AuthResult<T> = Result<T, AuthError>;
41
42pub fn extract_identity_from_auth_header(auth_service: &AuthService, auth_header: &str) -> AuthResult<IdentityId> {
43 match auth_header.strip_prefix("Bearer ") {
44 Some(token) => validate_bearer_token(auth_service, token.trim()),
45 None => Err(AuthError::InvalidHeader),
46 }
47}
48
49pub fn extract_identity_from_ws_auth(auth_service: &AuthService, token: Option<&str>) -> AuthResult<IdentityId> {
50 match token {
51 Some(t) if !t.is_empty() => validate_bearer_token(auth_service, t),
52 _ => Ok(IdentityId::anonymous()),
53 }
54}
55
56fn validate_bearer_token(auth_service: &AuthService, token: &str) -> AuthResult<IdentityId> {
57 if token.is_empty() {
58 return Err(AuthError::InvalidToken);
59 }
60
61 match auth_service.validate_token(token) {
62 Ok(Some(session)) => Ok(session.identity),
63 Ok(None) => Err(AuthError::InvalidToken),
64 Err(e) => {
65 error!("token validation could not reach storage, rejecting the request: {e}");
66 Err(AuthError::Internal)
67 }
68 }
69}
70
71#[cfg(test)]
72pub mod tests {
73 use super::*;
74
75 #[test]
76 fn test_auth_error_display() {
77 assert_eq!(AuthError::InvalidHeader.to_string(), "Invalid authorization header");
78 assert_eq!(AuthError::MissingCredentials.to_string(), "Authentication required");
79 assert_eq!(AuthError::InvalidToken.to_string(), "Invalid authentication token");
80 assert_eq!(AuthError::Expired.to_string(), "Authentication token expired");
81 }
82
83 #[test]
84 fn test_anonymous_identity() {
85 let identity = IdentityId::anonymous();
86 assert!(identity.is_anonymous());
87 }
88
89 #[test]
90 fn test_root_identity() {
91 let identity = IdentityId::root();
92 assert!(identity.is_root());
93 }
94
95 #[test]
96 fn internal_does_not_read_as_a_client_mistake() {
97 let message = AuthError::Internal.to_string();
99 assert_eq!(message, "Authentication could not be completed");
100 assert!(!message.contains("token"), "a storage failure must not point the client at its token");
101 }
102}