Skip to content

Commit

Permalink
feat: add some http client options, like TLS
Browse files Browse the repository at this point in the history
  • Loading branch information
ctron committed Jul 8, 2024
1 parent 11ca9f7 commit 2322755
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 16 deletions.
9 changes: 6 additions & 3 deletions src/cmd/create/confidential.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::oidc::TokenResult;
use crate::{
cmd::create::CreateCommon,
config::{Client, ClientType, Config},
oidc::get_token,
http::HttpOptions,
oidc::{get_token, TokenResult},
utils::OrNone,
};
use anyhow::{bail, Context};
Expand All @@ -24,6 +24,9 @@ pub struct CreateConfidential {
/// The client secret
#[arg(short = 's', long)]
pub client_secret: String,

#[command(flatten)]
pub http: HttpOptions,
}

impl CreateConfidential {
Expand All @@ -49,7 +52,7 @@ impl CreateConfidential {
};

if !self.common.skip_initial {
let token = get_token(&client)
let token = get_token(&client, &self.http)
.await
.context("failed retrieving first token")?;

Expand Down
9 changes: 6 additions & 3 deletions src/cmd/create/public.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::utils::OrNone;
use crate::{
cmd::create::CreateCommon,
config::{Client, ClientType, Config},
http::create_client,
http::{create_client, HttpOptions},
server::Server,
utils::OrNone,
};
use anyhow::bail;
use openid::{Discovered, Options, StandardClaims};
Expand All @@ -29,6 +29,9 @@ pub struct CreatePublic {
/// Open the link automatically
#[arg(short, long)]
pub open: bool,

#[command(flatten)]
pub http: HttpOptions,
}

impl CreatePublic {
Expand All @@ -47,7 +50,7 @@ impl CreatePublic {
let server = Server::new(self.port).await?;
let redirect = format!("http://localhost:{}", server.port);

let client = create_client().await?;
let client = create_client(&self.http).await?;
let client = openid::Client::<Discovered, StandardClaims>::discover_with_client(
client,
self.client_id.clone(),
Expand Down
8 changes: 6 additions & 2 deletions src/cmd/token.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
config::Config,
http::HttpOptions,
oidc::{fetch_token, get_token, TokenResult},
utils::inspect::inspect,
};
Expand Down Expand Up @@ -39,6 +40,9 @@ pub struct GetToken {
/// Force a new token
#[arg(short, long)]
pub force: bool,

#[command(flatten)]
pub http: HttpOptions,
}

impl GetToken {
Expand All @@ -50,8 +54,8 @@ impl GetToken {
.ok_or_else(|| anyhow!("unknown client '{}'", self.name))?;

let token = match self.force {
true => fetch_token(client).await?,
false => get_token(client).await?,
true => fetch_token(client, &self.http).await?,
false => get_token(client, &self.http).await?,
};

let token = match token {
Expand Down
103 changes: 101 additions & 2 deletions src/http.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,106 @@
use anyhow::Context;
use reqwest::{header, tls::Version};
use std::path::PathBuf;

const USER_AGENT: &str = concat!("OIDC-CLI/", env!("CARGO_PKG_VERSION"));

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, clap::ValueEnum)]
pub enum TlsVersion {
/// TLS 1.0
#[value(name("1.0"))]
Tls1_0,
/// TLS 1.1
#[value(name("1.1"))]
Tls1_1,
/// TLS 1.2
#[value(name("1.2"))]
Tls1_2,
/// TLS 1.3
#[value(name("1.3"))]
Tls1_3,
}

impl From<TlsVersion> for Version {
fn from(value: TlsVersion) -> Self {
match value {
TlsVersion::Tls1_0 => Version::TLS_1_0,
TlsVersion::Tls1_1 => Version::TLS_1_1,
TlsVersion::Tls1_2 => Version::TLS_1_2,
TlsVersion::Tls1_3 => Version::TLS_1_3,
}
}
}

/// HTTP client options
#[derive(Clone, Debug, PartialEq, Eq, clap::Args)]
#[command(next_help_heading = "HTTP client options")]
pub struct HttpOptions {
/// Disable TLS validation (INSECURE!)
#[arg(long)]
pub tls_insecure: bool,

/// Additional root certificates
#[arg(long = "root-certificate", alias = "cacert", short = 'C')]
pub additional_root_certificates: Vec<PathBuf>,

/// Disable system root certificates
#[arg(long = "no-system-certificates")]
pub disable_system_certificates: bool,

/// Connect timeout
#[arg(long, default_value = "30s")]
pub connect_timeout: humantime::Duration,

/// Request timeout
#[arg(long, default_value = "60s", short = 't')]
pub timeout: humantime::Duration,

/// Minimum TLS version
#[arg(long, value_enum, default_value_t = TlsVersion::Tls1_2)]
pub min_tls_version: TlsVersion,
}

/// A common way to create an HTTP client
pub async fn create_client() -> anyhow::Result<reqwest::Client> {
let client = reqwest::ClientBuilder::new();
pub async fn create_client(options: &HttpOptions) -> anyhow::Result<reqwest::Client> {
let mut headers = header::HeaderMap::new();
headers.insert("User-Agent", header::HeaderValue::from_static(USER_AGENT));

let mut client = reqwest::ClientBuilder::new().default_headers(headers);

// tls validation

if options.tls_insecure {
log::warn!("Disabling TLS validation");
client = client
.danger_accept_invalid_certs(true)
.danger_accept_invalid_hostnames(true);
}

// timeouts

client = client.connect_timeout(options.connect_timeout.into());
client = client.timeout(options.timeout.into());

// certs

client = client.tls_built_in_root_certs(!options.disable_system_certificates);

for cert in &options.additional_root_certificates {
let cert = std::fs::read(&cert)
.with_context(|| format!("Reading certificate: {}", cert.display()))?;
let cert = reqwest::tls::Certificate::from_pem(&cert)?;
client = client.add_root_certificate(cert);
}

// tls version

client = client.min_tls_version(options.min_tls_version.into());

// build

let client = client.build()?;

// done

Ok(client)
}
3 changes: 1 addition & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ use crate::cmd::Command;
use clap::Parser;
use log::LevelFilter;
use simplelog::{ColorChoice, Config, TermLogger, TerminalMode};
use std::path::PathBuf;
use std::process::ExitCode;
use std::{path::PathBuf, process::ExitCode};

#[derive(Debug, clap::Parser)]
#[command(about, author, version, rename_all_env = "SNAKE_CASE")]
Expand Down
9 changes: 5 additions & 4 deletions src/oidc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::http::HttpOptions;
use crate::{
config::{Client, ClientState, ClientType},
http::create_client,
Expand All @@ -13,8 +14,8 @@ pub enum TokenResult {
}

/// Fetch a new token
pub async fn fetch_token(config: &Client) -> anyhow::Result<TokenResult> {
let client = create_client().await?;
pub async fn fetch_token(config: &Client, http: &HttpOptions) -> anyhow::Result<TokenResult> {
let client = create_client(http).await?;

match &config.r#type {
ClientType::Confidential {
Expand Down Expand Up @@ -73,7 +74,7 @@ pub async fn fetch_token(config: &Client) -> anyhow::Result<TokenResult> {
}

/// Get the current token, or fetch a new one
pub async fn get_token(config: &Client) -> anyhow::Result<TokenResult> {
pub async fn get_token(config: &Client, http: &HttpOptions) -> anyhow::Result<TokenResult> {
if let Some(state) = &config.state {
log::debug!("Token expires: {}", OrNone(&state.expires));
if let Some(expires) = state.expires {
Expand All @@ -83,5 +84,5 @@ pub async fn get_token(config: &Client) -> anyhow::Result<TokenResult> {
}
}

fetch_token(config).await
fetch_token(config, http).await
}

0 comments on commit 2322755

Please sign in to comment.