Files
mcias/clients/rust
Kyle Isom 8545473703 Fix SEC-01: require password for TOTP enroll
- REST handleTOTPEnroll now requires password field in request body
- gRPC EnrollTOTP updated with password field in proto message
- Both handlers check lockout status and record failures on bad password
- Updated Go, Python, and Rust client libraries to pass password
- Updated OpenAPI specs with new requestBody schema
- Added TestTOTPEnrollRequiresPassword with no-password, wrong-password,
  and correct-password sub-tests

Security: TOTP enrollment now requires the current password to prevent
session-theft escalation to persistent account takeover. Lockout and
failure recording use the same Argon2id constant-time path as login.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 00:48:31 -07:00
..

mcias-client (Rust)

Async Rust client library for the MCIAS identity and access management API.

Requirements

  • Rust 2021 edition (stable toolchain)
  • Tokio async runtime

Installation

Add to Cargo.toml:

[dependencies]
mcias-client = { path = "path/to/clients/rust" }

Quick Start

use mcias_client::{Client, ClientOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new(
        "https://auth.example.com".to_string(),
        ClientOptions::default(),
    )?;

    // Authenticate.
    let (token, expires_at) = client.login("alice", "s3cret", None).await?;
    println!("token expires at {expires_at}");

    // The token is stored in the client automatically.
    let accounts = client.list_accounts().await?;

    // Revoke the token when done.
    client.logout().await?;

    Ok(())
}

Custom CA Certificate

let ca_pem = std::fs::read("/etc/mcias/ca.pem")?;
let client = Client::new(
    "https://auth.example.com".to_string(),
    ClientOptions {
        ca_cert_pem: Some(ca_pem),
        token: None,
    },
)?;

Error Handling

All methods return Result<_, MciasError>:

use mcias_client::MciasError;

match client.login("alice", "wrongpass", None).await {
    Err(MciasError::Auth { message }) => eprintln!("auth failed: {message}"),
    Err(MciasError::Forbidden { message }) => eprintln!("forbidden: {message}"),
    Err(MciasError::NotFound { message }) => eprintln!("not found: {message}"),
    Err(MciasError::InvalidInput { message }) => eprintln!("bad input: {message}"),
    Err(MciasError::Conflict { message }) => eprintln!("conflict: {message}"),
    Err(MciasError::Server { status, message }) => eprintln!("server error {status}: {message}"),
    Err(MciasError::Transport(e)) => eprintln!("network error: {e}"),
    Err(MciasError::Decode(e)) => eprintln!("parse error: {e}"),
    Ok((token, _)) => println!("ok: {token}"),
}

Thread Safety

Client is Send + Sync. The internal token is wrapped in Arc<RwLock<Option<String>>> for safe concurrent access.

Running Tests

cargo test
cargo clippy -- -D warnings