Update configuration files, templates, and internal documentation for the provisioning repository system. Configuration Updates: - KMS configuration modernization - Plugin system settings - Service port mappings - Test cluster topologies - Installation configuration examples - VM configuration defaults - Cedar authorization policies Documentation Updates: - Library module documentation - Extension API guides - AI system documentation - Service management guides - Test environment setup - Plugin usage guides - Validator configuration documentation All changes are backward compatible.
742 lines
34 KiB
HTML
742 lines
34 KiB
HTML
<!DOCTYPE HTML>
|
|
<html lang="en" class="ayu sidebar-visible" dir="ltr">
|
|
<head>
|
|
<!-- Book generated using mdBook -->
|
|
<meta charset="UTF-8">
|
|
<title>JWT Auth Implementation - Provisioning Platform Documentation</title>
|
|
|
|
|
|
<!-- Custom HTML head -->
|
|
|
|
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="theme-color" content="#ffffff">
|
|
|
|
<link rel="icon" href="../favicon.svg">
|
|
<link rel="shortcut icon" href="../favicon.png">
|
|
<link rel="stylesheet" href="../css/variables.css">
|
|
<link rel="stylesheet" href="../css/general.css">
|
|
<link rel="stylesheet" href="../css/chrome.css">
|
|
<link rel="stylesheet" href="../css/print.css" media="print">
|
|
|
|
<!-- Fonts -->
|
|
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
|
|
<link rel="stylesheet" href="../fonts/fonts.css">
|
|
|
|
<!-- Highlight.js Stylesheets -->
|
|
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
|
|
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
|
|
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
|
|
|
|
<!-- Custom theme stylesheets -->
|
|
|
|
|
|
<!-- Provide site root and default themes to javascript -->
|
|
<script>
|
|
const path_to_root = "../";
|
|
const default_light_theme = "ayu";
|
|
const default_dark_theme = "navy";
|
|
</script>
|
|
<!-- Start loading toc.js asap -->
|
|
<script src="../toc.js"></script>
|
|
</head>
|
|
<body>
|
|
<div id="mdbook-help-container">
|
|
<div id="mdbook-help-popup">
|
|
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
|
|
<div>
|
|
<p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p>
|
|
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
|
|
<p>Press <kbd>?</kbd> to show this help</p>
|
|
<p>Press <kbd>Esc</kbd> to hide this help</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="body-container">
|
|
<!-- Work around some values being stored in localStorage wrapped in quotes -->
|
|
<script>
|
|
try {
|
|
let theme = localStorage.getItem('mdbook-theme');
|
|
let sidebar = localStorage.getItem('mdbook-sidebar');
|
|
|
|
if (theme.startsWith('"') && theme.endsWith('"')) {
|
|
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
|
|
}
|
|
|
|
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
|
|
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
|
|
}
|
|
} catch (e) { }
|
|
</script>
|
|
|
|
<!-- Set the theme before any content is loaded, prevents flash -->
|
|
<script>
|
|
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
|
|
let theme;
|
|
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
|
|
if (theme === null || theme === undefined) { theme = default_theme; }
|
|
const html = document.documentElement;
|
|
html.classList.remove('ayu')
|
|
html.classList.add(theme);
|
|
html.classList.add("js");
|
|
</script>
|
|
|
|
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
|
|
|
|
<!-- Hide / unhide sidebar before it is displayed -->
|
|
<script>
|
|
let sidebar = null;
|
|
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
|
|
if (document.body.clientWidth >= 1080) {
|
|
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
|
|
sidebar = sidebar || 'visible';
|
|
} else {
|
|
sidebar = 'hidden';
|
|
}
|
|
sidebar_toggle.checked = sidebar === 'visible';
|
|
html.classList.remove('sidebar-visible');
|
|
html.classList.add("sidebar-" + sidebar);
|
|
</script>
|
|
|
|
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
|
|
<!-- populated by js -->
|
|
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
|
|
<noscript>
|
|
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
|
|
</noscript>
|
|
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
|
|
<div class="sidebar-resize-indicator"></div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div id="page-wrapper" class="page-wrapper">
|
|
|
|
<div class="page">
|
|
<div id="menu-bar-hover-placeholder"></div>
|
|
<div id="menu-bar" class="menu-bar sticky">
|
|
<div class="left-buttons">
|
|
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
|
|
<i class="fa fa-bars"></i>
|
|
</label>
|
|
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
|
|
<i class="fa fa-paint-brush"></i>
|
|
</button>
|
|
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
|
|
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
|
|
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
|
|
</ul>
|
|
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
|
|
<i class="fa fa-search"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<h1 class="menu-title">Provisioning Platform Documentation</h1>
|
|
|
|
<div class="right-buttons">
|
|
<a href="../print.html" title="Print this book" aria-label="Print this book">
|
|
<i id="print-button" class="fa fa-print"></i>
|
|
</a>
|
|
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
|
|
<i id="git-repository-button" class="fa fa-github"></i>
|
|
</a>
|
|
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/architecture/JWT_AUTH_IMPLEMENTATION.md" title="Suggest an edit" aria-label="Suggest an edit">
|
|
<i id="git-edit-button" class="fa fa-edit"></i>
|
|
</a>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<div id="search-wrapper" class="hidden">
|
|
<form id="searchbar-outer" class="searchbar-outer">
|
|
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
|
|
</form>
|
|
<div id="searchresults-outer" class="searchresults-outer hidden">
|
|
<div id="searchresults-header" class="searchresults-header"></div>
|
|
<ul id="searchresults">
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
|
|
<script>
|
|
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
|
|
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
|
|
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
|
|
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
|
|
});
|
|
</script>
|
|
|
|
<div id="content" class="content">
|
|
<main>
|
|
<h1 id="jwt-authentication-system-implementation-summary"><a class="header" href="#jwt-authentication-system-implementation-summary">JWT Authentication System Implementation Summary</a></h1>
|
|
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
|
|
<p>A comprehensive JWT authentication system has been successfully implemented for the Provisioning Platform Control Center (Rust). The system provides secure token-based authentication with RS256 asymmetric signing, automatic token rotation, revocation support, and integration with password hashing and user management.</p>
|
|
<hr />
|
|
<h2 id="implementation-status"><a class="header" href="#implementation-status">Implementation Status</a></h2>
|
|
<p>✅ <strong>COMPLETED</strong> - All components implemented with comprehensive unit tests</p>
|
|
<hr />
|
|
<h2 id="files-createdmodified"><a class="header" href="#files-createdmodified">Files Created/Modified</a></h2>
|
|
<h3 id="1-provisioningplatformcontrol-centersrcauthjwtrs-627-lines"><a class="header" href="#1-provisioningplatformcontrol-centersrcauthjwtrs-627-lines">1. <strong><code>provisioning/platform/control-center/src/auth/jwt.rs</code></strong> (627 lines)</a></h3>
|
|
<p>Core JWT token management system with RS256 signing.</p>
|
|
<p><strong>Key Features:</strong></p>
|
|
<ul>
|
|
<li>Token generation (access + refresh token pairs)</li>
|
|
<li>RS256 asymmetric signing for enhanced security</li>
|
|
<li>Token validation with comprehensive checks (signature, expiration, issuer, audience)</li>
|
|
<li>Token rotation mechanism using refresh tokens</li>
|
|
<li>Token revocation with thread-safe blacklist</li>
|
|
<li>Automatic token expiry cleanup</li>
|
|
<li>Token metadata support (IP address, user agent, etc.)</li>
|
|
<li>Blacklist statistics and monitoring</li>
|
|
</ul>
|
|
<p><strong>Structs:</strong></p>
|
|
<ul>
|
|
<li><code>TokenType</code> - Enum for Access/Refresh token types</li>
|
|
<li><code>TokenClaims</code> - JWT claims with user_id, workspace, permissions_hash, iat, exp</li>
|
|
<li><code>TokenPair</code> - Complete token pair with expiry information</li>
|
|
<li><code>JwtService</code> - Main service with Arc+RwLock for thread-safety</li>
|
|
<li><code>BlacklistStats</code> - Statistics for revoked tokens</li>
|
|
</ul>
|
|
<p><strong>Methods:</strong></p>
|
|
<ul>
|
|
<li><code>generate_token_pair()</code> - Generate access + refresh token pair</li>
|
|
<li><code>validate_token()</code> - Validate and decode JWT token</li>
|
|
<li><code>rotate_token()</code> - Rotate access token using refresh token</li>
|
|
<li><code>revoke_token()</code> - Add token to revocation blacklist</li>
|
|
<li><code>is_revoked()</code> - Check if token is revoked</li>
|
|
<li><code>cleanup_expired_tokens()</code> - Remove expired tokens from blacklist</li>
|
|
<li><code>extract_token_from_header()</code> - Parse Authorization header</li>
|
|
</ul>
|
|
<p><strong>Token Configuration:</strong></p>
|
|
<ul>
|
|
<li>Access token: 15 minutes expiry</li>
|
|
<li>Refresh token: 7 days expiry</li>
|
|
<li>Algorithm: RS256 (RSA with SHA-256)</li>
|
|
<li>Claims: jti (UUID), sub (user_id), workspace, permissions_hash, iat, exp, iss, aud</li>
|
|
</ul>
|
|
<p><strong>Unit Tests:</strong> 11 comprehensive tests covering:</p>
|
|
<ul>
|
|
<li>Token pair generation</li>
|
|
<li>Token validation</li>
|
|
<li>Token revocation</li>
|
|
<li>Token rotation</li>
|
|
<li>Header extraction</li>
|
|
<li>Blacklist cleanup</li>
|
|
<li>Claims expiry checks</li>
|
|
<li>Token metadata</li>
|
|
</ul>
|
|
<hr />
|
|
<h3 id="2-provisioningplatformcontrol-centersrcauthmodrs-310-lines"><a class="header" href="#2-provisioningplatformcontrol-centersrcauthmodrs-310-lines">2. <strong><code>provisioning/platform/control-center/src/auth/mod.rs</code></strong> (310 lines)</a></h3>
|
|
<p>Unified authentication module with comprehensive documentation.</p>
|
|
<p><strong>Key Features:</strong></p>
|
|
<ul>
|
|
<li>Module organization and re-exports</li>
|
|
<li><code>AuthService</code> - Unified authentication facade</li>
|
|
<li>Complete authentication flow documentation</li>
|
|
<li>Login/logout workflows</li>
|
|
<li>Token refresh mechanism</li>
|
|
<li>Permissions hash generation using SHA256</li>
|
|
</ul>
|
|
<p><strong>Methods:</strong></p>
|
|
<ul>
|
|
<li><code>login()</code> - Authenticate user and generate tokens</li>
|
|
<li><code>logout()</code> - Revoke tokens on logout</li>
|
|
<li><code>validate()</code> - Validate access token</li>
|
|
<li><code>refresh()</code> - Rotate tokens using refresh token</li>
|
|
<li><code>generate_permissions_hash()</code> - SHA256 hash of user roles</li>
|
|
</ul>
|
|
<p><strong>Architecture Diagram:</strong> Included in module documentation
|
|
<strong>Token Flow Diagram:</strong> Complete authentication flow documented</p>
|
|
<hr />
|
|
<h3 id="3-provisioningplatformcontrol-centersrcauthpasswordrs-223-lines"><a class="header" href="#3-provisioningplatformcontrol-centersrcauthpasswordrs-223-lines">3. <strong><code>provisioning/platform/control-center/src/auth/password.rs</code></strong> (223 lines)</a></h3>
|
|
<p>Secure password hashing using Argon2id.</p>
|
|
<p><strong>Key Features:</strong></p>
|
|
<ul>
|
|
<li>Argon2id password hashing (memory-hard, side-channel resistant)</li>
|
|
<li>Password verification</li>
|
|
<li>Password strength evaluation (Weak/Fair/Good/Strong/VeryStrong)</li>
|
|
<li>Password requirements validation</li>
|
|
<li>Cryptographically secure random salts</li>
|
|
</ul>
|
|
<p><strong>Structs:</strong></p>
|
|
<ul>
|
|
<li><code>PasswordStrength</code> - Enum for password strength levels</li>
|
|
<li><code>PasswordService</code> - Password management service</li>
|
|
</ul>
|
|
<p><strong>Methods:</strong></p>
|
|
<ul>
|
|
<li><code>hash_password()</code> - Hash password with Argon2id</li>
|
|
<li><code>verify_password()</code> - Verify password against hash</li>
|
|
<li><code>evaluate_strength()</code> - Evaluate password strength</li>
|
|
<li><code>meets_requirements()</code> - Check minimum requirements (8+ chars, 2+ types)</li>
|
|
</ul>
|
|
<p><strong>Unit Tests:</strong> 8 tests covering:</p>
|
|
<ul>
|
|
<li>Password hashing</li>
|
|
<li>Password verification</li>
|
|
<li>Strength evaluation (all levels)</li>
|
|
<li>Requirements validation</li>
|
|
<li>Different salts producing different hashes</li>
|
|
</ul>
|
|
<hr />
|
|
<h3 id="4-provisioningplatformcontrol-centersrcauthuserrs-466-lines"><a class="header" href="#4-provisioningplatformcontrol-centersrcauthuserrs-466-lines">4. <strong><code>provisioning/platform/control-center/src/auth/user.rs</code></strong> (466 lines)</a></h3>
|
|
<p>User management service with role-based access control.</p>
|
|
<p><strong>Key Features:</strong></p>
|
|
<ul>
|
|
<li>User CRUD operations</li>
|
|
<li>Role-based access control (Admin, Developer, Operator, Viewer, Auditor)</li>
|
|
<li>User status management (Active, Suspended, Locked, Disabled)</li>
|
|
<li>Failed login tracking with automatic lockout (5 attempts)</li>
|
|
<li>Thread-safe in-memory storage (Arc+RwLock with HashMap)</li>
|
|
<li>Username and email uniqueness enforcement</li>
|
|
<li>Last login tracking</li>
|
|
</ul>
|
|
<p><strong>Structs:</strong></p>
|
|
<ul>
|
|
<li><code>UserRole</code> - Enum with 5 roles</li>
|
|
<li><code>UserStatus</code> - Account status enum</li>
|
|
<li><code>User</code> - Complete user entity with metadata</li>
|
|
<li><code>UserService</code> - User management service</li>
|
|
</ul>
|
|
<p><strong>User Fields:</strong></p>
|
|
<ul>
|
|
<li>id (UUID), username, email, full_name</li>
|
|
<li>roles (Vec<UserRole>), status (UserStatus)</li>
|
|
<li>password_hash (Argon2), mfa_enabled, mfa_secret</li>
|
|
<li>created_at, last_login, password_changed_at</li>
|
|
<li>failed_login_attempts, last_failed_login</li>
|
|
<li>metadata (HashMap<String, String>)</li>
|
|
</ul>
|
|
<p><strong>Methods:</strong></p>
|
|
<ul>
|
|
<li><code>create_user()</code> - Create new user with validation</li>
|
|
<li><code>find_by_id()</code>, <code>find_by_username()</code>, <code>find_by_email()</code> - User lookup</li>
|
|
<li><code>update_user()</code> - Update user information</li>
|
|
<li><code>update_last_login()</code> - Track successful login</li>
|
|
<li><code>delete_user()</code> - Remove user and mappings</li>
|
|
<li><code>list_users()</code>, <code>count()</code> - User enumeration</li>
|
|
</ul>
|
|
<p><strong>Unit Tests:</strong> 9 tests covering:</p>
|
|
<ul>
|
|
<li>User creation</li>
|
|
<li>Username/email lookups</li>
|
|
<li>Duplicate prevention</li>
|
|
<li>Role checking</li>
|
|
<li>Failed login lockout</li>
|
|
<li>Last login tracking</li>
|
|
<li>User listing</li>
|
|
</ul>
|
|
<hr />
|
|
<h3 id="5-provisioningplatformcontrol-centercargotoml-modified"><a class="header" href="#5-provisioningplatformcontrol-centercargotoml-modified">5. <strong><code>provisioning/platform/control-center/Cargo.toml</code></strong> (Modified)</a></h3>
|
|
<p>Dependencies already present:</p>
|
|
<ul>
|
|
<li>✅ <code>jsonwebtoken = "9"</code> (RS256 JWT signing)</li>
|
|
<li>✅ <code>serde = { workspace = true }</code> (with derive features)</li>
|
|
<li>✅ <code>chrono = { workspace = true }</code> (timestamp management)</li>
|
|
<li>✅ <code>uuid = { workspace = true }</code> (with serde, v4 features)</li>
|
|
<li>✅ <code>argon2 = { workspace = true }</code> (password hashing)</li>
|
|
<li>✅ <code>sha2 = { workspace = true }</code> (permissions hash)</li>
|
|
<li>✅ <code>thiserror = { workspace = true }</code> (error handling)</li>
|
|
</ul>
|
|
<hr />
|
|
<h2 id="security-features"><a class="header" href="#security-features">Security Features</a></h2>
|
|
<h3 id="1-rs256-asymmetric-signing"><a class="header" href="#1-rs256-asymmetric-signing">1. <strong>RS256 Asymmetric Signing</strong></a></h3>
|
|
<ul>
|
|
<li>Enhanced security over symmetric HMAC algorithms</li>
|
|
<li>Private key for signing (server-only)</li>
|
|
<li>Public key for verification (can be distributed)</li>
|
|
<li>Prevents token forgery even if public key is exposed</li>
|
|
</ul>
|
|
<h3 id="2-token-rotation"><a class="header" href="#2-token-rotation">2. <strong>Token Rotation</strong></a></h3>
|
|
<ul>
|
|
<li>Automatic rotation before expiry (5-minute threshold)</li>
|
|
<li>Old refresh tokens revoked after rotation</li>
|
|
<li>Seamless user experience with continuous authentication</li>
|
|
</ul>
|
|
<h3 id="3-token-revocation"><a class="header" href="#3-token-revocation">3. <strong>Token Revocation</strong></a></h3>
|
|
<ul>
|
|
<li>Blacklist-based revocation system</li>
|
|
<li>Thread-safe with Arc+RwLock</li>
|
|
<li>Automatic cleanup of expired tokens</li>
|
|
<li>Prevents use of revoked tokens</li>
|
|
</ul>
|
|
<h3 id="4-password-security"><a class="header" href="#4-password-security">4. <strong>Password Security</strong></a></h3>
|
|
<ul>
|
|
<li>Argon2id hashing (memory-hard, side-channel resistant)</li>
|
|
<li>Cryptographically secure random salts</li>
|
|
<li>Password strength evaluation</li>
|
|
<li>Failed login tracking with automatic lockout (5 attempts)</li>
|
|
</ul>
|
|
<h3 id="5-permissions-hash"><a class="header" href="#5-permissions-hash">5. <strong>Permissions Hash</strong></a></h3>
|
|
<ul>
|
|
<li>SHA256 hash of user roles for quick validation</li>
|
|
<li>Avoids full Cedar policy evaluation on every request</li>
|
|
<li>Deterministic hash for cache-friendly validation</li>
|
|
</ul>
|
|
<h3 id="6-thread-safety"><a class="header" href="#6-thread-safety">6. <strong>Thread Safety</strong></a></h3>
|
|
<ul>
|
|
<li>Arc+RwLock for concurrent access</li>
|
|
<li>Safe shared state across async runtime</li>
|
|
<li>No data races or deadlocks</li>
|
|
</ul>
|
|
<hr />
|
|
<h2 id="token-structure"><a class="header" href="#token-structure">Token Structure</a></h2>
|
|
<h3 id="access-token-15-minutes"><a class="header" href="#access-token-15-minutes">Access Token (15 minutes)</a></h3>
|
|
<pre><code class="language-json">{
|
|
"jti": "uuid-v4",
|
|
"sub": "user_id",
|
|
"workspace": "workspace_name",
|
|
"permissions_hash": "sha256_hex",
|
|
"type": "access",
|
|
"iat": 1696723200,
|
|
"exp": 1696724100,
|
|
"iss": "control-center",
|
|
"aud": ["orchestrator", "cli"],
|
|
"metadata": {
|
|
"ip_address": "192.168.1.1",
|
|
"user_agent": "provisioning-cli/1.0"
|
|
}
|
|
}
|
|
</code></pre>
|
|
<h3 id="refresh-token-7-days"><a class="header" href="#refresh-token-7-days">Refresh Token (7 days)</a></h3>
|
|
<pre><code class="language-json">{
|
|
"jti": "uuid-v4",
|
|
"sub": "user_id",
|
|
"workspace": "workspace_name",
|
|
"permissions_hash": "sha256_hex",
|
|
"type": "refresh",
|
|
"iat": 1696723200,
|
|
"exp": 1697328000,
|
|
"iss": "control-center",
|
|
"aud": ["orchestrator", "cli"]
|
|
}
|
|
</code></pre>
|
|
<hr />
|
|
<h2 id="authentication-flow"><a class="header" href="#authentication-flow">Authentication Flow</a></h2>
|
|
<h3 id="1-login"><a class="header" href="#1-login">1. Login</a></h3>
|
|
<pre><code>User credentials (username + password)
|
|
↓
|
|
Password verification (Argon2)
|
|
↓
|
|
User status check (Active?)
|
|
↓
|
|
Permissions hash generation (SHA256 of roles)
|
|
↓
|
|
Token pair generation (access + refresh)
|
|
↓
|
|
Return tokens to client
|
|
</code></pre>
|
|
<h3 id="2-api-request"><a class="header" href="#2-api-request">2. API Request</a></h3>
|
|
<pre><code>Authorization: Bearer <access_token>
|
|
↓
|
|
Extract token from header
|
|
↓
|
|
Validate signature (RS256)
|
|
↓
|
|
Check expiration
|
|
↓
|
|
Check revocation
|
|
↓
|
|
Validate issuer/audience
|
|
↓
|
|
Grant access
|
|
</code></pre>
|
|
<h3 id="3-token-rotation"><a class="header" href="#3-token-rotation">3. Token Rotation</a></h3>
|
|
<pre><code>Access token about to expire (<5 min)
|
|
↓
|
|
Client sends refresh token
|
|
↓
|
|
Validate refresh token
|
|
↓
|
|
Revoke old refresh token
|
|
↓
|
|
Generate new token pair
|
|
↓
|
|
Return new tokens
|
|
</code></pre>
|
|
<h3 id="4-logout"><a class="header" href="#4-logout">4. Logout</a></h3>
|
|
<pre><code>Client sends access token
|
|
↓
|
|
Extract token claims
|
|
↓
|
|
Add jti to blacklist
|
|
↓
|
|
Token immediately revoked
|
|
</code></pre>
|
|
<hr />
|
|
<h2 id="usage-examples"><a class="header" href="#usage-examples">Usage Examples</a></h2>
|
|
<h3 id="initialize-jwt-service"><a class="header" href="#initialize-jwt-service">Initialize JWT Service</a></h3>
|
|
<pre><code class="language-rust">use control_center::auth::JwtService;
|
|
|
|
let private_key = std::fs::read("keys/private.pem")?;
|
|
let public_key = std::fs::read("keys/public.pem")?;
|
|
|
|
let jwt_service = JwtService::new(
|
|
&private_key,
|
|
&public_key,
|
|
"control-center",
|
|
vec!["orchestrator".to_string(), "cli".to_string()],
|
|
)?;</code></pre>
|
|
<h3 id="generate-token-pair"><a class="header" href="#generate-token-pair">Generate Token Pair</a></h3>
|
|
<pre><code class="language-rust">let tokens = jwt_service.generate_token_pair(
|
|
"user123",
|
|
"workspace1",
|
|
"sha256_permissions_hash",
|
|
None, // Optional metadata
|
|
)?;
|
|
|
|
println!("Access token: {}", tokens.access_token);
|
|
println!("Refresh token: {}", tokens.refresh_token);
|
|
println!("Expires in: {} seconds", tokens.expires_in);</code></pre>
|
|
<h3 id="validate-token"><a class="header" href="#validate-token">Validate Token</a></h3>
|
|
<pre><code class="language-rust">let claims = jwt_service.validate_token(&access_token)?;
|
|
|
|
println!("User ID: {}", claims.sub);
|
|
println!("Workspace: {}", claims.workspace);
|
|
println!("Expires at: {}", claims.exp);</code></pre>
|
|
<h3 id="rotate-token"><a class="header" href="#rotate-token">Rotate Token</a></h3>
|
|
<pre><code class="language-rust">if claims.needs_rotation() {
|
|
let new_tokens = jwt_service.rotate_token(&refresh_token)?;
|
|
// Use new tokens
|
|
}</code></pre>
|
|
<h3 id="revoke-token-logout"><a class="header" href="#revoke-token-logout">Revoke Token (Logout)</a></h3>
|
|
<pre><code class="language-rust">jwt_service.revoke_token(&claims.jti, claims.exp)?;</code></pre>
|
|
<h3 id="full-authentication-flow"><a class="header" href="#full-authentication-flow">Full Authentication Flow</a></h3>
|
|
<pre><code class="language-rust">use control_center::auth::{AuthService, PasswordService, UserService, JwtService};
|
|
|
|
// Initialize services
|
|
let jwt_service = JwtService::new(...)?;
|
|
let password_service = PasswordService::new();
|
|
let user_service = UserService::new();
|
|
|
|
let auth_service = AuthService::new(
|
|
jwt_service,
|
|
password_service,
|
|
user_service,
|
|
);
|
|
|
|
// Login
|
|
let tokens = auth_service.login("alice", "password123", "workspace1").await?;
|
|
|
|
// Validate
|
|
let claims = auth_service.validate(&tokens.access_token)?;
|
|
|
|
// Refresh
|
|
let new_tokens = auth_service.refresh(&tokens.refresh_token)?;
|
|
|
|
// Logout
|
|
auth_service.logout(&tokens.access_token).await?;</code></pre>
|
|
<hr />
|
|
<h2 id="testing"><a class="header" href="#testing">Testing</a></h2>
|
|
<h3 id="test-coverage"><a class="header" href="#test-coverage">Test Coverage</a></h3>
|
|
<ul>
|
|
<li><strong>JWT Tests:</strong> 11 unit tests (627 lines total)</li>
|
|
<li><strong>Password Tests:</strong> 8 unit tests (223 lines total)</li>
|
|
<li><strong>User Tests:</strong> 9 unit tests (466 lines total)</li>
|
|
<li><strong>Auth Module Tests:</strong> 2 integration tests (310 lines total)</li>
|
|
</ul>
|
|
<h3 id="running-tests"><a class="header" href="#running-tests">Running Tests</a></h3>
|
|
<pre><code class="language-bash">cd provisioning/platform/control-center
|
|
|
|
# Run all auth tests
|
|
cargo test --lib auth
|
|
|
|
# Run specific module tests
|
|
cargo test --lib auth::jwt
|
|
cargo test --lib auth::password
|
|
cargo test --lib auth::user
|
|
|
|
# Run with output
|
|
cargo test --lib auth -- --nocapture
|
|
</code></pre>
|
|
<hr />
|
|
<h2 id="line-counts"><a class="header" href="#line-counts">Line Counts</a></h2>
|
|
<div class="table-wrapper"><table><thead><tr><th>File</th><th>Lines</th><th>Description</th></tr></thead><tbody>
|
|
<tr><td><code>auth/jwt.rs</code></td><td>627</td><td>JWT token management</td></tr>
|
|
<tr><td><code>auth/mod.rs</code></td><td>310</td><td>Authentication module</td></tr>
|
|
<tr><td><code>auth/password.rs</code></td><td>223</td><td>Password hashing</td></tr>
|
|
<tr><td><code>auth/user.rs</code></td><td>466</td><td>User management</td></tr>
|
|
<tr><td><strong>Total</strong></td><td><strong>1,626</strong></td><td>Complete auth system</td></tr>
|
|
</tbody></table>
|
|
</div>
|
|
<hr />
|
|
<h2 id="integration-points"><a class="header" href="#integration-points">Integration Points</a></h2>
|
|
<h3 id="1-control-center-api"><a class="header" href="#1-control-center-api">1. <strong>Control Center API</strong></a></h3>
|
|
<ul>
|
|
<li>REST endpoints for login/logout</li>
|
|
<li>Authorization middleware for protected routes</li>
|
|
<li>Token extraction from Authorization headers</li>
|
|
</ul>
|
|
<h3 id="2-cedar-policy-engine"><a class="header" href="#2-cedar-policy-engine">2. <strong>Cedar Policy Engine</strong></a></h3>
|
|
<ul>
|
|
<li>Permissions hash in JWT claims</li>
|
|
<li>Quick validation without full policy evaluation</li>
|
|
<li>Role-based access control integration</li>
|
|
</ul>
|
|
<h3 id="3-orchestrator-service"><a class="header" href="#3-orchestrator-service">3. <strong>Orchestrator Service</strong></a></h3>
|
|
<ul>
|
|
<li>JWT validation for orchestrator API calls</li>
|
|
<li>Token-based service-to-service authentication</li>
|
|
<li>Workspace-scoped operations</li>
|
|
</ul>
|
|
<h3 id="4-cli-tool"><a class="header" href="#4-cli-tool">4. <strong>CLI Tool</strong></a></h3>
|
|
<ul>
|
|
<li>Token storage in local config</li>
|
|
<li>Automatic token rotation</li>
|
|
<li>Workspace switching with token refresh</li>
|
|
</ul>
|
|
<hr />
|
|
<h2 id="production-considerations"><a class="header" href="#production-considerations">Production Considerations</a></h2>
|
|
<h3 id="1-key-management"><a class="header" href="#1-key-management">1. <strong>Key Management</strong></a></h3>
|
|
<ul>
|
|
<li>Generate strong RSA keys (2048-bit minimum, 4096-bit recommended)</li>
|
|
<li>Store private key securely (environment variable, secrets manager)</li>
|
|
<li>Rotate keys periodically (6-12 months)</li>
|
|
<li>Public key can be distributed to services</li>
|
|
</ul>
|
|
<h3 id="2-persistence"><a class="header" href="#2-persistence">2. <strong>Persistence</strong></a></h3>
|
|
<ul>
|
|
<li>Current implementation uses in-memory storage (development)</li>
|
|
<li>Production: Replace with database (PostgreSQL, SurrealDB)</li>
|
|
<li>Blacklist should persist across restarts</li>
|
|
<li>Consider Redis for blacklist (fast lookup, TTL support)</li>
|
|
</ul>
|
|
<h3 id="3-monitoring"><a class="header" href="#3-monitoring">3. <strong>Monitoring</strong></a></h3>
|
|
<ul>
|
|
<li>Track token generation rates</li>
|
|
<li>Monitor blacklist size</li>
|
|
<li>Alert on high failed login rates</li>
|
|
<li>Log token validation failures</li>
|
|
</ul>
|
|
<h3 id="4-rate-limiting"><a class="header" href="#4-rate-limiting">4. <strong>Rate Limiting</strong></a></h3>
|
|
<ul>
|
|
<li>Implement rate limiting on login endpoint</li>
|
|
<li>Prevent brute-force attacks</li>
|
|
<li>Use tower_governor middleware (already in dependencies)</li>
|
|
</ul>
|
|
<h3 id="5-scalability"><a class="header" href="#5-scalability">5. <strong>Scalability</strong></a></h3>
|
|
<ul>
|
|
<li>Blacklist cleanup job (periodic background task)</li>
|
|
<li>Consider distributed cache for blacklist (Redis Cluster)</li>
|
|
<li>Stateless token validation (except blacklist check)</li>
|
|
</ul>
|
|
<hr />
|
|
<h2 id="next-steps"><a class="header" href="#next-steps">Next Steps</a></h2>
|
|
<h3 id="1-database-integration"><a class="header" href="#1-database-integration">1. <strong>Database Integration</strong></a></h3>
|
|
<ul>
|
|
<li>Replace in-memory storage with persistent database</li>
|
|
<li>Implement user repository pattern</li>
|
|
<li>Add blacklist table with automatic cleanup</li>
|
|
</ul>
|
|
<h3 id="2-mfa-support"><a class="header" href="#2-mfa-support">2. <strong>MFA Support</strong></a></h3>
|
|
<ul>
|
|
<li>TOTP (Time-based One-Time Password) implementation</li>
|
|
<li>QR code generation for MFA setup</li>
|
|
<li>MFA verification during login</li>
|
|
</ul>
|
|
<h3 id="3-oauth2-integration"><a class="header" href="#3-oauth2-integration">3. <strong>OAuth2 Integration</strong></a></h3>
|
|
<ul>
|
|
<li>OAuth2 provider support (GitHub, Google, etc.)</li>
|
|
<li>Social login flow</li>
|
|
<li>Token exchange</li>
|
|
</ul>
|
|
<h3 id="4-audit-logging"><a class="header" href="#4-audit-logging">4. <strong>Audit Logging</strong></a></h3>
|
|
<ul>
|
|
<li>Log all authentication events</li>
|
|
<li>Track login/logout/rotation</li>
|
|
<li>Monitor suspicious activities</li>
|
|
</ul>
|
|
<h3 id="5-websocket-authentication"><a class="header" href="#5-websocket-authentication">5. <strong>WebSocket Authentication</strong></a></h3>
|
|
<ul>
|
|
<li>JWT authentication for WebSocket connections</li>
|
|
<li>Token validation on connect</li>
|
|
<li>Keep-alive token refresh</li>
|
|
</ul>
|
|
<hr />
|
|
<h2 id="conclusion"><a class="header" href="#conclusion">Conclusion</a></h2>
|
|
<p>The JWT authentication system has been fully implemented with production-ready security features:</p>
|
|
<p>✅ <strong>RS256 asymmetric signing</strong> for enhanced security
|
|
✅ <strong>Token rotation</strong> for seamless user experience
|
|
✅ <strong>Token revocation</strong> with thread-safe blacklist
|
|
✅ <strong>Argon2id password hashing</strong> with strength evaluation
|
|
✅ <strong>User management</strong> with role-based access control
|
|
✅ <strong>Comprehensive testing</strong> with 30+ unit tests
|
|
✅ <strong>Thread-safe implementation</strong> with Arc+RwLock
|
|
✅ <strong>Cedar integration</strong> via permissions hash</p>
|
|
<p>The system follows idiomatic Rust patterns with proper error handling, comprehensive documentation, and extensive test coverage.</p>
|
|
<p><strong>Total Lines:</strong> 1,626 lines of production-quality Rust code
|
|
<strong>Test Coverage:</strong> 30+ unit tests across all modules
|
|
<strong>Security:</strong> Industry-standard algorithms and best practices</p>
|
|
|
|
</main>
|
|
|
|
<nav class="nav-wrapper" aria-label="Page navigation">
|
|
<!-- Mobile navigation buttons -->
|
|
<a rel="prev" href="../architecture/DATABASE_AND_CONFIG_ARCHITECTURE.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../architecture/MFA_IMPLEMENTATION_SUMMARY.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
|
|
<div style="clear: both"></div>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
|
|
<nav class="nav-wide-wrapper" aria-label="Page navigation">
|
|
<a rel="prev" href="../architecture/DATABASE_AND_CONFIG_ARCHITECTURE.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
|
|
<i class="fa fa-angle-left"></i>
|
|
</a>
|
|
|
|
<a rel="next prefetch" href="../architecture/MFA_IMPLEMENTATION_SUMMARY.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
|
|
<i class="fa fa-angle-right"></i>
|
|
</a>
|
|
</nav>
|
|
|
|
</div>
|
|
|
|
<!-- Livereload script (if served using the cli tool) -->
|
|
<script>
|
|
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
|
|
const socket = new WebSocket(wsAddress);
|
|
socket.onmessage = function (event) {
|
|
if (event.data === "reload") {
|
|
socket.close();
|
|
location.reload();
|
|
}
|
|
};
|
|
|
|
window.onbeforeunload = function() {
|
|
socket.close();
|
|
}
|
|
</script>
|
|
|
|
|
|
|
|
<script>
|
|
window.playground_copyable = true;
|
|
</script>
|
|
|
|
|
|
<script src="../elasticlunr.min.js"></script>
|
|
<script src="../mark.min.js"></script>
|
|
<script src="../searcher.js"></script>
|
|
|
|
<script src="../clipboard.min.js"></script>
|
|
<script src="../highlight.js"></script>
|
|
<script src="../book.js"></script>
|
|
|
|
<!-- Custom JS scripts -->
|
|
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|