462 lines
17 KiB
Plaintext
Raw Permalink Normal View History

# 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 <username>(_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 <type>(_ansi reset) Enroll in MFA (totp or webauthn)
(_ansi blue)auth mfa verify --code <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 <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)
"
}