winding-lines commented on code in PR #3541:
URL: https://github.com/apache/arrow-rs/pull/3541#discussion_r1085358261
##########
object_store/src/gcp/credential.rs:
##########
@@ -222,3 +327,118 @@ fn b64_encode_obj<T: serde::Serialize>(obj: &T) ->
Result<String> {
let string = serde_json::to_string(obj).context(EncodeSnafu)?;
Ok(BASE64_URL_SAFE_NO_PAD.encode(string))
}
+
+/// A provider that uses the Google Cloud Platform metadata server to fetch a
token.
+#[derive(Debug, Default)]
+pub struct InstanceCredentialProvider {
+ audience: String,
+}
+
+impl InstanceCredentialProvider {
+ pub fn new<T: Into<String>>(audience: T) -> Self {
+ Self {
+ audience: audience.into(),
+ }
+ }
+}
+
+#[async_trait]
+impl TokenProvider for InstanceCredentialProvider {
+ async fn fetch_token(
+ &self,
+ client: &Client,
+ retry: &RetryConfig,
+ ) -> Result<TemporaryToken<String>> {
+ println!("fetching token from metadata server");
+ const TOKEN_URL: &str =
+
"http://metadata/computeMetadata/v1/instance/service-accounts/default/token";
+ let response: TokenResponse = client
+ .request(Method::GET, TOKEN_URL)
+ .header("Metadata-Flavor", "Google")
+ .query(&[("audience", &self.audience)])
+ .send_retry(retry)
+ .await
+ .context(TokenRequestSnafu)?
+ .json()
+ .await
+ .context(TokenResponseBodySnafu)?;
+ let token = TemporaryToken {
+ token: response.access_token,
+ expiry: Instant::now() + Duration::from_secs(response.expires_in),
+ };
+ Ok(token)
+ }
+}
+
+/// A deserialized `application_default_credentials.json`-file.
+#[derive(serde::Deserialize, Debug)]
+pub struct ApplicationDefaultCredentials {
+ client_id: String,
+ client_secret: String,
+ refresh_token: String,
+ #[serde(rename = "type")]
+ type_: String,
+}
+
+impl ApplicationDefaultCredentials {
+ const DEFAULT_TOKEN_GCP_URI: &'static str =
+ "https://accounts.google.com/o/oauth2/token";
+ const CREDENTIALS_PATH: &'static str =
+ ".config/gcloud/application_default_credentials.json";
+ const EXPECTED_TYPE: &str = "authorized_user";
+
+ // Create a new application default credential in the following situations:
+ // 1. a file is passed in and the type matches.
+ // 2. without argument if the well-known configuration file is present.
+ pub fn new(path: Option<&str>) -> Result<Option<Self>, Error> {
+ if let Some(path) = path {
+ if let Ok(credentials) = reader_credentials_file::<Self>(path) {
+ if credentials.type_ == Self::EXPECTED_TYPE {
+ return Ok(Some(credentials));
+ }
+ }
+ // Other credential mechanisms may be able to use this path.
+ return Ok(None);
Review Comment:
My thinking here is that in addition to the Application Default Credentials
a configuration file is also used by Workload Identity Federation. So I wanted
to leave this open for additional processing. I see your point that the
additional implementation is not part of this PR so we should have the error
checking to be consistent.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]