Skip to content

Commit

Permalink
Add from_credentials_json function (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
brocaar authored Jan 24, 2022
1 parent 9624a24 commit f6de1d2
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 20 deletions.
13 changes: 12 additions & 1 deletion src/custom_service_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ impl CustomServiceAccount {
tokens: RwLock::new(HashMap::new()),
})
}

pub(crate) fn from_json(s: &str) -> Result<Self, Error> {
Ok(Self {
credentials: ApplicationCredentials::from_json(s)?,
tokens: RwLock::new(HashMap::new()),
})
}
}

#[async_trait]
Expand Down Expand Up @@ -99,6 +106,10 @@ impl ApplicationCredentials {
let content = fs::read_to_string(path)
.await
.map_err(Error::ApplicationProfilePath)?;
Ok(serde_json::from_str(&content).map_err(Error::ApplicationProfileFormat)?)
ApplicationCredentials::from_json(&content)
}

fn from_json(s: &str) -> Result<ApplicationCredentials, Error> {
serde_json::from_str(s).map_err(Error::ApplicationProfileFormat)
}
}
3 changes: 1 addition & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ pub enum Error {
/// Application can authenticate against GCP using:
///
/// - Default service account - available inside GCP platform using GCP Instance Metadata server
/// - Service account file - provided using `GOOGLE_APPLICATION_CREDENTIALS` with path
/// - GCloud authorized user - retrieved using `gcloud auth` command
///
/// All authentication methods have been tested and none succeeded.
/// Service account file can be downloaded from GCP in json format.
#[error("No available authentication method was discovered")]
NoAuthMethod(Box<Error>, Box<Error>, Box<Error>, Box<Error>),
NoAuthMethod(Box<Error>, Box<Error>, Box<Error>),

/// Error in underlying RustTLS library.
/// Might signal problem with establishing secure connection using trusted certificates
Expand Down
45 changes: 28 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,26 @@ use std::path::Path;
use hyper::Client;
use hyper_rustls::HttpsConnectorBuilder;

/// Initialize GCP authentication based on a credentials file
/// Initialize GCP authentication based on a credentials file path
///
/// Returns `AuthenticationManager` which can be used to obtain tokens
pub async fn from_credentials_file<T: AsRef<Path>>(
path: T,
) -> Result<AuthenticationManager, Error> {
get_authentication_manager(Some(path.as_ref())).await
let custom = CustomServiceAccount::from_file(path.as_ref()).await?;
get_authentication_manager(Some(custom)).await
}

/// Initialize GCP authentication based on a JSON string
///
/// Returns `AuthenticationManager` which can be used to obtain tokens
pub async fn from_credentials_json(s: &str) -> Result<AuthenticationManager, Error> {
let custom = CustomServiceAccount::from_json(s)?;
get_authentication_manager(Some(custom)).await
}

async fn get_authentication_manager(
credential_path: Option<&Path>,
custom: Option<CustomServiceAccount>,
) -> Result<AuthenticationManager, Error> {
#[cfg(feature = "webpki-roots")]
let https = HttpsConnectorBuilder::new().with_webpki_roots();
Expand All @@ -102,18 +111,7 @@ async fn get_authentication_manager(
let client =
Client::builder().build::<_, hyper::Body>(https.https_or_http().enable_http2().build());

let custom = match credential_path {
Some(path) => CustomServiceAccount::from_file(path).await,
None => match std::env::var("GOOGLE_APPLICATION_CREDENTIALS") {
Ok(path) => {
log::debug!("Trying GOOGLE_APPLICATION_CREDENTIALS env var");
CustomServiceAccount::from_file(Path::new(&path)).await
}
Err(_) => Err(Error::ApplicationProfileMissing),
},
};

if let Ok(service_account) = custom {
if let Some(service_account) = custom {
log::debug!("Using CustomServiceAccount");
return Ok(AuthenticationManager::new(
client,
Expand Down Expand Up @@ -142,7 +140,6 @@ async fn get_authentication_manager(
return Ok(AuthenticationManager::new(client, Box::new(user_account)));
}
Err(Error::NoAuthMethod(
Box::new(custom.unwrap_err()),
Box::new(gcloud.unwrap_err()),
Box::new(default.unwrap_err()),
Box::new(user.unwrap_err()),
Expand All @@ -153,5 +150,19 @@ async fn get_authentication_manager(
/// Returns `AuthenticationManager` which can be used to obtain tokens
pub async fn init() -> Result<AuthenticationManager, Error> {
log::debug!("Initializing gcp_auth");
get_authentication_manager(None).await

// will return an error if the environment variable isn’t set, in which case custom is set to
// none.
let custom = match std::env::var("GOOGLE_APPLICATION_CREDENTIALS") {
Ok(path) => {
log::debug!("Reading credentials file from GOOGLE_APPLICATION_CREDENTIALS env var");

// We know that GOOGLE_APPLICATION_CREDENTIALS exists, read the file and return an
// error in case of failure.
Some(CustomServiceAccount::from_file(Path::new(&path)).await?)
}
Err(_) => None,
};

get_authentication_manager(custom).await
}

0 comments on commit f6de1d2

Please sign in to comment.