Skip to content

Commit

Permalink
support url-sourced external account
Browse files Browse the repository at this point in the history
fix

fix protocol
  • Loading branch information
Hakuyume committed May 24, 2024
1 parent 26f9085 commit cecc05e
Showing 1 changed file with 58 additions and 1 deletion.
59 changes: 58 additions & 1 deletion src/external_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use http::Uri;
use hyper::client::connect::Connection;
use hyper::header;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::error::Error as StdError;
use tokio::io::{AsyncRead, AsyncWrite};
use tower_service::Service;
Expand Down Expand Up @@ -47,10 +48,33 @@ pub enum CredentialSource {
/// file
file: String,
},
// TODO: Microsoft Azure and URL-sourced credentials
/// Microsoft Azure and URL-sourced credentials
Url {
/// url
url: String,
/// headers
headers: Option<HashMap<String, String>>,
/// format
format: UrlCredentialSourceFormat,
},
// TODO: executable-sourced credentials
}

/// JSON schema of URL-sourced credentials' format.
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum UrlCredentialSourceFormat {
/// text
#[serde(rename = "text")]
Text,
/// json
#[serde(rename = "json")]
Json {
/// subject_token_field_name
subject_token_field_name: String,
},
}

/// ExternalAccountFlow can fetch oauth tokens using an external account secret.
pub struct ExternalAccountFlow {
pub(crate) secret: ExternalAccountSecret,
Expand All @@ -72,6 +96,39 @@ impl ExternalAccountFlow {
{
let subject_token = match &self.secret.credential_source {
CredentialSource::File { file } => tokio::fs::read_to_string(file).await?,
CredentialSource::Url {
url,
headers,
format,
} => {
let request = headers
.iter()
.flatten()
.fold(hyper::Request::get(url), |builder, (name, value)| {
builder.header(name, value)
})
.body(hyper::Body::empty())
.unwrap();

log::debug!("requesting credential from url: {:?}", request);
let (head, body) = hyper_client.request(request).await?.into_parts();
let body = hyper::body::to_bytes(body).await?;
log::debug!("received response; head: {:?}, body: {:?}", head, body);

match format {
UrlCredentialSourceFormat::Text => {
String::from_utf8(body.to_vec()).map_err(anyhow::Error::from)?
}
UrlCredentialSourceFormat::Json {
subject_token_field_name,
} => serde_json::from_slice::<HashMap<String, serde_json::Value>>(&body)?
.remove(subject_token_field_name)
.ok_or_else(|| anyhow::format_err!("missing {subject_token_field_name}"))?
.as_str()
.ok_or_else(|| anyhow::format_err!("invalid type"))?
.to_string(),
}
}
};

let req = form_urlencoded::Serializer::new(String::new())
Expand Down

0 comments on commit cecc05e

Please sign in to comment.