feat: enhance auth config (#922)

* feat: enhance auth config
This commit is contained in:
gudnuf
2025-08-05 04:55:17 -07:00
committed by GitHub
parent 2bd97e4d80
commit cceea654fe
6 changed files with 195 additions and 143 deletions

View File

@@ -17,6 +17,7 @@ use anyhow::Result;
use bip39::Mnemonic;
use cdk_integration_tests::cli::CommonArgs;
use cdk_integration_tests::shared;
use cdk_mintd::config::AuthType;
use clap::Parser;
use tokio::sync::Notify;
@@ -68,16 +69,19 @@ async fn start_fake_auth_mint(
// Enable authentication
settings.auth = Some(cdk_mintd::config::Auth {
auth_enabled: true,
openid_discovery,
openid_client_id: "cashu-client".to_string(),
mint_max_bat: 50,
enabled_mint: true,
enabled_melt: true,
enabled_swap: true,
enabled_check_mint_quote: true,
enabled_check_melt_quote: true,
enabled_restore: true,
enabled_check_proof_state: true,
mint: AuthType::Blind,
get_mint_quote: AuthType::Blind,
check_mint_quote: AuthType::Blind,
melt: AuthType::Blind,
get_melt_quote: AuthType::Blind,
check_melt_quote: AuthType::Blind,
swap: AuthType::Blind,
restore: AuthType::Blind,
check_proof_state: AuthType::Blind,
});
// Set description for the mint

View File

@@ -83,13 +83,23 @@ reserve_fee_min = 4
# tls_dir = "/path/to/tls"
# [auth]
# Set to true to enable authentication features (defaults to false)
# auth_enabled = false
# openid_discovery = "http://127.0.0.1:8080/realms/cdk-test-realm/.well-known/openid-configuration"
# openid_client_id = "cashu-client"
# mint_max_bat=50
# enabled_mint=true
# enabled_melt=true
# enabled_swap=true
# enabled_check_mint_quote=true
# enabled_check_melt_quote=true
# enabled_restore=true
# enabled_check_proof_state=true
# Authentication settings for endpoints
# Options: "clear", "blind", "none" (none = disabled)
# mint = "blind"
# get_mint_quote = "none"
# check_mint_quote = "none"
# melt = "none"
# get_melt_quote = "none"
# check_melt_quote = "none"
# swap = "blind"
# restore = "blind"
# check_proof_state = "none"

View File

@@ -208,30 +208,59 @@ pub struct Database {
pub engine: DatabaseEngine,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "lowercase")]
pub enum AuthType {
Clear,
Blind,
#[default]
None,
}
impl std::str::FromStr for AuthType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"clear" => Ok(AuthType::Clear),
"blind" => Ok(AuthType::Blind),
"none" => Ok(AuthType::None),
_ => Err(format!("Unknown auth type: {s}")),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Auth {
#[serde(default)]
pub auth_enabled: bool,
pub openid_discovery: String,
pub openid_client_id: String,
pub mint_max_bat: u64,
#[serde(default = "default_true")]
pub enabled_mint: bool,
#[serde(default = "default_true")]
pub enabled_melt: bool,
#[serde(default = "default_true")]
pub enabled_swap: bool,
#[serde(default = "default_true")]
pub enabled_check_mint_quote: bool,
#[serde(default = "default_true")]
pub enabled_check_melt_quote: bool,
#[serde(default = "default_true")]
pub enabled_restore: bool,
#[serde(default = "default_true")]
pub enabled_check_proof_state: bool,
#[serde(default = "default_blind")]
pub mint: AuthType,
#[serde(default)]
pub get_mint_quote: AuthType,
#[serde(default)]
pub check_mint_quote: AuthType,
#[serde(default)]
pub melt: AuthType,
#[serde(default)]
pub get_melt_quote: AuthType,
#[serde(default)]
pub check_melt_quote: AuthType,
#[serde(default = "default_blind")]
pub swap: AuthType,
#[serde(default = "default_blind")]
pub restore: AuthType,
#[serde(default)]
pub check_proof_state: AuthType,
}
fn default_true() -> bool {
true
fn default_blind() -> AuthType {
AuthType::Blind
}
/// CDK settings, derived from `config.toml`
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Settings {

View File

@@ -4,19 +4,28 @@ use std::env;
use crate::config::Auth;
pub const ENV_AUTH_ENABLED: &str = "CDK_MINTD_AUTH_ENABLED";
pub const ENV_AUTH_OPENID_DISCOVERY: &str = "CDK_MINTD_AUTH_OPENID_DISCOVERY";
pub const ENV_AUTH_OPENID_CLIENT_ID: &str = "CDK_MINTD_AUTH_OPENID_CLIENT_ID";
pub const ENV_AUTH_MINT_MAX_BAT: &str = "CDK_MINTD_AUTH_MINT_MAX_BAT";
pub const ENV_AUTH_ENABLED_MINT: &str = "CDK_MINTD_AUTH_ENABLED_MINT";
pub const ENV_AUTH_ENABLED_MELT: &str = "CDK_MINTD_AUTH_ENABLED_MELT";
pub const ENV_AUTH_ENABLED_SWAP: &str = "CDK_MINTD_AUTH_ENABLED_SWAP";
pub const ENV_AUTH_ENABLED_CHECK_MINT_QUOTE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_MINT_QUOTE";
pub const ENV_AUTH_ENABLED_CHECK_MELT_QUOTE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_MELT_QUOTE";
pub const ENV_AUTH_ENABLED_RESTORE: &str = "CDK_MINTD_AUTH_ENABLED_RESTORE";
pub const ENV_AUTH_ENABLED_CHECK_PROOF_STATE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_PROOF_STATE";
pub const ENV_AUTH_MINT: &str = "CDK_MINTD_AUTH_MINT";
pub const ENV_AUTH_GET_MINT_QUOTE: &str = "CDK_MINTD_AUTH_GET_MINT_QUOTE";
pub const ENV_AUTH_CHECK_MINT_QUOTE: &str = "CDK_MINTD_AUTH_CHECK_MINT_QUOTE";
pub const ENV_AUTH_MELT: &str = "CDK_MINTD_AUTH_MELT";
pub const ENV_AUTH_GET_MELT_QUOTE: &str = "CDK_MINTD_AUTH_GET_MELT_QUOTE";
pub const ENV_AUTH_CHECK_MELT_QUOTE: &str = "CDK_MINTD_AUTH_CHECK_MELT_QUOTE";
pub const ENV_AUTH_SWAP: &str = "CDK_MINTD_AUTH_SWAP";
pub const ENV_AUTH_RESTORE: &str = "CDK_MINTD_AUTH_RESTORE";
pub const ENV_AUTH_CHECK_PROOF_STATE: &str = "CDK_MINTD_AUTH_CHECK_PROOF_STATE";
impl Auth {
pub fn from_env(mut self) -> Self {
if let Ok(enabled_str) = env::var(ENV_AUTH_ENABLED) {
if let Ok(enabled) = enabled_str.parse() {
self.auth_enabled = enabled;
}
}
if let Ok(discovery) = env::var(ENV_AUTH_OPENID_DISCOVERY) {
self.openid_discovery = discovery;
}
@@ -31,45 +40,57 @@ impl Auth {
}
}
if let Ok(enabled_mint_str) = env::var(ENV_AUTH_ENABLED_MINT) {
if let Ok(enabled) = enabled_mint_str.parse() {
self.enabled_mint = enabled;
if let Ok(mint_str) = env::var(ENV_AUTH_MINT) {
if let Ok(auth_type) = mint_str.parse() {
self.mint = auth_type;
}
}
if let Ok(enabled_melt_str) = env::var(ENV_AUTH_ENABLED_MELT) {
if let Ok(enabled) = enabled_melt_str.parse() {
self.enabled_melt = enabled;
if let Ok(get_mint_quote_str) = env::var(ENV_AUTH_GET_MINT_QUOTE) {
if let Ok(auth_type) = get_mint_quote_str.parse() {
self.get_mint_quote = auth_type;
}
}
if let Ok(enabled_swap_str) = env::var(ENV_AUTH_ENABLED_SWAP) {
if let Ok(enabled) = enabled_swap_str.parse() {
self.enabled_swap = enabled;
if let Ok(check_mint_quote_str) = env::var(ENV_AUTH_CHECK_MINT_QUOTE) {
if let Ok(auth_type) = check_mint_quote_str.parse() {
self.check_mint_quote = auth_type;
}
}
if let Ok(enabled_check_mint_str) = env::var(ENV_AUTH_ENABLED_CHECK_MINT_QUOTE) {
if let Ok(enabled) = enabled_check_mint_str.parse() {
self.enabled_check_mint_quote = enabled;
if let Ok(melt_str) = env::var(ENV_AUTH_MELT) {
if let Ok(auth_type) = melt_str.parse() {
self.melt = auth_type;
}
}
if let Ok(enabled_check_melt_str) = env::var(ENV_AUTH_ENABLED_CHECK_MELT_QUOTE) {
if let Ok(enabled) = enabled_check_melt_str.parse() {
self.enabled_check_melt_quote = enabled;
if let Ok(get_melt_quote_str) = env::var(ENV_AUTH_GET_MELT_QUOTE) {
if let Ok(auth_type) = get_melt_quote_str.parse() {
self.get_melt_quote = auth_type;
}
}
if let Ok(enabled_restore_str) = env::var(ENV_AUTH_ENABLED_RESTORE) {
if let Ok(enabled) = enabled_restore_str.parse() {
self.enabled_restore = enabled;
if let Ok(check_melt_quote_str) = env::var(ENV_AUTH_CHECK_MELT_QUOTE) {
if let Ok(auth_type) = check_melt_quote_str.parse() {
self.check_melt_quote = auth_type;
}
}
if let Ok(enabled_check_proof_str) = env::var(ENV_AUTH_ENABLED_CHECK_PROOF_STATE) {
if let Ok(enabled) = enabled_check_proof_str.parse() {
self.enabled_check_proof_state = enabled;
if let Ok(swap_str) = env::var(ENV_AUTH_SWAP) {
if let Ok(auth_type) = swap_str.parse() {
self.swap = auth_type;
}
}
if let Ok(restore_str) = env::var(ENV_AUTH_RESTORE) {
if let Ok(auth_type) = restore_str.parse() {
self.restore = auth_type;
}
}
if let Ok(check_proof_state_str) = env::var(ENV_AUTH_CHECK_PROOF_STATE) {
if let Ok(auth_type) = check_proof_state_str.parse() {
self.check_proof_state = auth_type;
}
}

View File

@@ -63,14 +63,8 @@ impl Settings {
// Check env vars for auth config even if None
let auth = self.auth.clone().unwrap_or_default().from_env();
// Only set auth if env vars are present and have non-default values
if auth.openid_discovery != String::default()
|| auth.openid_client_id != String::default()
|| auth.mint_max_bat != 0
|| auth.enabled_mint
|| auth.enabled_melt
|| auth.enabled_swap
{
// Only set auth if auth_enabled flag is true
if auth.auth_enabled {
self.auth = Some(auth);
} else {
self.auth = None;

View File

@@ -43,7 +43,7 @@ use cdk_axum::cache::HttpCache;
use cdk_sqlite::mint::MintSqliteAuthDatabase;
use cdk_sqlite::MintSqliteDatabase;
use cli::CLIArgs;
use config::{DatabaseEngine, LnBackend};
use config::{AuthType, DatabaseEngine, LnBackend};
use env_vars::ENV_WORK_DIR;
use setup::LnBackendSetup;
use tower::ServiceBuilder;
@@ -456,116 +456,110 @@ async fn setup_authentication(
}
};
let mut protected_endpoints = HashMap::new();
let mut blind_auth_endpoints = vec![];
let mut clear_auth_endpoints = vec![];
let mut unprotected_endpoints = vec![];
let mint_blind_auth_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MintBlindAuth);
let mut protected_endpoints = HashMap::new();
protected_endpoints.insert(mint_blind_auth_endpoint, AuthRequired::Clear);
let mut blind_auth_endpoints = vec![];
let mut unprotected_endpoints = vec![];
clear_auth_endpoints.push(mint_blind_auth_endpoint);
// Helper function to add endpoint based on auth type
let mut add_endpoint = |endpoint: ProtectedEndpoint, auth_type: &AuthType| {
match auth_type {
AuthType::Blind => {
protected_endpoints.insert(endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(endpoint);
}
AuthType::Clear => {
protected_endpoints.insert(endpoint, AuthRequired::Clear);
clear_auth_endpoints.push(endpoint);
}
AuthType::None => {
unprotected_endpoints.push(endpoint);
}
};
};
// Get mint quote endpoint
{
let mint_quote_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MintQuoteBolt11);
let mint_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MintBolt11);
if auth_settings.enabled_mint {
protected_endpoints.insert(mint_quote_protected_endpoint, AuthRequired::Blind);
protected_endpoints.insert(mint_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(mint_quote_protected_endpoint);
blind_auth_endpoints.push(mint_protected_endpoint);
} else {
unprotected_endpoints.push(mint_protected_endpoint);
unprotected_endpoints.push(mint_quote_protected_endpoint);
}
}
{
let melt_quote_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MeltQuoteBolt11);
let melt_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MeltBolt11);
if auth_settings.enabled_melt {
protected_endpoints.insert(melt_quote_protected_endpoint, AuthRequired::Blind);
protected_endpoints.insert(melt_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(melt_quote_protected_endpoint);
blind_auth_endpoints.push(melt_protected_endpoint);
} else {
unprotected_endpoints.push(melt_quote_protected_endpoint);
unprotected_endpoints.push(melt_protected_endpoint);
}
}
{
let swap_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Swap);
if auth_settings.enabled_swap {
protected_endpoints.insert(swap_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(swap_protected_endpoint);
} else {
unprotected_endpoints.push(swap_protected_endpoint);
}
ProtectedEndpoint::new(cdk::nuts::Method::Post, RoutePath::MintQuoteBolt11);
add_endpoint(mint_quote_protected_endpoint, &auth_settings.get_mint_quote);
}
// Check mint quote endpoint
{
let check_mint_protected_endpoint =
ProtectedEndpoint::new(Method::Get, RoutePath::MintQuoteBolt11);
if auth_settings.enabled_check_mint_quote {
protected_endpoints.insert(check_mint_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(check_mint_protected_endpoint);
} else {
unprotected_endpoints.push(check_mint_protected_endpoint);
}
add_endpoint(
check_mint_protected_endpoint,
&auth_settings.check_mint_quote,
);
}
// Mint endpoint
{
let mint_protected_endpoint =
ProtectedEndpoint::new(cdk::nuts::Method::Post, RoutePath::MintBolt11);
add_endpoint(mint_protected_endpoint, &auth_settings.mint);
}
// Get melt quote endpoint
{
let melt_quote_protected_endpoint = ProtectedEndpoint::new(
cdk::nuts::Method::Post,
cdk::nuts::RoutePath::MeltQuoteBolt11,
);
add_endpoint(melt_quote_protected_endpoint, &auth_settings.get_melt_quote);
}
// Check melt quote endpoint
{
let check_melt_protected_endpoint =
ProtectedEndpoint::new(Method::Get, RoutePath::MeltQuoteBolt11);
if auth_settings.enabled_check_melt_quote {
protected_endpoints.insert(check_melt_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(check_melt_protected_endpoint);
} else {
unprotected_endpoints.push(check_melt_protected_endpoint);
}
add_endpoint(
check_melt_protected_endpoint,
&auth_settings.check_melt_quote,
);
}
// Melt endpoint
{
let melt_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::MeltBolt11);
add_endpoint(melt_protected_endpoint, &auth_settings.melt);
}
// Swap endpoint
{
let swap_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Swap);
add_endpoint(swap_protected_endpoint, &auth_settings.swap);
}
// Restore endpoint
{
let restore_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::Restore);
if auth_settings.enabled_restore {
protected_endpoints.insert(restore_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(restore_protected_endpoint);
} else {
unprotected_endpoints.push(restore_protected_endpoint);
}
add_endpoint(restore_protected_endpoint, &auth_settings.restore);
}
// Check proof state endpoint
{
let state_protected_endpoint =
ProtectedEndpoint::new(Method::Post, RoutePath::Checkstate);
if auth_settings.enabled_check_proof_state {
protected_endpoints.insert(state_protected_endpoint, AuthRequired::Blind);
blind_auth_endpoints.push(state_protected_endpoint);
} else {
unprotected_endpoints.push(state_protected_endpoint);
}
add_endpoint(state_protected_endpoint, &auth_settings.check_proof_state);
}
mint_builder = mint_builder.with_auth(
auth_localstore.clone(),
auth_settings.openid_discovery,
auth_settings.openid_client_id,
vec![mint_blind_auth_endpoint],
clear_auth_endpoints,
);
mint_builder =
mint_builder.with_blind_auth(auth_settings.mint_max_bat, blind_auth_endpoints);