service_authenticator/
error.rs

1//! Module containing various error types.
2
3use std::borrow::Cow;
4use std::error::Error as StdError;
5use std::fmt;
6use std::io;
7
8use actix_web::client::SendRequestError;
9use serde::Deserialize;
10/// Error returned by the authorization server.
11/// https://tools.ietf.org/html/rfc6749#section-5.2
12/// https://tools.ietf.org/html/rfc8628#section-3.5
13#[derive(Deserialize, Debug, PartialEq, Eq)]
14pub struct AuthError {
15  /// Error code from the server.
16  pub error: AuthErrorCode,
17  /// Human-readable text providing additional information.
18  pub error_description: Option<String>,
19  /// A URI identifying a human-readable web page with information about the error.
20  pub error_uri: Option<String>,
21}
22impl fmt::Display for AuthError {
23  fn fmt(
24    &self,
25    f: &mut fmt::Formatter,
26  ) -> fmt::Result {
27    write!(f, "{}", &self.error.as_str())?;
28    if let Some(desc) = &self.error_description {
29      write!(f, ": {}", desc)?;
30    }
31    if let Some(uri) = &self.error_uri {
32      write!(f, "; See {} for more info", uri)?;
33    }
34    Ok(())
35  }
36}
37impl StdError for AuthError {}
38
39/// The error code returned by the authorization server.
40#[derive(Debug, Clone, Eq, PartialEq)]
41pub enum AuthErrorCode {
42  /// invalid_request
43  InvalidRequest,
44  /// invalid_client
45  InvalidClient,
46  /// invalid_grant
47  InvalidGrant,
48  /// unauthorized_client
49  UnauthorizedClient,
50  /// unsupported_grant_type
51  UnsupportedGrantType,
52  /// invalid_scope
53  InvalidScope,
54  /// access_denied
55  AccessDenied,
56  /// expired_token
57  ExpiredToken,
58  /// other error
59  Other(String),
60}
61
62impl AuthErrorCode {
63  /// The error code as a &str
64  pub fn as_str(&self) -> &str {
65    match self {
66      AuthErrorCode::InvalidRequest => "invalid_request",
67      AuthErrorCode::InvalidClient => "invalid_client",
68      AuthErrorCode::InvalidGrant => "invalid_grant",
69      AuthErrorCode::UnauthorizedClient => "unauthorized_client",
70      AuthErrorCode::UnsupportedGrantType => "unsupported_grant_type",
71      AuthErrorCode::InvalidScope => "invalid_scope",
72      AuthErrorCode::AccessDenied => "access_denied",
73      AuthErrorCode::ExpiredToken => "expired_token",
74      AuthErrorCode::Other(s) => s.as_str(),
75    }
76  }
77
78  fn from_string<'a>(s: impl Into<Cow<'a, str>>) -> AuthErrorCode {
79    let s = s.into();
80    match s.as_ref() {
81      "invalid_request" => AuthErrorCode::InvalidRequest,
82      "invalid_client" => AuthErrorCode::InvalidClient,
83      "invalid_grant" => AuthErrorCode::InvalidGrant,
84      "unauthorized_client" => AuthErrorCode::UnauthorizedClient,
85      "unsupported_grant_type" => AuthErrorCode::UnsupportedGrantType,
86      "invalid_scope" => AuthErrorCode::InvalidScope,
87      "access_denied" => AuthErrorCode::AccessDenied,
88      "expired_token" => AuthErrorCode::ExpiredToken,
89      _ => AuthErrorCode::Other(s.into_owned()),
90    }
91  }
92}
93
94impl From<String> for AuthErrorCode {
95  fn from(s: String) -> Self {
96    AuthErrorCode::from_string(s)
97  }
98}
99
100impl<'a> From<&'a str> for AuthErrorCode {
101  fn from(s: &str) -> Self {
102    AuthErrorCode::from_string(s)
103  }
104}
105
106impl<'de> Deserialize<'de> for AuthErrorCode {
107  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108  where
109    D: serde::Deserializer<'de>,
110  {
111    struct V;
112    impl<'de> serde::de::Visitor<'de> for V {
113      type Value = AuthErrorCode;
114      fn expecting(
115        &self,
116        f: &mut std::fmt::Formatter,
117      ) -> std::fmt::Result {
118        f.write_str("any string")
119      }
120      fn visit_string<E: serde::de::Error>(
121        self,
122        value: String,
123      ) -> Result<Self::Value, E> {
124        Ok(value.into())
125      }
126      fn visit_str<E: serde::de::Error>(
127        self,
128        value: &str,
129      ) -> Result<Self::Value, E> {
130        Ok(value.into())
131      }
132    }
133    deserializer.deserialize_string(V)
134  }
135}
136
137/// A helper type to deserialize either an AuthError or another piece of data.
138#[derive(Deserialize, Debug)]
139#[serde(untagged)]
140pub(crate) enum AuthErrorOr<T> {
141  AuthError(AuthError),
142  Data(T),
143}
144
145impl<T> AuthErrorOr<T> {
146  pub(crate) fn into_result(self) -> Result<T, AuthError> {
147    match self {
148      AuthErrorOr::AuthError(err) => Result::Err(err),
149      AuthErrorOr::Data(value) => Result::Ok(value),
150    }
151  }
152}
153
154/// Encapsulates all possible results of the `token(...)` operation
155#[derive(Debug)]
156pub enum Error {
157  /// Indicates connection failure
158  HttpError(SendRequestError),
159  /// The server returned an error.
160  AuthError(AuthError),
161  /// Error while decoding a JSON response.
162  JSONError(serde_json::Error),
163  /// Error within user input.
164  UserError(String),
165  /// A lower level IO error.
166  LowLevelError(io::Error),
167  /// PayloadError
168  PayloadError(actix_http::error::PayloadError),
169}
170
171impl From<SendRequestError> for Error {
172  fn from(error: SendRequestError) -> Error {
173    Error::HttpError(error)
174  }
175}
176
177impl From<actix_http::error::PayloadError> for Error {
178  fn from(error: actix_http::error::PayloadError) -> Error {
179    Error::PayloadError(error)
180  }
181}
182
183impl From<AuthError> for Error {
184  fn from(value: AuthError) -> Error {
185    Error::AuthError(value)
186  }
187}
188impl From<serde_json::Error> for Error {
189  fn from(value: serde_json::Error) -> Error {
190    Error::JSONError(value)
191  }
192}
193
194impl From<io::Error> for Error {
195  fn from(value: io::Error) -> Error {
196    Error::LowLevelError(value)
197  }
198}
199
200impl fmt::Display for Error {
201  fn fmt(
202    &self,
203    f: &mut fmt::Formatter,
204  ) -> Result<(), fmt::Error> {
205    match *self {
206      Error::HttpError(ref err) => err.fmt(f),
207      Error::AuthError(ref err) => err.fmt(f),
208      Error::JSONError(ref e) => {
209        write!(
210          f,
211          "JSON Error; this might be a bug with unexpected server responses! {}",
212          e
213        )?;
214        Ok(())
215      }
216      Error::UserError(ref s) => s.fmt(f),
217      Error::LowLevelError(ref e) => e.fmt(f),
218      Error::PayloadError(ref e) => e.fmt(f),
219    }
220  }
221}
222
223impl StdError for Error {
224  #[cfg(test)]
225  fn source(&self) -> Option<&(dyn StdError + 'static)> {
226    match *self {
227      Error::HttpError(ref err) => Some(err),
228      Error::AuthError(ref err) => Some(err),
229      Error::JSONError(ref err) => Some(err),
230      Error::LowLevelError(ref err) => Some(err),
231      _ => None,
232    }
233  }
234}