Skip to content

Commit

Permalink
feat(*): add support for http basic auth to bindle server (#165)
Browse files Browse the repository at this point in the history
- also adds support for ignoring bindle server cert errors

Signed-off-by: Vaughn Dice <vaughn.dice@fermyon.com>
  • Loading branch information
vdice committed Mar 3, 2022
1 parent 2d4d8ad commit b3d1781
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
hyper = { version = "0.14", features = ["full"] }
indexmap = { version = "^1.6.2", features = ["serde"] }
oci-distribution = "0.6"
reqwest = { version = "0.11", features = ["stream"] }
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.9"
tokio = { version = "1.1", features = ["full"] }
Expand Down
61 changes: 61 additions & 0 deletions src/bindle_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,67 @@ fn parse_csv(text: &str) -> Vec<String> {
text.split(',').map(|v| v.to_owned()).collect() // TODO: trim etc.?
}

// Bindle client/auth utils, derived from github.com/deislabs/hippo-cli

use std::sync::Arc;

use bindle::client::{
tokens::{HttpBasic, NoToken, TokenManager},
Client, ClientBuilder,
};

#[derive(Clone)]
pub struct BindleConnectionInfo {
base_url: String,
allow_insecure: bool,
token_manager: AnyAuth,
}

impl BindleConnectionInfo {
pub fn new<I: Into<String>>(
base_url: I,
allow_insecure: bool,
username: Option<String>,
password: Option<String>,
) -> Self {
let token_manager: Box<dyn TokenManager + Send + Sync> = match (username, password) {
(Some(u), Some(p)) => Box::new(HttpBasic::new(&u, &p)),
_ => Box::new(NoToken::default()),
};

Self {
base_url: base_url.into(),
allow_insecure,
token_manager: AnyAuth {
token_manager: Arc::new(token_manager),
},
}
}

pub fn client(&self) -> bindle::client::Result<Client<AnyAuth>> {
let builder = ClientBuilder::default()
.http2_prior_knowledge(false)
.danger_accept_invalid_certs(self.allow_insecure);
builder.build(&self.base_url, self.token_manager.clone())
}
}

#[derive(Clone)]
pub struct AnyAuth {
token_manager: Arc<Box<dyn TokenManager + Send + Sync>>,
}

#[async_trait::async_trait]
impl TokenManager for AnyAuth {
async fn apply_auth_header(
&self,
builder: reqwest::RequestBuilder,
) -> bindle::client::Result<reqwest::RequestBuilder> {
self.token_manager.apply_auth_header(builder).await
}
}


#[cfg(test)]
mod test {
use super::*;
Expand Down
12 changes: 4 additions & 8 deletions src/handler_loader/emplacer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::{collections::HashMap, path::{Path, PathBuf}, sync::Arc};
use anyhow::Context;
use bindle::Invoice;
use sha2::{Digest, Sha256};
use url::Url;

use crate::{
bindle_util::{InvoiceUnderstander, WagiHandlerInfo},
Expand Down Expand Up @@ -62,8 +61,8 @@ impl Emplacer {
Ok(EmplacedHandlerConfiguration::ModuleMapFile(path.clone())),
HandlerConfigurationSource::StandaloneBindle(bindle_base_dir, id) =>
self.emplace_standalone_bindle(&bindle_base_dir, &id).await,
HandlerConfigurationSource::RemoteBindle(bindle_base_url, id) =>
self.emplace_remote_bindle(&bindle_base_url, &id).await,
HandlerConfigurationSource::RemoteBindle(bindle_connection_info, id) =>
self.emplace_remote_bindle(bindle_connection_info, &id).await,
}.with_context(|| "Error caching assets from bindle")
}

Expand Down Expand Up @@ -91,11 +90,8 @@ impl Emplacer {
self.emplace_bindle(&reader, id).await
}

async fn emplace_remote_bindle(self, bindle_base_url: &Url, id: &bindle::Id) -> anyhow::Result<EmplacedHandlerConfiguration> {
let token = bindle::client::tokens::NoToken::default();
let client = bindle::client::Client::new(bindle_base_url.as_str(), token)?;

self.emplace_bindle(&client, id).await
async fn emplace_remote_bindle(self, bindle_connection_info: crate::bindle_util::BindleConnectionInfo, id: &bindle::Id) -> anyhow::Result<EmplacedHandlerConfiguration> {
self.emplace_bindle(&bindle_connection_info.client()?, id).await
}

async fn emplace_bindle(self, reader: &impl BindleReader, id: &bindle::Id) -> anyhow::Result<EmplacedHandlerConfiguration> {
Expand Down
50 changes: 47 additions & 3 deletions src/wagi_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use clap::{App, Arg, ArgMatches, ArgGroup};
use core::convert::TryFrom;
use std::collections::HashMap;
use std::net::SocketAddr;
use crate::wagi_config::{
HandlerConfigurationSource, HttpConfiguration, TlsConfiguration, WagiConfiguration,
use crate::{
bindle_util::BindleConnectionInfo,
wagi_config::{
HandlerConfigurationSource, HttpConfiguration, TlsConfiguration, WagiConfiguration,
},
};

const ABOUT: &str = r#"
Expand All @@ -28,6 +31,9 @@ const BINDLE_URL: &str = "BINDLE_URL";
const ARG_BINDLE_ID: &str = "bindle";
const ARG_BINDLE_URL: &str = "BINDLE_URL";
const ARG_BINDLE_STANDALONE_DIR: &str = "bindle_path";
const ARG_BINDLE_INSECURE: &str = "bindle_insecure";
const ARG_BINDLE_HTTP_USER: &str = "BINDLE_HTTP_USER";
const ARG_BINDLE_HTTP_PASSWORD: &str = "BINDLE_HTTP_PASSWORD";

// Arguments for serving from local Wasm files specified in a modules.toml
const ARG_MODULES_CONFIG: &str = "config";
Expand Down Expand Up @@ -97,6 +103,32 @@ pub fn wagi_app_definition() -> App<'static, 'static> {
ArgGroup::with_name(GROUP_BINDLE_SOURCE)
.args(&[ARG_BINDLE_STANDALONE_DIR, ARG_BINDLE_URL])
)
.arg(
Arg::with_name(ARG_BINDLE_HTTP_USER)
.long("bindle-http-user")
.value_name("BINDLE_HTTP_USER")
.env("BINDLE_HTTP_USER")
.help("The username for authentication via basic http auth with the Bindle server.")
.takes_value(true)
.requires(ARG_BINDLE_HTTP_PASSWORD)
)
.arg(
Arg::with_name(ARG_BINDLE_HTTP_PASSWORD)
.long("bindle-http-password")
.value_name("BINDLE_HTTP_PASSWORD")
.env("BINDLE_HTTP_PASSWORD")
.help("The password for authentication via basic http auth with the Bindle server.")
.takes_value(true)
.requires(ARG_BINDLE_HTTP_USER)
)
.arg(
Arg::with_name(ARG_BINDLE_INSECURE)
.short("k")
.long("bindle-insecure")
.help("if set, ignore bindle server certificate errors")
.required(false)
.takes_value(false),
)
.arg(
Arg::with_name(ARG_WASM_CACHE_CONFIG_FILE)
.long("cache")
Expand Down Expand Up @@ -246,6 +278,18 @@ pub fn parse_configuration_from(matches: ArgMatches) -> anyhow::Result<WagiConfi
Ok(configuration)
}

fn parse_bindle_connection_info(
url: url::Url,
matches: &ArgMatches,
) -> anyhow::Result<BindleConnectionInfo> {
Ok(BindleConnectionInfo::new(
url,
matches.is_present(ARG_BINDLE_INSECURE),
matches.value_of(ARG_BINDLE_HTTP_USER).map(|s| s.to_string()),
matches.value_of(ARG_BINDLE_HTTP_PASSWORD).map(|s| s.to_string()),
))
}

fn parse_handler_configuration_source(
matches: &ArgMatches,
) -> anyhow::Result<HandlerConfigurationSource> {
Expand Down Expand Up @@ -293,7 +337,7 @@ fn parse_handler_configuration_source(
(Some(bindle_id), None, Some(bindle_url), None) => {
match url::Url::parse(bindle_url) {
Ok(url) => Ok(HandlerConfigurationSource::RemoteBindle(
url,
parse_bindle_connection_info(url, &matches)?,
bindle::Id::try_from(bindle_id)?,
)),
Err(e) => Err(anyhow::anyhow!("Invalid Bindle server URL: {}", e)),
Expand Down
15 changes: 11 additions & 4 deletions src/wagi_config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
use std::{collections::HashMap, net::SocketAddr, path::PathBuf};

use crate::{handler_loader::WasmCompilationSettings, request::RequestGlobalContext};
use crate::{
bindle_util::BindleConnectionInfo,
handler_loader::WasmCompilationSettings,
request::RequestGlobalContext,
};

#[derive(Clone, Debug)]
// TODO: figure out how to re-apply the Debug trait here (and on HandlerConfigurationSource)
// At time of writing, it was removed on account of the bindle::client::tokens::token_manager
// not implementing this trait (see crate::bindle_util::BindleConnectionInfo)
#[derive(Clone)]
pub struct WagiConfiguration {
pub handlers: HandlerConfigurationSource,
pub env_vars: HashMap<String, String>,
Expand All @@ -12,11 +19,11 @@ pub struct WagiConfiguration {
pub log_dir: PathBuf,
}

#[derive(Clone, Debug)]
#[derive(Clone)]
pub enum HandlerConfigurationSource {
ModuleConfigFile(PathBuf),
StandaloneBindle(PathBuf, bindle::Id),
RemoteBindle(url::Url, bindle::Id),
RemoteBindle(BindleConnectionInfo, bindle::Id),
}

#[derive(Clone, Debug)]
Expand Down

0 comments on commit b3d1781

Please sign in to comment.