Skip to main content

gcloud_sdk/
error.rs

1use std::{convert::From, fmt};
2
3/// Represents the details of the [`Error`](struct.Error.html)
4#[derive(Debug)]
5#[non_exhaustive]
6pub enum ErrorKind {
7    /// Errors that can possibly occur while accessing an HTTP server.
8    Http(reqwest::Error),
9    /// An HTTP status other than 2xx.
10    HttpStatus(reqwest::StatusCode),
11    /// Credentials could not be built: no Application Default Credentials were found, or a
12    /// credentials file is malformed or of a type the token cannot be minted from.
13    CredentialsBuild(google_cloud_auth::build_errors::Error),
14    /// Credentials failed to produce a token: a token endpoint refused them or could not be
15    /// reached. [`CredentialsError::is_transient`](google_cloud_auth::errors::CredentialsError::is_transient)
16    /// says whether a retry may succeed.
17    Credentials(google_cloud_auth::errors::CredentialsError),
18    TonicMetadata(tonic::metadata::errors::InvalidMetadataValue),
19    GrpcStatus(tonic::transport::Error),
20    UrlError(hyper::http::uri::InvalidUri),
21    /// An API URL that parses but cannot be connected to: no scheme, a scheme
22    /// other than `http` or `https`, or no host.
23    InvalidApiUrl(String),
24    /// A header value built from user input (user agent, headers, the token itself)
25    /// failed HTTP header validation (e.g. contained a control character).
26    HeaderValue(hyper::header::InvalidHeaderValue),
27    /// The Application Default Credentials hold no service account to mint an ID token
28    /// as. An ID token needs a service account to impersonate, given to
29    /// [`GoogleAuthHeaders::id_token_impersonating`](crate::GoogleAuthHeaders::id_token_impersonating).
30    IdTokenNeedsImpersonation(IdTokenUnsupportedCredentials),
31    /// A `service_account_impersonation_url` in a credentials file that names no
32    /// service account.
33    InvalidImpersonationUrl(String),
34    /// The Application Default Credentials sign with a private key of their own, such as
35    /// a service account key file, and no rustls
36    /// [`CryptoProvider`](rustls::crypto::CryptoProvider) is installed to sign with.
37    ///
38    /// Only reported when the `auth-default-crypto` feature is off. Install a provider
39    /// with `CryptoProvider::install_default` before building a client, or enable that
40    /// feature.
41    CryptoProviderMissing,
42}
43
44/// Credentials that cannot mint an ID token without impersonating a service account
45/// (see [`ErrorKind::IdTokenNeedsImpersonation`]).
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47#[non_exhaustive]
48pub enum IdTokenUnsupportedCredentials {
49    /// `authorized_user` credentials, such as those `gcloud auth application-default login`
50    /// writes.
51    AuthorizedUser,
52    /// `external_account` credentials without a `service_account_impersonation_url`.
53    ExternalAccount,
54    /// `external_account_authorized_user` credentials, such as
55    /// `gcloud auth application-default login` writes for a workforce identity
56    /// federation user.
57    ExternalAccountAuthorizedUser,
58    /// `gdch_service_account` credentials of Google Distributed Cloud Hosted.
59    GdchServiceAccount,
60}
61
62impl fmt::Display for IdTokenUnsupportedCredentials {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Self::AuthorizedUser => write!(f, "authorized_user credentials"),
66            Self::ExternalAccount => write!(
67                f,
68                "external_account credentials without service_account_impersonation_url"
69            ),
70            Self::ExternalAccountAuthorizedUser => {
71                write!(f, "external_account_authorized_user credentials")
72            }
73            Self::GdchServiceAccount => write!(f, "gdch_service_account credentials"),
74        }
75    }
76}
77
78/// Represents errors that can occur during getting token.
79#[derive(Debug)]
80pub struct Error(Box<ErrorKind>);
81
82impl Error {
83    /// Borrow [`ErrorKind`](enum.ErrorKind.html).
84    pub fn kind(&self) -> &ErrorKind {
85        &self.0
86    }
87
88    /// To own [`ErrorKind`](enum.ErrorKind.html).
89    pub fn into_kind(self) -> ErrorKind {
90        *self.0
91    }
92}
93
94impl fmt::Display for Error {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        use ErrorKind::*;
97        match *self.0 {
98            Http(ref e) => write!(f, "http error: {}", e),
99            HttpStatus(ref s) => write!(f, "http status error: {}", s),
100            CredentialsBuild(ref e) => write!(f, "credentials build error: {}", e),
101            Credentials(ref e) => write!(f, "credentials error: {}", e),
102            GrpcStatus(ref e) => write!(f, "Tonic/gRPC error: {}", e),
103            TonicMetadata(ref e) => write!(f, "Tonic metadata error: {}", e),
104            UrlError(ref e) => write!(f, "Url error: {}", e),
105            InvalidApiUrl(ref e) => write!(f, "Invalid API URL: {}", e),
106            HeaderValue(ref e) => write!(f, "invalid header value: {}", e),
107            IdTokenNeedsImpersonation(ref credentials) => write!(
108                f,
109                "{} cannot mint an ID token; give a service account to impersonate",
110                credentials
111            ),
112            InvalidImpersonationUrl(ref url) => write!(
113                f,
114                "service_account_impersonation_url names no service account: {}",
115                url
116            ),
117            CryptoProviderMissing => write!(
118                f,
119                "the credentials sign with a private key and no rustls CryptoProvider is installed; \
120                 install one with CryptoProvider::install_default or enable the auth-default-crypto feature"
121            ),
122        }
123    }
124}
125
126impl std::error::Error for Error {}
127
128impl From<reqwest::Error> for Error {
129    fn from(e: reqwest::Error) -> Self {
130        ErrorKind::Http(e).into()
131    }
132}
133
134impl From<google_cloud_auth::build_errors::Error> for Error {
135    fn from(e: google_cloud_auth::build_errors::Error) -> Self {
136        ErrorKind::CredentialsBuild(e).into()
137    }
138}
139
140impl From<google_cloud_auth::errors::CredentialsError> for Error {
141    fn from(e: google_cloud_auth::errors::CredentialsError) -> Self {
142        ErrorKind::Credentials(e).into()
143    }
144}
145
146impl From<ErrorKind> for Error {
147    fn from(k: ErrorKind) -> Self {
148        Error(Box::new(k))
149    }
150}
151
152impl From<tonic::transport::Error> for Error {
153    fn from(e: tonic::transport::Error) -> Self {
154        ErrorKind::GrpcStatus(e).into()
155    }
156}
157
158impl From<tonic::metadata::errors::InvalidMetadataValue> for Error {
159    fn from(e: tonic::metadata::errors::InvalidMetadataValue) -> Self {
160        ErrorKind::TonicMetadata(e).into()
161    }
162}
163
164impl From<hyper::http::uri::InvalidUri> for Error {
165    fn from(e: hyper::http::uri::InvalidUri) -> Self {
166        ErrorKind::UrlError(e).into()
167    }
168}
169
170impl From<hyper::header::InvalidHeaderValue> for Error {
171    fn from(e: hyper::header::InvalidHeaderValue) -> Self {
172        ErrorKind::HeaderValue(e).into()
173    }
174}
175
176/// Wrapper for the `Result` type with an [`Error`](struct.Error.html).
177pub type Result<T> = std::result::Result<T, Error>;