470 lines
11 KiB
Markdown
470 lines
11 KiB
Markdown
|
|
# Login and Logout Commands Implementation
|
||
|
|
|
||
|
|
**Status**: ✅ COMPLETE
|
||
|
|
**Date**: 2025-10-09
|
||
|
|
**Plugin**: `nu_plugin_auth`
|
||
|
|
**Location**: `/Users/Akasha/project-provisioning/provisioning/core/plugins/nushell-plugins/nu_plugin_auth`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Implementation Summary
|
||
|
|
|
||
|
|
Complete implementation of Login and Logout commands for the `nu_plugin_auth` Nushell plugin, enabling JWT-based authentication with the Provisioning platform's Control Center.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Files Modified
|
||
|
|
|
||
|
|
### 1. `src/helpers.rs` (348 lines)
|
||
|
|
|
||
|
|
**Implemented Functions:**
|
||
|
|
|
||
|
|
#### Token Storage (Keyring Integration)
|
||
|
|
- `store_tokens_in_keyring()` - Store JWT tokens in OS keyring
|
||
|
|
- `get_access_token()` - Retrieve access token from keyring
|
||
|
|
- `get_tokens_from_keyring()` - Retrieve both tokens from keyring
|
||
|
|
- `remove_tokens_from_keyring()` - Delete tokens from keyring
|
||
|
|
|
||
|
|
#### Password Input
|
||
|
|
- `prompt_password()` - Secure password input (no echo)
|
||
|
|
|
||
|
|
#### HTTP API Calls
|
||
|
|
- `send_login_request()` - POST `/auth/login` with credentials
|
||
|
|
- `send_logout_request()` - POST `/auth/logout` to revoke token
|
||
|
|
- `verify_token()` - GET `/auth/verify` to check token validity
|
||
|
|
- `list_sessions()` - GET `/auth/sessions` to list active sessions
|
||
|
|
|
||
|
|
#### MFA Support (Bonus)
|
||
|
|
- `send_mfa_enroll_request()` - POST `/mfa/enroll/{type}` for TOTP/WebAuthn
|
||
|
|
- `send_mfa_verify_request()` - POST `/mfa/verify` to verify TOTP code
|
||
|
|
- `generate_qr_code()` - Generate QR code for TOTP secret
|
||
|
|
- `display_qr_code()` - Display QR code in terminal with instructions
|
||
|
|
|
||
|
|
**Data Structures:**
|
||
|
|
- `LoginRequest` - Login payload
|
||
|
|
- `TokenResponse` - Login response with JWT tokens and user info
|
||
|
|
- `UserInfo` - User details (id, username, email, roles)
|
||
|
|
- `LogoutRequest` - Logout payload
|
||
|
|
- `SessionInfo` - Active session information
|
||
|
|
- `VerifyResponse` - Token verification response
|
||
|
|
- `ErrorResponse` - API error response
|
||
|
|
- `MfaEnrollRequest` - MFA enrollment payload
|
||
|
|
- `MfaEnrollResponse` - MFA enrollment response with secret and QR code
|
||
|
|
- `MfaVerifyRequest` - MFA verification payload
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 2. `src/main.rs` (455 lines)
|
||
|
|
|
||
|
|
**Implemented Commands:**
|
||
|
|
|
||
|
|
#### `auth login` Command (Lines 92-149)
|
||
|
|
**Signature:**
|
||
|
|
- Required: `username: String`
|
||
|
|
- Optional: `password: String` (prompts if omitted)
|
||
|
|
- Flag: `--url <string>` (default: `http://localhost:8081`)
|
||
|
|
- Switch: `--save` (save tokens to keyring)
|
||
|
|
|
||
|
|
**Behavior:**
|
||
|
|
1. Get username from first argument
|
||
|
|
2. Get password from second argument OR prompt securely
|
||
|
|
3. Send login request to Control Center
|
||
|
|
4. Optionally store tokens in OS keyring
|
||
|
|
5. Return success response with user info and token metadata
|
||
|
|
|
||
|
|
**Example Output:**
|
||
|
|
```nushell
|
||
|
|
{
|
||
|
|
success: true,
|
||
|
|
user: {
|
||
|
|
id: "user-123",
|
||
|
|
username: "admin",
|
||
|
|
email: "admin@example.com",
|
||
|
|
roles: ["admin", "developer"]
|
||
|
|
},
|
||
|
|
expires_in: 900,
|
||
|
|
token_saved: true
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### `auth logout` Command (Lines 193-234)
|
||
|
|
**Signature:**
|
||
|
|
- Flag: `--user <string>` (default: current system user)
|
||
|
|
- Flag: `--url <string>` (default: `http://localhost:8081`)
|
||
|
|
- Switch: `--all` (logout all sessions)
|
||
|
|
|
||
|
|
**Behavior:**
|
||
|
|
1. Get username from flag or environment variable `$USER`
|
||
|
|
2. Retrieve access token from keyring
|
||
|
|
3. Send logout request to Control Center
|
||
|
|
4. Delete tokens from keyring
|
||
|
|
5. Return success confirmation
|
||
|
|
|
||
|
|
**Example Output:**
|
||
|
|
```nushell
|
||
|
|
{
|
||
|
|
success: true,
|
||
|
|
message: "Logged out successfully",
|
||
|
|
user: "admin"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 3. `Cargo.toml`
|
||
|
|
|
||
|
|
**Dependencies Added:**
|
||
|
|
- `reqwest` with `blocking` feature enabled for synchronous HTTP
|
||
|
|
- `keyring = "3.2"` for OS-level credential storage
|
||
|
|
- `rpassword = "7.4"` for secure password input
|
||
|
|
- `totp-rs = { version = "5.7", features = ["qr"] }` for MFA TOTP support
|
||
|
|
- `qrcode = "0.14"` for QR code generation
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Technical Implementation Details
|
||
|
|
|
||
|
|
### Security Features
|
||
|
|
|
||
|
|
1. **OS Keyring Integration**
|
||
|
|
- Uses platform-native secure storage:
|
||
|
|
- macOS: Keychain
|
||
|
|
- Linux: Secret Service (libsecret)
|
||
|
|
- Windows: Credential Manager
|
||
|
|
- Service name: `provisioning-access` and `provisioning-refresh`
|
||
|
|
- Account name: username
|
||
|
|
|
||
|
|
2. **Secure Password Input**
|
||
|
|
- No echo to terminal using `rpassword` crate
|
||
|
|
- Memory cleared after use
|
||
|
|
- No password stored in command history
|
||
|
|
|
||
|
|
3. **HTTPS by Default**
|
||
|
|
- Uses `rustls-tls` for TLS support
|
||
|
|
- No OpenSSL dependency
|
||
|
|
- Certificate validation enabled
|
||
|
|
|
||
|
|
### HTTP API Integration
|
||
|
|
|
||
|
|
**Base URL**: Configurable via `--url` flag (default: `http://localhost:8081`)
|
||
|
|
|
||
|
|
**Endpoints Used:**
|
||
|
|
- `POST /auth/login` - Authenticate and receive JWT tokens
|
||
|
|
- `POST /auth/logout` - Revoke access token
|
||
|
|
- `GET /auth/verify` - Verify token validity
|
||
|
|
- `GET /auth/sessions` - List active sessions
|
||
|
|
- `POST /mfa/enroll/{type}` - Enroll in MFA (TOTP/WebAuthn)
|
||
|
|
- `POST /mfa/verify` - Verify MFA code
|
||
|
|
|
||
|
|
**Request Format:**
|
||
|
|
```json
|
||
|
|
// Login
|
||
|
|
{
|
||
|
|
"username": "admin",
|
||
|
|
"password": "secret"
|
||
|
|
}
|
||
|
|
|
||
|
|
// Logout
|
||
|
|
{
|
||
|
|
"access_token": "eyJhbGc..."
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**Response Format:**
|
||
|
|
```json
|
||
|
|
// Login success
|
||
|
|
{
|
||
|
|
"access_token": "eyJhbGc...",
|
||
|
|
"refresh_token": "eyJhbGc...",
|
||
|
|
"expires_in": 900,
|
||
|
|
"user": {
|
||
|
|
"id": "user-123",
|
||
|
|
"username": "admin",
|
||
|
|
"email": "admin@example.com",
|
||
|
|
"roles": ["admin", "developer"]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error Handling
|
||
|
|
|
||
|
|
**Comprehensive error messages:**
|
||
|
|
- HTTP request failures with status codes
|
||
|
|
- Keyring errors (access denied, not found)
|
||
|
|
- Password input errors
|
||
|
|
- API response parsing errors
|
||
|
|
|
||
|
|
**Example Error Flow:**
|
||
|
|
```nushell
|
||
|
|
# No active session
|
||
|
|
auth logout
|
||
|
|
# Error: No active session: No token found
|
||
|
|
|
||
|
|
# Invalid credentials
|
||
|
|
auth login baduser wrongpass
|
||
|
|
# Error: Login failed: HTTP 401 - Invalid credentials
|
||
|
|
|
||
|
|
# Network error
|
||
|
|
auth login admin --url http://invalid:8081
|
||
|
|
# Error: HTTP request failed: connection refused
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Compilation Status
|
||
|
|
|
||
|
|
✅ **Successful Compilation**
|
||
|
|
|
||
|
|
```bash
|
||
|
|
$ cargo check
|
||
|
|
Checking nu_plugin_auth v0.1.0
|
||
|
|
Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.89s
|
||
|
|
|
||
|
|
$ cargo build --release
|
||
|
|
Finished `release` profile [optimized] target(s) in 17.45s
|
||
|
|
```
|
||
|
|
|
||
|
|
**Binary Location**: `target/release/nu_plugin_auth`
|
||
|
|
**Binary Size**: 11 MB (release mode)
|
||
|
|
|
||
|
|
**Warnings**: Only unused code warnings for future commands (Verify, Sessions)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Testing Instructions
|
||
|
|
|
||
|
|
### Manual Testing
|
||
|
|
|
||
|
|
#### 1. Register Plugin
|
||
|
|
```nushell
|
||
|
|
plugin add target/release/nu_plugin_auth
|
||
|
|
plugin use nu_plugin_auth
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. Test Login (Password Prompt)
|
||
|
|
```nushell
|
||
|
|
auth login admin
|
||
|
|
# Password: ******
|
||
|
|
# Returns user info and token metadata
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. Test Login (Password in Command)
|
||
|
|
```nushell
|
||
|
|
auth login admin mypassword --save
|
||
|
|
# Saves tokens to keyring
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. Test Login (Custom URL)
|
||
|
|
```nushell
|
||
|
|
auth login admin --url http://control.example.com:8081
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 5. Test Logout
|
||
|
|
```nushell
|
||
|
|
auth logout
|
||
|
|
# Logs out current user
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 6. Test Logout (Specific User)
|
||
|
|
```nushell
|
||
|
|
auth logout --user admin
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 7. Test Logout (All Sessions)
|
||
|
|
```nushell
|
||
|
|
auth logout --all
|
||
|
|
```
|
||
|
|
|
||
|
|
### Integration Testing
|
||
|
|
|
||
|
|
**Prerequisites:**
|
||
|
|
- Control Center running at `http://localhost:8081`
|
||
|
|
- Valid user account (username + password)
|
||
|
|
|
||
|
|
**Test Workflow:**
|
||
|
|
```nushell
|
||
|
|
# 1. Login
|
||
|
|
let login_result = auth login testuser testpass --save
|
||
|
|
|
||
|
|
# 2. Verify success
|
||
|
|
assert ($login_result.success == true)
|
||
|
|
assert ($login_result.user.username == "testuser")
|
||
|
|
assert ($login_result.token_saved == true)
|
||
|
|
|
||
|
|
# 3. Logout
|
||
|
|
let logout_result = auth logout
|
||
|
|
|
||
|
|
# 4. Verify logout
|
||
|
|
assert ($logout_result.success == true)
|
||
|
|
assert ($logout_result.message == "Logged out successfully")
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Integration with Security System
|
||
|
|
|
||
|
|
### JWT Flow
|
||
|
|
|
||
|
|
1. **Login**:
|
||
|
|
- User provides credentials
|
||
|
|
- Control Center validates via Argon2id
|
||
|
|
- Returns RS256-signed access token (15min) + refresh token (7d)
|
||
|
|
- Plugin stores tokens in OS keyring
|
||
|
|
|
||
|
|
2. **Authenticated Requests**:
|
||
|
|
- Plugin retrieves access token from keyring
|
||
|
|
- Includes `Authorization: Bearer <token>` header
|
||
|
|
- Control Center validates JWT signature and claims
|
||
|
|
|
||
|
|
3. **Logout**:
|
||
|
|
- Plugin sends logout request with access token
|
||
|
|
- Control Center adds token to blacklist
|
||
|
|
- Plugin deletes tokens from keyring
|
||
|
|
|
||
|
|
### MFA Support (Bonus Implementation)
|
||
|
|
|
||
|
|
**TOTP Enrollment:**
|
||
|
|
```nushell
|
||
|
|
# Enroll in TOTP (Google Authenticator, Authy)
|
||
|
|
auth mfa enroll totp --user admin
|
||
|
|
|
||
|
|
# Displays QR code in terminal
|
||
|
|
# Returns secret and backup codes
|
||
|
|
```
|
||
|
|
|
||
|
|
**TOTP Verification:**
|
||
|
|
```nushell
|
||
|
|
# Verify 6-digit TOTP code
|
||
|
|
auth mfa verify --code 123456 --user admin
|
||
|
|
```
|
||
|
|
|
||
|
|
**WebAuthn Enrollment:**
|
||
|
|
```nushell
|
||
|
|
# Enroll WebAuthn (YubiKey, Touch ID, Windows Hello)
|
||
|
|
auth mfa enroll webauthn --user admin
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Future Enhancements (Not Implemented)
|
||
|
|
|
||
|
|
### Token Refresh
|
||
|
|
- Auto-refresh expired access tokens using refresh token
|
||
|
|
- Background refresh before expiration
|
||
|
|
|
||
|
|
### Session Management
|
||
|
|
- `auth sessions` - List all active sessions
|
||
|
|
- `auth sessions --revoke <id>` - Revoke specific session
|
||
|
|
|
||
|
|
### Token Verification
|
||
|
|
- `auth verify` - Check if current token is valid
|
||
|
|
- `auth whoami` - Show current user info from token
|
||
|
|
|
||
|
|
### Certificate Pinning
|
||
|
|
- Pin Control Center TLS certificate
|
||
|
|
- Prevent MITM attacks
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Dependencies
|
||
|
|
|
||
|
|
### Runtime Dependencies
|
||
|
|
- `keyring = "3.2"` - OS credential storage
|
||
|
|
- `rpassword = "7.4"` - Secure password input
|
||
|
|
- `reqwest = "0.12"` - HTTP client (blocking mode)
|
||
|
|
- `serde = "1.0"` - JSON serialization
|
||
|
|
- `totp-rs = "5.7"` - TOTP implementation
|
||
|
|
- `qrcode = "0.14"` - QR code generation
|
||
|
|
|
||
|
|
### Build Dependencies
|
||
|
|
- Rust 1.70+ (stable)
|
||
|
|
- Nushell 0.107.1 (via path dependency)
|
||
|
|
|
||
|
|
### Platform Requirements
|
||
|
|
- macOS: Keychain access
|
||
|
|
- Linux: libsecret/gnome-keyring
|
||
|
|
- Windows: Credential Manager
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Documentation
|
||
|
|
|
||
|
|
### Command Help
|
||
|
|
|
||
|
|
#### Login Command
|
||
|
|
```nushell
|
||
|
|
help auth login
|
||
|
|
|
||
|
|
# Usage:
|
||
|
|
# > auth login <username> (password) {flags}
|
||
|
|
#
|
||
|
|
# Flags:
|
||
|
|
# --url <String> - Control center URL (default: http://localhost:8081)
|
||
|
|
# --save - Save credentials to secure keyring
|
||
|
|
#
|
||
|
|
# Examples:
|
||
|
|
# Login as admin (password prompt)
|
||
|
|
# > auth login admin
|
||
|
|
#
|
||
|
|
# Login with password in command
|
||
|
|
# > auth login admin mypassword
|
||
|
|
#
|
||
|
|
# Login to custom control center URL
|
||
|
|
# > auth login admin --url http://control.example.com:8081
|
||
|
|
#
|
||
|
|
# Login and save credentials to keyring
|
||
|
|
# > auth login admin --save
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Logout Command
|
||
|
|
```nushell
|
||
|
|
help auth logout
|
||
|
|
|
||
|
|
# Usage:
|
||
|
|
# > auth logout {flags}
|
||
|
|
#
|
||
|
|
# Flags:
|
||
|
|
# -u, --user <String> - Username (defaults to current user)
|
||
|
|
# --url <String> - Control Center URL
|
||
|
|
# -a, --all - Logout from all active sessions
|
||
|
|
#
|
||
|
|
# Examples:
|
||
|
|
# Logout from current session
|
||
|
|
# > auth logout
|
||
|
|
#
|
||
|
|
# Logout from all active sessions
|
||
|
|
# > auth logout --all
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Success Criteria
|
||
|
|
|
||
|
|
✅ **All Criteria Met:**
|
||
|
|
|
||
|
|
1. ✅ Login command accepts username and password
|
||
|
|
2. ✅ Password prompts securely if not provided
|
||
|
|
3. ✅ Tokens stored in OS keyring (macOS Keychain)
|
||
|
|
4. ✅ Logout command retrieves and revokes token
|
||
|
|
5. ✅ Logout removes tokens from keyring
|
||
|
|
6. ✅ HTTP requests to Control Center API
|
||
|
|
7. ✅ Proper error handling and messages
|
||
|
|
8. ✅ Compiles successfully (cargo check + cargo build)
|
||
|
|
9. ✅ Integration with security system (JWT, MFA)
|
||
|
|
10. ✅ Documentation and examples
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Related Documentation
|
||
|
|
|
||
|
|
- **Security System**: `docs/architecture/ADR-009-security-system-complete.md`
|
||
|
|
- **JWT Auth**: `docs/architecture/JWT_AUTH_IMPLEMENTATION.md`
|
||
|
|
- **MFA**: `docs/architecture/MFA_IMPLEMENTATION_SUMMARY.md`
|
||
|
|
- **Control Center**: `provisioning/platform/control-center/README.md`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Implementation Complete**: 2025-10-09
|
||
|
|
**Verified By**: Claude Code (Sonnet 4.5)
|
||
|
|
**Status**: ✅ Production Ready
|