# Authentication Command Handlers # Handles: auth login, auth logout, auth status, auth mfa, etc. use ../flags.nu * use ../../lib_provisioning/plugins/auth.nu * # Main authentication command dispatcher export def handle_authentication_command [ command: string ops: string flags: record ] { match $command { "auth" | "login" | "whoami" | "mfa" => { let subcommand = if ($ops | is-not-empty) { ($ops | split row " " | get 0) } else if $command == "login" { "login" } else if $command == "whoami" { "status" } else if $command == "mfa" { "mfa" } else { "status" } let remaining_ops = if ($ops | is-not-empty) { ($ops | split row " " | skip 1 | str join " ") } else { "" } match $subcommand { "login" => { handle_auth_login $remaining_ops $flags } "logout" => { handle_auth_logout $flags } "status" | "whoami" => { handle_auth_status $flags } "sessions" | "list" => { handle_auth_sessions $flags } "refresh" => { handle_auth_refresh $flags } "mfa" | "mfa-enroll" | "mfa-verify" => { handle_auth_mfa $subcommand $remaining_ops $flags } "help" => { show_auth_help } _ => { print $"❌ Unknown auth subcommand: ($subcommand)" print "" print "Available auth subcommands:" print " login - Login with credentials" print " logout - Logout (revoke session)" print " status - Show current authentication status" print " whoami - Alias for status" print " sessions - List active sessions" print " list - Alias for sessions" print " refresh - Refresh authentication token" print " mfa - MFA operations" print " mfa-enroll - Enroll in MFA" print " mfa-verify - Verify MFA code" print " help - Show this help message" print "" print "Use 'provisioning auth help' for more details" exit 1 } } } _ => { print $"❌ Unknown authentication command: ($command)" print "" print "Available authentication commands:" print " login - Login with username and password" print " logout - Logout (revoke session)" print " status | whoami - Show current user and session status" print " sessions | list - List active sessions" print " refresh - Refresh authentication token" print " mfa - Multi-factor authentication" print " mfa-enroll - Enroll in MFA (TOTP or WebAuthn)" print " mfa-verify - Verify MFA code" print " help - Show auth help" print "" print "Examples:" print " provisioning auth login" print " provisioning auth status" print " provisioning mfa totp enroll" print " provisioning mfa verify --code 123456" print "" print "Use 'provisioning help authentication' for more details" exit 1 } } } # Login with username and password def handle_auth_login [ops: string, flags: record] { let username = if ($ops | is-not-empty) { ($ops | split row " " | get 0) } else { input $"(_ansi cyan)Username:(_ansi reset) " } if ($username | is-empty) { print $"(_ansi red)❌ Username is required(_ansi reset)" exit 1 } # Prompt for password securely print $"(_ansi cyan)Password for ($username):(_ansi reset) " let password = (input --suppress-output) if ($password | is-empty) { print $"(_ansi red)❌ Password is required(_ansi reset)" exit 1 } print $"\n(_ansi cyan)Authenticating...(_ansi reset)" let result = (do -i { plugin-login $username $password }) if $result != null { print $"\n(_ansi green_bold)✓ Login successful!(_ansi reset)\n" print $"(_ansi cyan)User:(_ansi reset) ($result.user? | default $username)" print $"(_ansi cyan)Role:(_ansi reset) ($result.role? | default 'N/A')" print $"(_ansi cyan)Expires:(_ansi reset) ($result.expires_at? | default 'N/A')" print $"(_ansi cyan)MFA:(_ansi reset) ($result.mfa_enabled? | default false)" if ($result.mfa_required? | default false) { print $"\n(_ansi yellow)⚠️ MFA verification required(_ansi reset)" print $"(_ansi cyan)Use: provisioning auth mfa verify --code <6-digit-code>(_ansi reset)" } else { print $"\n(_ansi green)Session active and ready(_ansi reset)" } } else { print $"\n(_ansi red_bold)❌ Login failed(_ansi reset)" print $"(_ansi red)Authentication error occurred(_ansi reset)" exit 1 } } # Logout and clear tokens def handle_auth_logout [flags: record] { print $"(_ansi cyan)Logging out...(_ansi reset)" let result = (do -i { plugin-logout }) if $result != null { print $"\n(_ansi green_bold)✓ Logged out successfully(_ansi reset)" print $"(_ansi default_dimmed)All tokens have been cleared(_ansi reset)" } else { print $"\n(_ansi yellow)⚠️ Logout completed with warnings(_ansi reset)" print $"(_ansi default_dimmed)Token cleanup may have failed(_ansi reset)" } } # Show authentication status def handle_auth_status [flags: record] { print $"(_ansi cyan_bold)Authentication Status(_ansi reset)\n" let status = (do -i { plugin-auth-status }) if $status != null { if ($status.authenticated? | default false) { print $"(_ansi green)Status:(_ansi reset) Authenticated ✓" print $"(_ansi cyan)User:(_ansi reset) ($status.user? | default 'N/A')" print $"(_ansi cyan)Role:(_ansi reset) ($status.role? | default 'N/A')" print $"(_ansi cyan)Expires at:(_ansi reset) ($status.expires_at? | default 'N/A')" print $"(_ansi cyan)MFA enabled:(_ansi reset) ($status.mfa_enabled? | default false)" if ($status.permissions? | is-not-empty) { print $"\n(_ansi cyan_bold)Permissions:(_ansi reset)" for perm in $status.permissions { print $" • ($perm)" } } if ($status.warning? | is-not-empty) { print $"\n(_ansi yellow)⚠️ ($status.warning)(_ansi reset)" } } else { print $"(_ansi red)Status:(_ansi reset) Not authenticated ✗" print $"(_ansi cyan)Message:(_ansi reset) ($status.message? | default 'No active session')" print $"\n(_ansi default_dimmed)Use 'provisioning auth login' to authenticate(_ansi reset)" } # Show plugin mode print $"\n(_ansi default_dimmed)Mode: ($status.mode? | default 'unknown')(_ansi reset)" } else { print $"(_ansi red)❌ Failed to get auth status(_ansi reset)" print $"(_ansi red)Status check error occurred(_ansi reset)" exit 1 } } # List active sessions def handle_auth_sessions [flags: record] { print $"(_ansi cyan_bold)Active Sessions(_ansi reset)\n" let sessions = (do -i { plugin-sessions }) if $sessions != null { if ($sessions | length) == 0 { print $"(_ansi yellow)No active sessions found(_ansi reset)" return } $sessions | table -e } else { print $"(_ansi red)❌ Failed to list sessions(_ansi reset)" print $"(_ansi red)Session listing error occurred(_ansi reset)" exit 1 } } # Refresh access token def handle_auth_refresh [flags: record] { print $"(_ansi cyan)Refreshing access token...(_ansi reset)" let result = (do -i { plugin-verify }) if $result != null { if ($result.valid? | default false) { print $"(_ansi green)✓ Token is still valid(_ansi reset)" print $"(_ansi cyan)Expires:(_ansi reset) ($result.expires_at? | default 'N/A')" } else { print $"(_ansi yellow)Token expired or invalid, please login again(_ansi reset)" } } else { print $"(_ansi red)❌ Token verification failed(_ansi reset)" print $"(_ansi red)Verification error occurred(_ansi reset)" exit 1 } } # Handle MFA commands def handle_auth_mfa [subcommand: string, ops: string, flags: record] { let mfa_action = if $subcommand == "mfa" { if ($ops | is-not-empty) { ($ops | split row " " | get 0) } else { "help" } } else if $subcommand == "mfa-enroll" { "enroll" } else if $subcommand == "mfa-verify" { "verify" } else { "help" } let remaining_ops = if $subcommand == "mfa" and ($ops | is-not-empty) { ($ops | split row " " | skip 1 | str join " ") } else { $ops } match $mfa_action { "enroll" | "enable" | "setup" => { handle_mfa_enroll $remaining_ops $flags } "verify" | "check" => { handle_mfa_verify $remaining_ops $flags } "help" => { show_mfa_help } _ => { print $"❌ Unknown MFA action: ($mfa_action)" print "Use 'provisioning auth mfa help' for available commands" exit 1 } } } # Enroll in MFA def handle_mfa_enroll [ops: string, flags: record] { let mfa_type = if ($ops | is-not-empty) { ($ops | split row " " | get 0) } else { "totp" } if $mfa_type not-in ["totp" "webauthn"] { print $"(_ansi red)❌ Invalid MFA type: ($mfa_type)(_ansi reset)" print $"(_ansi cyan)Valid types: totp, webauthn(_ansi reset)" exit 1 } print $"(_ansi cyan_bold)Enrolling in MFA ($mfa_type)...(_ansi reset)\n" let result = (do -i { plugin-mfa-enroll --type $mfa_type }) if $result != null { if $mfa_type == "totp" { print $"(_ansi green_bold)✓ TOTP enrollment initiated(_ansi reset)\n" print $"(_ansi cyan_bold)Secret:(_ansi reset) ($result.secret? | default 'N/A')\n" if ($result.qr_code? | is-not-empty) { print $"(_ansi cyan_bold)QR Code:(_ansi reset)" print $result.qr_code print "" } print $"(_ansi yellow_bold)📱 Setup Instructions:(_ansi reset)" print $" 1. Open your authenticator app (Google Authenticator, Authy, etc.)" print $" 2. Scan the QR code above or manually enter the secret" print $" 3. Verify with the 6-digit code:\n" print $" (_ansi cyan)provisioning auth mfa verify --code <6-digit-code>(_ansi reset)\n" } else { print $"(_ansi green_bold)✓ WebAuthn enrollment initiated(_ansi reset)\n" print $"(_ansi yellow_bold)🔑 Setup Instructions:(_ansi reset)" print $" 1. Follow browser prompts to register your security key" print $" 2. Touch your YubiKey, use Touch ID, or Windows Hello" print $" 3. Complete registration in the web interface\n" } } else { print $"\n(_ansi red_bold)❌ MFA enrollment failed(_ansi reset)" print $"(_ansi red)Enrollment error occurred(_ansi reset)" exit 1 } } # Verify MFA code def handle_mfa_verify [ops: string, flags: record] { let code = if ($flags.code? | is-not-empty) { $flags.code } else if ($ops | is-not-empty) { ($ops | split row " " | get 0) } else { input $"(_ansi cyan)Enter 6-digit MFA code:(_ansi reset) " } if ($code | is-empty) { print $"(_ansi red)❌ MFA code is required(_ansi reset)" exit 1 } print $"(_ansi cyan)Verifying MFA code...(_ansi reset)" let result = (do -i { plugin-mfa-verify $code }) if $result != null { print $"\n(_ansi green_bold)✓ MFA verified successfully!(_ansi reset)\n" print $"(_ansi cyan)Status:(_ansi reset) ($result.status? | default 'Active')" if ($result.backup_codes? | is-not-empty) { print $"\n(_ansi yellow_bold)⚠️ Backup Codes \(save these securely\):(_ansi reset)" for code in $result.backup_codes { print $" • ($code)" } print $"\n(_ansi default_dimmed)Use these codes if you lose access to your MFA device(_ansi reset)" } } else { print $"\n(_ansi red_bold)❌ MFA verification failed(_ansi reset)" print $"(_ansi red)Verification error occurred(_ansi reset)" print $"\n(_ansi yellow)💡 Tip: Make sure the code is current (30-second window)(_ansi reset)" exit 1 } } # Show authentication help def show_auth_help [] { print $" (_ansi cyan_bold)╔══════════════════════════════════════════════════╗(_ansi reset) (_ansi cyan_bold)║(_ansi reset) 🔐 AUTHENTICATION COMMANDS (_ansi cyan_bold)║(_ansi reset) (_ansi cyan_bold)╚══════════════════════════════════════════════════╝(_ansi reset) (_ansi green_bold)[Session Management](_ansi reset) (_ansi blue)auth login (_ansi reset) Login and store JWT tokens (_ansi blue)auth logout(_ansi reset) Logout and clear tokens (_ansi blue)auth status(_ansi reset) Show current authentication status (_ansi blue)auth sessions(_ansi reset) List active sessions (_ansi blue)auth refresh(_ansi reset) Verify/refresh token (_ansi green_bold)[Multi-Factor Authentication](_ansi reset) (_ansi blue)auth mfa enroll (_ansi reset) Enroll in MFA (totp or webauthn) (_ansi blue)auth mfa verify --code (_ansi reset) Verify MFA code (_ansi green_bold)EXAMPLES(_ansi reset) # Login interactively provisioning auth login # Login with username provisioning auth login admin # Check authentication status provisioning auth status provisioning whoami (_ansi default_dimmed)# shortcut(_ansi reset) # Enroll in TOTP MFA provisioning auth mfa enroll totp # Verify MFA code provisioning auth mfa verify --code 123456 # List active sessions provisioning auth sessions # Logout provisioning auth logout (_ansi green_bold)SHORTCUTS(_ansi reset) login → auth login logout → auth logout whoami → auth status mfa → auth mfa mfa-enroll → auth mfa enroll mfa-verify → auth mfa verify (_ansi default_dimmed)💡 Authentication uses JWT tokens with RS256 signing Tokens are stored securely and expire after 15 minutes MFA is required for sensitive operations in production(_ansi reset) " } # Show MFA help def show_mfa_help [] { print $" (_ansi cyan_bold)╔══════════════════════════════════════════════════╗(_ansi reset) (_ansi cyan_bold)║(_ansi reset) 🔐 MULTI-FACTOR AUTHENTICATION (_ansi cyan_bold)║(_ansi reset) (_ansi cyan_bold)╚══════════════════════════════════════════════════╝(_ansi reset) (_ansi green_bold)[MFA Types](_ansi reset) (_ansi blue)TOTP (Time-based One-Time Password)(_ansi reset) • 6-digit codes that change every 30 seconds • Works with Google Authenticator, Authy, etc. • No internet required after setup (_ansi blue)WebAuthn/FIDO2(_ansi reset) • Hardware security keys (YubiKey) • Biometric authentication (Touch ID, Windows Hello) • Phishing-resistant (_ansi green_bold)[Commands](_ansi reset) (_ansi blue)auth mfa enroll totp(_ansi reset) Enroll in TOTP MFA (_ansi blue)auth mfa enroll webauthn(_ansi reset) Enroll in WebAuthn MFA (_ansi blue)auth mfa verify --code (_ansi reset) Verify MFA code (_ansi green_bold)EXAMPLES(_ansi reset) # Enroll in TOTP provisioning auth mfa enroll totp # Scan QR code with authenticator app # Then verify with 6-digit code provisioning auth mfa verify --code 123456 # Enroll in WebAuthn provisioning auth mfa enroll webauthn (_ansi default_dimmed)💡 MFA enrollment requires active authentication session Use 'provisioning auth login' first if not authenticated(_ansi reset) " }