Skip to content

Commit

Permalink
Load default credentials from right path on Windows (#112)
Browse files Browse the repository at this point in the history
Load default credentials from right path on Windows

On Windows, the default credentials file is located in the
`%APPDATA%\gcloud\application_default_credentials.json`. The existing
implementation was looking for credentials in
`$HOME/.config/gcloud/application_default_credentials.json`, which
only works on MacOS and Linux.

This change creates a `get_user_credentials_path()` function that has
different implementations for Linux/MacOS and Windows platforms.
  • Loading branch information
andreban authored May 29, 2024
1 parent b9e924f commit 5d93e26
Showing 1 changed file with 35 additions and 6 deletions.
41 changes: 35 additions & 6 deletions src/config_default_credentials.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::path::PathBuf;
use std::sync::Arc;

use async_trait::async_trait;
Expand All @@ -14,7 +15,10 @@ use crate::{Error, TokenProvider};

/// A token provider that uses the default user credentials
///
/// Reads credentials from `.config/gcloud/application_default_credentials.json`.
/// Reads credentials from `.config/gcloud/application_default_credentials.json` on Linux and MacOS
/// or from `%APPDATA%/gcloud/application_default_credentials.json` on Windows.
/// See [GCloud Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials#personal)
/// for details.
#[derive(Debug)]
pub struct ConfigDefaultCredentials {
client: HttpClient,
Expand All @@ -30,11 +34,12 @@ impl ConfigDefaultCredentials {
}

pub(crate) async fn with_client(client: &HttpClient) -> Result<Self, Error> {
debug!("try to load credentials from {}", USER_CREDENTIALS_PATH);
let mut home = home::home_dir().ok_or(Error::Str("home directory not found"))?;
home.push(USER_CREDENTIALS_PATH);
debug!("try to load credentials from configuration");
let mut config_path = config_dir()?;
config_path.push(USER_CREDENTIALS_PATH);
debug!(config = config_path.to_str(), "reading configuration file");

let credentials = AuthorizedUserRefreshToken::from_file(&home)?;
let credentials = AuthorizedUserRefreshToken::from_file(&config_path)?;
debug!(project = ?credentials.quota_project_id, client = credentials.client_id, "found user credentials");

Ok(Self {
Expand Down Expand Up @@ -103,5 +108,29 @@ struct RefreshRequest<'a> {
refresh_token: &'a str,
}

#[cfg(any(target_os = "linux", target_os = "macos"))]
fn config_dir() -> Result<PathBuf, Error> {
let mut home = home::home_dir().ok_or(Error::Str("home directory not found"))?;
home.push(CONFIG_DIR);
Ok(home)
}

#[cfg(target_os = "windows")]
fn config_dir() -> Result<PathBuf, Error> {
let app_data = std::env::var(ENV_APPDATA)
.map_err(|_| Error::Str("APPDATA environment variable not found"))?;
let config_path = PathBuf::from(app_data);
match config_path.exists() {
true => Ok(config_path),
false => Err(Error::Str("APPDATA directory not found")),
}
}

const DEFAULT_TOKEN_GCP_URI: &str = "https://accounts.google.com/o/oauth2/token";
const USER_CREDENTIALS_PATH: &str = ".config/gcloud/application_default_credentials.json";
const USER_CREDENTIALS_PATH: &str = "gcloud/application_default_credentials.json";

#[cfg(any(target_os = "linux", target_os = "macos"))]
const CONFIG_DIR: &str = ".config";

#[cfg(target_os = "windows")]
const ENV_APPDATA: &str = "APPDATA";

0 comments on commit 5d93e26

Please sign in to comment.