Skip to main content

cloud_sdk_reqwest/shared/credentials/
error.rs

1use core::fmt;
2
3use super::super::BearerTokenError;
4
5/// Credential-state access failure.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum CredentialStateError {
8    /// The short-lived credential-state lock could not be recovered.
9    Unavailable,
10}
11
12impl_static_error!(CredentialStateError,
13    Self::Unavailable => "credential state is unavailable",
14);
15
16/// Validated token rotation failure.
17#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum CredentialUpdateError {
19    /// The credential state could not be changed.
20    StateUnavailable,
21    /// The monotonic credential generation cannot advance.
22    GenerationExhausted,
23    /// An expiring lifecycle requires a replacement lifetime.
24    LifetimeRequired,
25    /// A static lifecycle cannot be changed into an expiring lifecycle.
26    LifetimeForbidden,
27}
28
29impl_static_error!(CredentialUpdateError,
30    Self::StateUnavailable => "credential state is unavailable",
31    Self::GenerationExhausted => "credential generation is exhausted",
32    Self::LifetimeRequired => "expiring credential replacement requires a lifetime",
33    Self::LifetimeForbidden => "static credential replacement forbids a lifetime",
34);
35
36/// Time-qualified refresh-handoff failure.
37#[derive(Clone, Copy, Debug, Eq, PartialEq)]
38pub enum RefreshHandoffError {
39    /// Expiring credentials require a time-qualified refresh handoff.
40    ExplicitTimeRequired,
41    /// A static credential has no expiry-qualified refresh window.
42    LifetimeNotConfigured,
43    /// The credential has not reached its refresh window.
44    RefreshNotRequired,
45    /// The credential has reached its exclusive expiry.
46    CredentialExpired,
47    /// The supplied caller time precedes lifetime observation.
48    ClockRollback,
49}
50
51impl_static_error!(RefreshHandoffError,
52    Self::ExplicitTimeRequired => "expiring credential refresh requires explicit caller time",
53    Self::LifetimeNotConfigured => "credential lifetime is not configured",
54    Self::RefreshNotRequired => "credential has not reached its refresh window",
55    Self::CredentialExpired => "credential has expired",
56    Self::ClockRollback => "credential clock moved before lifetime observation",
57);
58
59/// Bearer-token validation or rotation failure.
60#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61pub enum TokenRotationError {
62    /// The replacement bearer token was rejected before state changed.
63    TokenRejected(BearerTokenError),
64    /// The credential state could not be changed.
65    StateUnavailable,
66    /// The monotonic credential generation cannot advance.
67    GenerationExhausted,
68    /// An expiring lifecycle requires a replacement lifetime.
69    LifetimeRequired,
70    /// A static lifecycle cannot be changed into an expiring lifecycle.
71    LifetimeForbidden,
72}
73
74impl fmt::Display for TokenRotationError {
75    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
76        formatter.write_str(match self {
77            Self::TokenRejected(_) => "replacement bearer token was rejected",
78            Self::StateUnavailable => "credential state is unavailable",
79            Self::GenerationExhausted => "credential generation is exhausted",
80            Self::LifetimeRequired => "expiring credential replacement requires a lifetime",
81            Self::LifetimeForbidden => "static credential replacement forbids a lifetime",
82        })
83    }
84}
85
86impl core::error::Error for TokenRotationError {
87    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
88        match self {
89            Self::TokenRejected(error) => Some(error),
90            Self::StateUnavailable
91            | Self::GenerationExhausted
92            | Self::LifetimeRequired
93            | Self::LifetimeForbidden => None,
94        }
95    }
96}
97
98/// Compare-and-swap bearer refresh failure.
99#[derive(Clone, Copy, Debug, Eq, PartialEq)]
100pub enum TokenRefreshError {
101    /// The replacement bearer token was rejected before state changed.
102    TokenRejected(BearerTokenError),
103    /// A newer rotation or refresh superseded this handoff.
104    StaleGeneration,
105    /// The refresh handoff belongs to a different credential lifecycle.
106    CredentialMismatch,
107    /// The credential state could not be changed.
108    StateUnavailable,
109    /// The monotonic credential generation cannot advance.
110    GenerationExhausted,
111    /// An expiring lifecycle requires a replacement lifetime.
112    LifetimeRequired,
113    /// A static lifecycle cannot be changed into an expiring lifecycle.
114    LifetimeForbidden,
115}
116
117impl fmt::Display for TokenRefreshError {
118    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
119        formatter.write_str(match self {
120            Self::TokenRejected(_) => "refreshed bearer token was rejected",
121            Self::StaleGeneration => "credential refresh generation is stale",
122            Self::CredentialMismatch => "credential refresh handoff belongs to another credential",
123            Self::StateUnavailable => "credential state is unavailable",
124            Self::GenerationExhausted => "credential generation is exhausted",
125            Self::LifetimeRequired => "expiring credential refresh requires a lifetime",
126            Self::LifetimeForbidden => "static credential refresh forbids a lifetime",
127        })
128    }
129}
130
131impl core::error::Error for TokenRefreshError {
132    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
133        match self {
134            Self::TokenRejected(error) => Some(error),
135            Self::StaleGeneration
136            | Self::CredentialMismatch
137            | Self::StateUnavailable
138            | Self::GenerationExhausted
139            | Self::LifetimeRequired
140            | Self::LifetimeForbidden => None,
141        }
142    }
143}