winding-lines commented on code in PR #3541:
URL: https://github.com/apache/arrow-rs/pull/3541#discussion_r1086177439


##########
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);
+        }
+        if let Some(home) = env::var_os("HOME") {

Review Comment:
   `dirs` look like a good option but you mentioned wanting to keep the 
dependencies lean :)



-- 
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: github-unsubscr...@arrow.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to