#[cfg(not(feature = "cookies"))]
fn main() {
eprintln!("ERROR: The basic_auth example requires the 'cookies' feature to be enabled.");
eprintln!("This example demonstrates session management with Basic Authentication,");
eprintln!("which requires cookie support to maintain authentication state across requests.");
eprintln!();
eprintln!("To run this example, use:");
eprintln!(" cargo run --example basic_auth --features cookies");
eprintln!("or:");
eprintln!(" cargo run --example basic_auth # (cookies enabled by default)");
std::process::exit(1);
}
#[cfg(feature = "cookies")]
mod basic_auth_example {
use goose::goose::GooseResponse;
use goose::prelude::*;
use log::{info, warn};
use reqwest::{header, Client};
use std::{env, time::Duration};
#[tokio::main]
pub async fn main() -> Result<(), GooseError> {
GooseAttack::initialize()?
.register_scenario(
scenario!("CustomClientAuth")
.set_weight(3)?
.set_wait_time(Duration::from_secs(1), Duration::from_secs(3))?
.register_transaction(transaction!(setup_basic_auth_client).set_on_start())
.register_transaction(transaction!(test_basic_auth_endpoint))
.register_transaction(transaction!(test_user_agent_endpoint))
.register_transaction(transaction!(test_json_endpoint)),
)
.register_scenario(
scenario!("HelperFunctionAuth")
.set_weight(2)?
.set_wait_time(Duration::from_secs(1), Duration::from_secs(3))?
.register_transaction(transaction!(test_with_helper_function))
.register_transaction(transaction!(test_post_with_helper)),
)
.register_scenario(
scenario!("ManualPerRequestAuth")
.set_weight(1)?
.set_wait_time(Duration::from_secs(1), Duration::from_secs(3))?
.register_transaction(transaction!(test_manual_basic_auth))
.register_transaction(transaction!(test_manual_with_validation)),
)
.execute()
.await?;
Ok(())
}
async fn setup_basic_auth_client(user: &mut GooseUser) -> TransactionResult {
let (username, password) = get_basic_auth_credentials()?;
let temp_request = reqwest::Client::new()
.get("http://localhost")
.basic_auth(&username, Some(&password))
.build()
.map_err(TransactionError::Reqwest)?;
let mut headers = header::HeaderMap::new();
if let Some(auth_header) = temp_request.headers().get(header::AUTHORIZATION) {
headers.insert(header::AUTHORIZATION, auth_header.clone());
}
let builder = Client::builder()
.user_agent("Goose/1.0 BasicAuth Example")
.default_headers(headers)
.timeout(Duration::from_secs(30))
.cookie_store(true);
user.set_client_builder(builder).await?;
Ok(())
}
async fn test_basic_auth_endpoint(user: &mut GooseUser) -> TransactionResult {
let goose_metrics = user.get("/basic-auth/user/passwd").await?;
if let Ok(response) = &goose_metrics.response {
if response.status() == 200 {
info!("Basic Auth successful!");
}
}
Ok(())
}
async fn test_user_agent_endpoint(user: &mut GooseUser) -> TransactionResult {
let _goose_metrics = user.get("/user-agent").await?;
Ok(())
}
async fn test_json_endpoint(user: &mut GooseUser) -> TransactionResult {
let _goose_metrics = user.get("/json").await?;
Ok(())
}
async fn send_authenticated_request(
user: &mut GooseUser,
method: &GooseMethod,
path: &str,
) -> Result<GooseResponse, Box<TransactionError>> {
let mut reqwest_request_builder = user.get_request_builder(method, path)?;
if let Ok((username, password)) = get_basic_auth_credentials() {
reqwest_request_builder = reqwest_request_builder.basic_auth(username, Some(password));
}
let goose_request = GooseRequest::builder()
.path(path)
.set_request_builder(reqwest_request_builder)
.build();
let goose_response = user.request(goose_request).await?;
Ok(goose_response)
}
async fn test_with_helper_function(user: &mut GooseUser) -> TransactionResult {
let _goose_response =
send_authenticated_request(user, &GooseMethod::Get, "/basic-auth/user/passwd").await?;
Ok(())
}
async fn test_post_with_helper(user: &mut GooseUser) -> TransactionResult {
let _goose_response = send_authenticated_request(user, &GooseMethod::Post, "/post").await?;
Ok(())
}
async fn test_manual_basic_auth(user: &mut GooseUser) -> TransactionResult {
let (username, password) = get_basic_auth_credentials()?;
let reqwest_request_builder = user
.get_request_builder(&GooseMethod::Get, "/basic-auth/user/passwd")?
.basic_auth(username, Some(password));
let goose_request = GooseRequest::builder()
.path("/basic-auth/user/passwd")
.set_request_builder(reqwest_request_builder)
.build();
let _goose_metrics = user.request(goose_request).await?;
Ok(())
}
async fn test_manual_with_validation(user: &mut GooseUser) -> TransactionResult {
let (username, password) = get_basic_auth_credentials()?;
let reqwest_request_builder = user
.get_request_builder(&GooseMethod::Get, "/basic-auth/user/passwd")?
.basic_auth(username, Some(password));
let goose_request = GooseRequest::builder()
.path("/basic-auth/user/passwd")
.set_request_builder(reqwest_request_builder)
.build();
let goose_metrics = user.request(goose_request).await?;
if let Ok(response) = &goose_metrics.response {
if response.status() == 200 {
warn!("Manual Basic Auth successful, but static assets would fail!");
}
}
Ok(())
}
fn get_basic_auth_credentials() -> Result<(String, String), Box<TransactionError>> {
if let (Ok(username), Ok(password)) = (
env::var("BASIC_AUTH_USERNAME"),
env::var("BASIC_AUTH_PASSWORD"),
) {
return Ok((username, password));
}
if let Ok(basic_auth) = env::var("BASIC_AUTH") {
let parts: Vec<&str> = basic_auth.splitn(2, ':').collect();
if parts.len() == 2 {
return Ok((parts[0].to_string(), parts[1].to_string()));
} else {
return Err(Box::new(TransactionError::Custom(format!(
"BASIC_AUTH must be in format 'username:password', got: {}",
basic_auth
))));
}
}
warn!("No Basic Auth credentials found in environment variables.");
warn!("Using default credentials 'user:passwd' for httpbin.org testing.");
warn!("Set BASIC_AUTH_USERNAME/BASIC_AUTH_PASSWORD or BASIC_AUTH environment variables for real usage.");
Ok(("user".to_string(), "passwd".to_string()))
}
}
#[cfg(feature = "cookies")]
use basic_auth_example::main;