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