Skip to content

Commit

Permalink
Merge branch 'hrvolapeter-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
shane committed Aug 4, 2021
2 parents a1dad6c + 9610aac commit 9378676
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 102 deletions.
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
time: "13:00"
open-pull-requests-limit: 99
58 changes: 58 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CI

on:
push:
branches: ['main']
pull_request:
schedule:
- cron: "25 6 * * 5"

jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust: [stable, beta]
exclude:
- os: macos-latest
rust: beta

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- uses: actions-rs/cargo@v1
with:
command: check
args: --all-features --all-targets

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
components: rustfmt, clippy
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- uses: actions-rs/cargo@v1
if: always()
with:
command: clippy
args: --workspace --all-targets --all-features -- -D warnings

audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: EmbarkStudios/cargo-deny-action@v1
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ which = "4.2"
async-trait = "0.1"
thiserror = "1.0"
dirs-next = "2.0"

[dev-dependencies]
env_logger = "0.9"
tokio = { version = "1.1", features = ["macros", "rt-multi-thread"] }
9 changes: 9 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[licenses]
allow-osi-fsf-free = "either"
copyleft = "deny"
allow = ["MPL-2.0"]

[[licenses.clarify]]
name = "ring"
expression = "ISC AND MIT AND OpenSSL"
license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }]
17 changes: 0 additions & 17 deletions examples/Cargo.toml

This file was deleted.

4 changes: 3 additions & 1 deletion examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
async fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::init();
let authentication_manager = gcp_auth::init().await?;
let _token = authentication_manager.get_token(&["https://www.googleapis.com/auth/cloud-platform"]).await?;
let _token = authentication_manager
.get_token(&["https://www.googleapis.com/auth/cloud-platform"])
.await?;
Ok(())
}
7 changes: 5 additions & 2 deletions src/authentication_manager.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use crate::prelude::*;
use async_trait::async_trait;

use crate::error::Error;
use crate::types::{HyperClient, Token};

#[async_trait]
pub trait ServiceAccount: Send + Sync {
pub(crate) trait ServiceAccount: Send + Sync {
async fn project_id(&self, client: &HyperClient) -> Result<String, Error>;
fn get_token(&self, scopes: &[&str]) -> Option<Token>;
async fn refresh_token(&self, client: &HyperClient, scopes: &[&str]) -> Result<Token, Error>;
Expand Down
57 changes: 28 additions & 29 deletions src/custom_service_account.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
use crate::authentication_manager::ServiceAccount;
use crate::error::Error::AplicationProfileMissing;
use crate::prelude::*;
use std::collections::HashMap;
use std::path::Path;
use std::sync::RwLock;

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use tokio::fs;

use crate::authentication_manager::ServiceAccount;
use crate::error::Error;
use crate::types::{HyperClient, Token};
use crate::util::HyperExt;

#[derive(Debug)]
pub struct CustomServiceAccount {
pub(crate) struct CustomServiceAccount {
tokens: RwLock<HashMap<Vec<String>, Token>>,
credentials: ApplicationCredentials,
}

impl CustomServiceAccount {
pub async fn from_file(path: &str) -> Result<Self, Error> {
let credentials = ApplicationCredentials::from_file(path).await?;
pub(crate) async fn from_file(path: &Path) -> Result<Self, Error> {
Ok(Self {
credentials,
credentials: ApplicationCredentials::from_file(path).await?,
tokens: RwLock::new(HashMap::new()),
})
}

pub async fn from_env() -> Result<Self, Error> {
const GOOGLE_APPLICATION_CREDENTIALS: &str = "GOOGLE_APPLICATION_CREDENTIALS";
let path =
std::env::var(GOOGLE_APPLICATION_CREDENTIALS).map_err(|_| AplicationProfileMissing)?;
CustomServiceAccount::from_file(&path).await
}
}

#[async_trait]
Expand All @@ -43,12 +42,12 @@ impl ServiceAccount for CustomServiceAccount {

async fn refresh_token(&self, client: &HyperClient, scopes: &[&str]) -> Result<Token, Error> {
use crate::jwt::Claims;
use crate::jwt::JWTSigner;
use crate::jwt::JwtSigner;
use crate::jwt::GRANT_TYPE;
use hyper::header;
use url::form_urlencoded;

let signer = JWTSigner::new(&self.credentials.private_key)?;
let signer = JwtSigner::new(&self.credentials.private_key)?;

let claims = Claims::new(&self.credentials, scopes, None);
let signed = signer.sign_claims(&claims).map_err(Error::TLSError)?;
Expand All @@ -73,33 +72,33 @@ impl ServiceAccount for CustomServiceAccount {
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ApplicationCredentials {
pub r#type: Option<String>,
pub(crate) struct ApplicationCredentials {
pub(crate) r#type: Option<String>,
/// project_id
pub project_id: Option<String>,
pub(crate) project_id: Option<String>,
/// private_key_id
pub private_key_id: Option<String>,
pub(crate) private_key_id: Option<String>,
/// private_key
pub private_key: String,
pub(crate) private_key: String,
/// client_email
pub client_email: String,
pub(crate) client_email: String,
/// client_id
pub client_id: Option<String>,
pub(crate) client_id: Option<String>,
/// auth_uri
pub auth_uri: Option<String>,
pub(crate) auth_uri: Option<String>,
/// token_uri
pub token_uri: String,
pub(crate) token_uri: String,
/// auth_provider_x509_cert_url
pub auth_provider_x509_cert_url: Option<String>,
pub(crate) auth_provider_x509_cert_url: Option<String>,
/// client_x509_cert_url
pub client_x509_cert_url: Option<String>,
pub(crate) client_x509_cert_url: Option<String>,
}

impl ApplicationCredentials {
async fn from_file<T: AsRef<Path>>(path: T) -> Result<ApplicationCredentials, Error> {
let content = fs::read_to_string(path)
.await
.map_err(Error::AplicationProfilePath)?;
Ok(serde_json::from_str(&content).map_err(Error::AplicationProfileFormat)?)
.map_err(Error::ApplicationProfilePath)?;
Ok(serde_json::from_str(&content).map_err(Error::ApplicationProfileFormat)?)
}
}
35 changes: 20 additions & 15 deletions src/default_authorized_user.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
use crate::authentication_manager::ServiceAccount;
use crate::prelude::*;
use hyper::body::Body;
use hyper::Method;
use std::path::Path;
use std::sync::RwLock;

use async_trait::async_trait;
use hyper::body::Body;
use hyper::{Method, Request};
use serde::{Deserialize, Serialize};
use tokio::fs;

use crate::authentication_manager::ServiceAccount;
use crate::error::Error;
use crate::types::{HyperClient, Token};
use crate::util::HyperExt;

#[derive(Debug)]
pub struct DefaultAuthorizedUser {
pub(crate) struct DefaultAuthorizedUser {
token: RwLock<Token>,
}

Expand All @@ -15,7 +22,7 @@ impl DefaultAuthorizedUser {
const USER_CREDENTIALS_PATH: &'static str =
".config/gcloud/application_default_credentials.json";

pub async fn new(client: &HyperClient) -> Result<Self, Error> {
pub(crate) async fn new(client: &HyperClient) -> Result<Self, Error> {
let token = RwLock::new(Self::get_token(client).await?);
Ok(Self { token })
}
Expand All @@ -33,10 +40,8 @@ impl DefaultAuthorizedUser {
log::debug!("Loading user credentials file");
let mut home = dirs_next::home_dir().ok_or(Error::NoHomeDir)?;
home.push(Self::USER_CREDENTIALS_PATH);
let cred =
UserCredentials::from_file(home.display().to_string())
.await?;
let req = Self::build_token_request(&RerfeshRequest {
let cred = UserCredentials::from_file(home.display().to_string()).await?;
let req = Self::build_token_request(&RefreshRequest {
client_id: cred.client_id,
client_secret: cred.client_secret,
grant_type: "refresh_token".to_string(),
Expand Down Expand Up @@ -70,7 +75,7 @@ impl ServiceAccount for DefaultAuthorizedUser {
}

#[derive(Serialize, Debug)]
struct RerfeshRequest {
struct RefreshRequest {
client_id: String,
client_secret: String,
grant_type: String,
Expand All @@ -80,13 +85,13 @@ struct RerfeshRequest {
#[derive(Serialize, Deserialize, Debug, Clone)]
struct UserCredentials {
/// Client id
pub client_id: String,
pub(crate) client_id: String,
/// Client secret
pub client_secret: String,
pub(crate) client_secret: String,
/// Refresh Token
pub refresh_token: String,
pub(crate) refresh_token: String,
/// Type
pub r#type: String,
pub(crate) r#type: String,
}

impl UserCredentials {
Expand Down
17 changes: 11 additions & 6 deletions src/default_service_account.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use crate::authentication_manager::ServiceAccount;
use crate::prelude::*;
use hyper::body::Body;
use hyper::Method;
use std::str;
use std::sync::RwLock;

use async_trait::async_trait;
use hyper::body::Body;
use hyper::{Method, Request};

use crate::authentication_manager::ServiceAccount;
use crate::error::Error;
use crate::types::{HyperClient, Token};
use crate::util::HyperExt;

#[derive(Debug)]
pub struct DefaultServiceAccount {
pub(crate) struct DefaultServiceAccount {
token: RwLock<Token>,
}

Expand All @@ -15,7 +20,7 @@ impl DefaultServiceAccount {
"http://metadata.google.internal/computeMetadata/v1/project/project-id";
const DEFAULT_TOKEN_GCP_URI: &'static str = "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token";

pub async fn new(client: &HyperClient) -> Result<Self, Error> {
pub(crate) async fn new(client: &HyperClient) -> Result<Self, Error> {
let token = RwLock::new(Self::get_token(client).await?);
Ok(Self { token })
}
Expand Down
6 changes: 3 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ pub enum Error {
/// GOOGLE_APPLICATION_CREDENTIALS is used for providing path to json file with applications credentials.
/// File can be downloaded in GCP Console when creating service account.
#[error("Path to custom auth credentials was not provided in `GOOGLE_APPLICATION_CREDENTIALS` env variable")]
AplicationProfileMissing,
ApplicationProfileMissing,

/// Wrong path to custom application profile credentials provided
///
/// Path has to be defined using `GOOGLE_APPLICATION_CREDENTIALS` environment variable
#[error("Environment variable `GOOGLE_APPLICATION_CREDENTIALS` contains invalid path to application profile file")]
AplicationProfilePath(std::io::Error),
ApplicationProfilePath(std::io::Error),

/// Wrong format of custom application profile
///
/// Application profile is downloaded from GCP console and is stored in filesystem on the server.
/// Full path is passed to library by setting `GOOGLE_APPLICATION_CREDENTIALS` variable with path as a value.
#[error("Application profile provided in `GOOGLE_APPLICATION_CREDENTIALS` was not parsable")]
AplicationProfileFormat(serde_json::error::Error),
ApplicationProfileFormat(serde_json::error::Error),

/// Default user profile not found
///
Expand Down
9 changes: 6 additions & 3 deletions src/gcloud_authorized_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@ use crate::authentication_manager::ServiceAccount;
use crate::error::Error::{
GCloudError, GCloudNotFound, GCloudParseError, NoProjectId, ParsingError,
};
use crate::prelude::*;
use serde_json::json;
use std::path::PathBuf;
use std::process::Command;
use which::which;
use crate::types::HyperClient;
use crate::error::Error;
use crate::Token;
use async_trait::async_trait;

#[derive(Debug)]
pub struct GCloudAuthorizedUser {
pub(crate) struct GCloudAuthorizedUser {
gcloud: PathBuf,
}

impl GCloudAuthorizedUser {
pub async fn new() -> Result<Self, Error> {
pub(crate) async fn new() -> Result<Self, Error> {
which("gcloud")
.map_err(|_| GCloudNotFound)
.map(|path| Self { gcloud: path })
Expand Down
Loading

0 comments on commit 9378676

Please sign in to comment.