2025-11-29 12:42:55 +01:00
|
|
|
use miette::{IntoDiagnostic, Result};
|
2025-11-29 12:17:01 +01:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
|
2025-11-29 13:28:06 +01:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
2025-11-29 12:17:01 +01:00
|
|
|
pub struct Settings {
|
|
|
|
|
pub server: Server,
|
|
|
|
|
pub database: Database,
|
|
|
|
|
pub keys: Keys,
|
|
|
|
|
pub federation: Federation,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct Server {
|
|
|
|
|
pub host: String,
|
|
|
|
|
pub port: u16,
|
|
|
|
|
/// If set, this is used as the issuer/public base URL, e.g., https://idp.example.com
|
|
|
|
|
pub public_base_url: Option<String>,
|
2025-11-30 18:06:50 +01:00
|
|
|
/// Enable public user registration. If false, only admin API can create users.
|
|
|
|
|
#[serde(default = "default_allow_public_registration")]
|
|
|
|
|
pub allow_public_registration: bool,
|
|
|
|
|
/// Admin GraphQL API port (defaults to port + 1)
|
|
|
|
|
pub admin_port: Option<u16>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn default_allow_public_registration() -> bool {
|
|
|
|
|
false // Secure by default - registration disabled
|
2025-11-29 12:17:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct Database {
|
2025-11-30 18:06:50 +01:00
|
|
|
/// SeaORM/SQLx connection string
|
|
|
|
|
/// Examples:
|
|
|
|
|
/// - SQLite: sqlite://barycenter.db?mode=rwc
|
|
|
|
|
/// - PostgreSQL: postgresql://user:password@localhost/barycenter
|
2025-11-29 12:17:01 +01:00
|
|
|
pub url: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct Keys {
|
|
|
|
|
/// Path to persist JWKS (public keys). Default: data/jwks.json
|
|
|
|
|
pub jwks_path: PathBuf,
|
|
|
|
|
/// Optional explicit key id to set on generated keys
|
|
|
|
|
pub key_id: Option<String>,
|
|
|
|
|
/// JWS algorithm for ID tokens (currently RS256)
|
|
|
|
|
pub alg: String,
|
|
|
|
|
/// Path to persist the private key in PEM (PKCS#8). Default: data/private_key.pem
|
|
|
|
|
pub private_key_path: PathBuf,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
|
|
|
pub struct Federation {
|
|
|
|
|
/// List of trust anchor URLs or fingerprints (placeholder for real federation)
|
|
|
|
|
pub trust_anchors: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Server {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
host: "0.0.0.0".to_string(),
|
|
|
|
|
port: 8080,
|
|
|
|
|
public_base_url: None,
|
2025-11-30 18:06:50 +01:00
|
|
|
allow_public_registration: false,
|
|
|
|
|
admin_port: None, // Defaults to port + 1 if not set
|
2025-11-29 12:17:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Database {
|
|
|
|
|
fn default() -> Self {
|
2025-11-29 12:34:45 +01:00
|
|
|
Self {
|
refactor: update crabidp references to barycenter and add Gateway API support
Replace all remaining references to "crabidp" with "barycenter" across:
- Source code (error diagnostics, CLI name, comments)
- Configuration files and defaults
- Environment variable prefixes (CRABIDP__ → BARYCENTER__)
- Documentation (CLAUDE.md, README.md, DEPLOYMENT.md)
- Deployment configurations (Docker Compose, Helm, systemd, FreeBSD, illumos)
- Database filenames (crabidp.db → barycenter.db)
Add Kubernetes Gateway API support to Helm chart:
- New HTTPRoute template for Gateway API
- Configurable parentRefs, hostnames, filters, and weights
- Support for advanced traffic management features
- Gateway API as modern alternative to traditional Ingress
- Documentation and examples in DEPLOYMENT.md
Benefits of Gateway API:
- More expressive and extensible routing
- Role-oriented design with separation of concerns
- Better vendor portability
- Advanced traffic management capabilities
The Helm chart now supports both traditional Ingress and
Gateway API, allowing users to choose based on their cluster
capabilities and requirements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 15:38:07 +01:00
|
|
|
url: "sqlite://barycenter.db?mode=rwc".to_string(),
|
2025-11-29 12:34:45 +01:00
|
|
|
}
|
2025-11-29 12:17:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for Keys {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
jwks_path: PathBuf::from("data/jwks.json"),
|
|
|
|
|
key_id: None,
|
|
|
|
|
alg: "RS256".to_string(),
|
|
|
|
|
private_key_path: PathBuf::from("data/private_key.pem"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Settings {
|
|
|
|
|
pub fn load(path: &str) -> Result<Self> {
|
|
|
|
|
let mut builder = config::Config::builder()
|
|
|
|
|
.set_default("server.host", Server::default().host)
|
|
|
|
|
.into_diagnostic()?
|
|
|
|
|
.set_default("server.port", Server::default().port)
|
|
|
|
|
.into_diagnostic()?
|
2025-11-29 12:34:45 +01:00
|
|
|
.set_default("database.url", Database::default().url)
|
2025-11-29 12:17:01 +01:00
|
|
|
.into_diagnostic()?
|
|
|
|
|
.set_default(
|
|
|
|
|
"keys.jwks_path",
|
|
|
|
|
Keys::default().jwks_path.to_string_lossy().to_string(),
|
|
|
|
|
)
|
|
|
|
|
.into_diagnostic()?
|
|
|
|
|
.set_default("keys.alg", Keys::default().alg)
|
|
|
|
|
.into_diagnostic()?
|
|
|
|
|
.set_default(
|
|
|
|
|
"keys.private_key_path",
|
2025-11-29 12:34:45 +01:00
|
|
|
Keys::default()
|
|
|
|
|
.private_key_path
|
|
|
|
|
.to_string_lossy()
|
|
|
|
|
.to_string(),
|
2025-11-29 12:17:01 +01:00
|
|
|
)
|
|
|
|
|
.into_diagnostic()?;
|
|
|
|
|
|
|
|
|
|
// Optional file
|
|
|
|
|
if Path::new(path).exists() {
|
|
|
|
|
builder = builder.add_source(config::File::with_name(path));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Environment overrides: CRABIDP__SERVER__PORT=9090, etc.
|
2025-11-29 12:34:45 +01:00
|
|
|
builder = builder.add_source(config::Environment::with_prefix("CRABIDP").separator("__"));
|
2025-11-29 12:17:01 +01:00
|
|
|
|
|
|
|
|
let cfg = builder.build().into_diagnostic()?;
|
|
|
|
|
let mut s: Settings = cfg.try_deserialize().into_diagnostic()?;
|
|
|
|
|
|
|
|
|
|
// Normalize jwks path to be relative to current dir
|
|
|
|
|
if s.keys.jwks_path.is_relative() {
|
|
|
|
|
s.keys.jwks_path = std::env::current_dir()
|
|
|
|
|
.into_diagnostic()?
|
|
|
|
|
.join(&s.keys.jwks_path);
|
|
|
|
|
}
|
|
|
|
|
if s.keys.private_key_path.is_relative() {
|
|
|
|
|
s.keys.private_key_path = std::env::current_dir()
|
|
|
|
|
.into_diagnostic()?
|
|
|
|
|
.join(&s.keys.private_key_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn issuer(&self) -> String {
|
|
|
|
|
if let Some(base) = &self.server.public_base_url {
|
|
|
|
|
base.trim_end_matches('/').to_string()
|
|
|
|
|
} else {
|
|
|
|
|
format!("http://{}:{}", self.server.host, self.server.port)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|