@authrim/setup 0.1.134 → 0.1.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/cloudflare.d.ts.map +1 -1
- package/dist/core/cloudflare.js +15 -0
- package/dist/core/cloudflare.js.map +1 -1
- package/dist/web/api.d.ts.map +1 -1
- package/dist/web/api.js +55 -31
- package/dist/web/api.js.map +1 -1
- package/migrations/000_fresh_schema.sql +1966 -0
- package/migrations/admin/001_admin_users.sql +189 -0
- package/migrations/admin/002_admin_rbac.sql +256 -0
- package/migrations/admin/003_admin_audit.sql +175 -0
- package/migrations/admin/004_admin_security.sql +132 -0
- package/migrations/admin/005_admin_abac_rebac.sql +345 -0
- package/migrations/admin/006_admin_setup_tokens.sql +91 -0
- package/migrations/pii/001_pii_initial.sql +466 -0
- package/migrations/pii/002_pii_log_tables.sql +139 -0
- package/migrations/pii/003_tombstone_timestamps.sql +12 -0
- package/migrations/pii/004_cleanup_admin_from_pii.sql +50 -0
- package/package.json +2 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Migration: Admin Security - IP Allowlist (D1_ADMIN)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
-- Created: 2025-01-22
|
|
5
|
+
-- Description: Creates admin_ip_allowlist table for IP-based access control.
|
|
6
|
+
-- Provides network-level security for Admin access.
|
|
7
|
+
--
|
|
8
|
+
-- IMPORTANT: This migration is for D1_ADMIN (dedicated Admin database).
|
|
9
|
+
-- Implements IP restriction for Admin panel access.
|
|
10
|
+
--
|
|
11
|
+
-- Architecture:
|
|
12
|
+
-- - admin_ip_allowlist: IP addresses/ranges allowed to access Admin
|
|
13
|
+
-- - Empty list = all IPs allowed (default behavior)
|
|
14
|
+
-- - Supports CIDR notation (192.168.1.0/24) and single IPs (10.0.0.1)
|
|
15
|
+
-- =============================================================================
|
|
16
|
+
|
|
17
|
+
-- =============================================================================
|
|
18
|
+
-- admin_ip_allowlist Table
|
|
19
|
+
-- =============================================================================
|
|
20
|
+
-- IP-based access control for Admin panel.
|
|
21
|
+
-- When the table is empty, all IPs are allowed.
|
|
22
|
+
-- When entries exist, only matching IPs can access Admin.
|
|
23
|
+
--
|
|
24
|
+
-- IP formats supported:
|
|
25
|
+
-- - Single IPv4: 192.168.1.100
|
|
26
|
+
-- - IPv4 CIDR: 192.168.1.0/24
|
|
27
|
+
-- - Single IPv6: 2001:db8::1
|
|
28
|
+
-- - IPv6 CIDR: 2001:db8::/32
|
|
29
|
+
-- =============================================================================
|
|
30
|
+
|
|
31
|
+
CREATE TABLE IF NOT EXISTS admin_ip_allowlist (
|
|
32
|
+
-- Entry ID (UUID v4)
|
|
33
|
+
id TEXT PRIMARY KEY,
|
|
34
|
+
|
|
35
|
+
-- Multi-tenant support
|
|
36
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
37
|
+
|
|
38
|
+
-- IP address or CIDR range
|
|
39
|
+
ip_range TEXT NOT NULL,
|
|
40
|
+
|
|
41
|
+
-- IP version for easier filtering
|
|
42
|
+
ip_version INTEGER NOT NULL DEFAULT 4, -- 4 or 6
|
|
43
|
+
|
|
44
|
+
-- Human-readable description
|
|
45
|
+
description TEXT, -- e.g., 'Office VPN', 'Home IP', 'CI/CD server'
|
|
46
|
+
|
|
47
|
+
-- Enable/disable without deleting
|
|
48
|
+
enabled INTEGER DEFAULT 1,
|
|
49
|
+
|
|
50
|
+
-- Audit fields
|
|
51
|
+
created_by TEXT, -- Admin user ID who added this entry
|
|
52
|
+
created_at INTEGER NOT NULL,
|
|
53
|
+
updated_at INTEGER NOT NULL,
|
|
54
|
+
|
|
55
|
+
-- Unique constraint for IP range per tenant
|
|
56
|
+
UNIQUE(tenant_id, ip_range)
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
-- =============================================================================
|
|
60
|
+
-- Indexes for admin_ip_allowlist
|
|
61
|
+
-- =============================================================================
|
|
62
|
+
|
|
63
|
+
-- Tenant-scoped lookup (main query pattern)
|
|
64
|
+
CREATE INDEX IF NOT EXISTS idx_admin_ip_allowlist_tenant ON admin_ip_allowlist(tenant_id, enabled);
|
|
65
|
+
|
|
66
|
+
-- IP version filtering (for IPv4/IPv6 specific queries)
|
|
67
|
+
CREATE INDEX IF NOT EXISTS idx_admin_ip_allowlist_version ON admin_ip_allowlist(tenant_id, ip_version, enabled);
|
|
68
|
+
|
|
69
|
+
-- Enabled entries only (for authorization checks)
|
|
70
|
+
CREATE INDEX IF NOT EXISTS idx_admin_ip_allowlist_enabled ON admin_ip_allowlist(enabled, tenant_id);
|
|
71
|
+
|
|
72
|
+
-- =============================================================================
|
|
73
|
+
-- admin_login_attempts Table (Optional - for rate limiting)
|
|
74
|
+
-- =============================================================================
|
|
75
|
+
-- Tracks failed login attempts for rate limiting and security monitoring.
|
|
76
|
+
-- Used to implement progressive delays and account lockout.
|
|
77
|
+
-- =============================================================================
|
|
78
|
+
|
|
79
|
+
CREATE TABLE IF NOT EXISTS admin_login_attempts (
|
|
80
|
+
-- Attempt ID (UUID v4)
|
|
81
|
+
id TEXT PRIMARY KEY,
|
|
82
|
+
|
|
83
|
+
-- Multi-tenant support
|
|
84
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
85
|
+
|
|
86
|
+
-- Target email (even if user doesn't exist)
|
|
87
|
+
email TEXT NOT NULL,
|
|
88
|
+
|
|
89
|
+
-- Request context
|
|
90
|
+
ip_address TEXT NOT NULL,
|
|
91
|
+
user_agent TEXT,
|
|
92
|
+
|
|
93
|
+
-- Result
|
|
94
|
+
success INTEGER NOT NULL DEFAULT 0, -- 0 = failed, 1 = success
|
|
95
|
+
failure_reason TEXT, -- e.g., 'invalid_password', 'user_not_found', 'account_locked'
|
|
96
|
+
|
|
97
|
+
-- Timestamp
|
|
98
|
+
created_at INTEGER NOT NULL
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
-- =============================================================================
|
|
102
|
+
-- Indexes for admin_login_attempts
|
|
103
|
+
-- =============================================================================
|
|
104
|
+
|
|
105
|
+
-- Email-based lookup (for rate limiting per email)
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_admin_login_attempts_email ON admin_login_attempts(tenant_id, email, created_at DESC);
|
|
107
|
+
|
|
108
|
+
-- IP-based lookup (for rate limiting per IP)
|
|
109
|
+
CREATE INDEX IF NOT EXISTS idx_admin_login_attempts_ip ON admin_login_attempts(ip_address, created_at DESC);
|
|
110
|
+
|
|
111
|
+
-- Time-based cleanup
|
|
112
|
+
CREATE INDEX IF NOT EXISTS idx_admin_login_attempts_time ON admin_login_attempts(created_at);
|
|
113
|
+
|
|
114
|
+
-- Success tracking (for security monitoring)
|
|
115
|
+
CREATE INDEX IF NOT EXISTS idx_admin_login_attempts_success ON admin_login_attempts(success, created_at DESC);
|
|
116
|
+
|
|
117
|
+
-- =============================================================================
|
|
118
|
+
-- Migration Complete
|
|
119
|
+
-- =============================================================================
|
|
120
|
+
-- IP allowlist is now ready for use.
|
|
121
|
+
--
|
|
122
|
+
-- Usage:
|
|
123
|
+
-- 1. When admin_ip_allowlist is empty for a tenant, all IPs are allowed
|
|
124
|
+
-- 2. When entries exist, only enabled entries are checked
|
|
125
|
+
-- 3. Client IP is obtained from CF-Connecting-IP header (Cloudflare)
|
|
126
|
+
-- 4. CIDR matching is done in application code
|
|
127
|
+
--
|
|
128
|
+
-- Security notes:
|
|
129
|
+
-- - Always use CF-Connecting-IP for real client IP (not X-Forwarded-For)
|
|
130
|
+
-- - Consider adding office VPN and CI/CD IPs before restricting
|
|
131
|
+
-- - Keep at least one admin with IP access to prevent lockout
|
|
132
|
+
-- =============================================================================
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Migration: Admin ABAC & ReBAC (D1_ADMIN)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
-- Created: 2025-01-22
|
|
5
|
+
-- Description: Creates tables for Admin ABAC (Attribute-Based Access Control)
|
|
6
|
+
-- and ReBAC (Relationship-Based Access Control).
|
|
7
|
+
--
|
|
8
|
+
-- IMPORTANT: This migration is for D1_ADMIN (dedicated Admin database).
|
|
9
|
+
-- Separate from EndUser ABAC/ReBAC in D1_CORE.
|
|
10
|
+
--
|
|
11
|
+
-- Architecture:
|
|
12
|
+
-- - admin_attributes: Attribute type definitions
|
|
13
|
+
-- - admin_attribute_values: Attribute values assigned to Admin users
|
|
14
|
+
-- - admin_relationships: Relationships between Admin users/entities
|
|
15
|
+
-- - admin_policies: Policy definitions combining RBAC/ABAC/ReBAC
|
|
16
|
+
-- =============================================================================
|
|
17
|
+
|
|
18
|
+
-- =============================================================================
|
|
19
|
+
-- admin_attributes Table
|
|
20
|
+
-- =============================================================================
|
|
21
|
+
-- Attribute definitions for Admin ABAC.
|
|
22
|
+
-- Examples: department, location, clearance_level, project_access
|
|
23
|
+
-- =============================================================================
|
|
24
|
+
|
|
25
|
+
CREATE TABLE IF NOT EXISTS admin_attributes (
|
|
26
|
+
-- Attribute ID (UUID v4)
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
|
|
29
|
+
-- Multi-tenant support
|
|
30
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
31
|
+
|
|
32
|
+
-- Attribute identification
|
|
33
|
+
name TEXT NOT NULL, -- Machine-readable name (e.g., 'department')
|
|
34
|
+
display_name TEXT, -- Human-readable name (e.g., 'Department')
|
|
35
|
+
description TEXT,
|
|
36
|
+
|
|
37
|
+
-- Attribute type (determines value validation)
|
|
38
|
+
-- string: Free-form text
|
|
39
|
+
-- enum: Must be one of allowed_values
|
|
40
|
+
-- number: Numeric value (with optional min/max)
|
|
41
|
+
-- boolean: true/false
|
|
42
|
+
-- date: ISO 8601 date
|
|
43
|
+
-- array: Multiple values allowed
|
|
44
|
+
attribute_type TEXT NOT NULL DEFAULT 'string',
|
|
45
|
+
|
|
46
|
+
-- For enum type: JSON array of allowed values
|
|
47
|
+
-- e.g., ["engineering", "sales", "support"]
|
|
48
|
+
allowed_values_json TEXT,
|
|
49
|
+
|
|
50
|
+
-- Validation constraints
|
|
51
|
+
min_value INTEGER, -- For number type
|
|
52
|
+
max_value INTEGER, -- For number type
|
|
53
|
+
regex_pattern TEXT, -- For string type
|
|
54
|
+
|
|
55
|
+
-- Whether this attribute is required for all Admin users
|
|
56
|
+
is_required INTEGER DEFAULT 0,
|
|
57
|
+
|
|
58
|
+
-- Whether this attribute can have multiple values
|
|
59
|
+
is_multi_valued INTEGER DEFAULT 0,
|
|
60
|
+
|
|
61
|
+
-- System attribute flag (cannot be modified or deleted)
|
|
62
|
+
is_system INTEGER DEFAULT 0,
|
|
63
|
+
|
|
64
|
+
-- Lifecycle
|
|
65
|
+
created_at INTEGER NOT NULL,
|
|
66
|
+
updated_at INTEGER NOT NULL,
|
|
67
|
+
|
|
68
|
+
-- Unique constraint for attribute name per tenant
|
|
69
|
+
UNIQUE(tenant_id, name)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
-- =============================================================================
|
|
73
|
+
-- Indexes for admin_attributes
|
|
74
|
+
-- =============================================================================
|
|
75
|
+
|
|
76
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attributes_tenant ON admin_attributes(tenant_id);
|
|
77
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attributes_name ON admin_attributes(tenant_id, name);
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attributes_type ON admin_attributes(attribute_type);
|
|
79
|
+
|
|
80
|
+
-- =============================================================================
|
|
81
|
+
-- admin_attribute_values Table
|
|
82
|
+
-- =============================================================================
|
|
83
|
+
-- Attribute values assigned to Admin users.
|
|
84
|
+
-- Links admin_users to admin_attributes with specific values.
|
|
85
|
+
-- =============================================================================
|
|
86
|
+
|
|
87
|
+
CREATE TABLE IF NOT EXISTS admin_attribute_values (
|
|
88
|
+
-- Value assignment ID (UUID v4)
|
|
89
|
+
id TEXT PRIMARY KEY,
|
|
90
|
+
|
|
91
|
+
-- Multi-tenant support
|
|
92
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
93
|
+
|
|
94
|
+
-- References
|
|
95
|
+
admin_user_id TEXT NOT NULL REFERENCES admin_users(id) ON DELETE CASCADE,
|
|
96
|
+
admin_attribute_id TEXT NOT NULL REFERENCES admin_attributes(id) ON DELETE CASCADE,
|
|
97
|
+
|
|
98
|
+
-- The actual value (stored as text, parsed according to attribute_type)
|
|
99
|
+
value TEXT NOT NULL,
|
|
100
|
+
|
|
101
|
+
-- For multi-valued attributes, this is the index (0, 1, 2, ...)
|
|
102
|
+
value_index INTEGER DEFAULT 0,
|
|
103
|
+
|
|
104
|
+
-- Source of this value (manual, idp_sync, api, etc.)
|
|
105
|
+
source TEXT DEFAULT 'manual',
|
|
106
|
+
|
|
107
|
+
-- Expiration (for temporary attribute assignments)
|
|
108
|
+
expires_at INTEGER,
|
|
109
|
+
|
|
110
|
+
-- Audit fields
|
|
111
|
+
assigned_by TEXT, -- Admin user ID who assigned this value
|
|
112
|
+
created_at INTEGER NOT NULL,
|
|
113
|
+
updated_at INTEGER NOT NULL,
|
|
114
|
+
|
|
115
|
+
-- Unique constraint for single-valued attributes
|
|
116
|
+
-- For multi-valued, use UNIQUE(admin_user_id, admin_attribute_id, value_index)
|
|
117
|
+
UNIQUE(admin_user_id, admin_attribute_id, value_index)
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
-- =============================================================================
|
|
121
|
+
-- Indexes for admin_attribute_values
|
|
122
|
+
-- =============================================================================
|
|
123
|
+
|
|
124
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attr_values_user ON admin_attribute_values(admin_user_id);
|
|
125
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attr_values_attr ON admin_attribute_values(admin_attribute_id);
|
|
126
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attr_values_tenant ON admin_attribute_values(tenant_id);
|
|
127
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attr_values_expires ON admin_attribute_values(expires_at);
|
|
128
|
+
|
|
129
|
+
-- Combined index for policy evaluation
|
|
130
|
+
CREATE INDEX IF NOT EXISTS idx_admin_attr_values_lookup
|
|
131
|
+
ON admin_attribute_values(admin_user_id, admin_attribute_id, value);
|
|
132
|
+
|
|
133
|
+
-- =============================================================================
|
|
134
|
+
-- admin_relationships Table
|
|
135
|
+
-- =============================================================================
|
|
136
|
+
-- Relationships between Admin users/entities for ReBAC.
|
|
137
|
+
-- Examples: manager_of, delegate_of, team_member
|
|
138
|
+
-- =============================================================================
|
|
139
|
+
|
|
140
|
+
CREATE TABLE IF NOT EXISTS admin_relationships (
|
|
141
|
+
-- Relationship ID (UUID v4)
|
|
142
|
+
id TEXT PRIMARY KEY,
|
|
143
|
+
|
|
144
|
+
-- Multi-tenant support
|
|
145
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
146
|
+
|
|
147
|
+
-- Relationship type (e.g., 'manager_of', 'delegate_of', 'team_member')
|
|
148
|
+
relationship_type TEXT NOT NULL,
|
|
149
|
+
|
|
150
|
+
-- Source entity (from)
|
|
151
|
+
from_type TEXT NOT NULL DEFAULT 'admin_user', -- admin_user, admin_role, team
|
|
152
|
+
from_id TEXT NOT NULL,
|
|
153
|
+
|
|
154
|
+
-- Target entity (to)
|
|
155
|
+
to_type TEXT NOT NULL DEFAULT 'admin_user', -- admin_user, admin_role, team
|
|
156
|
+
to_id TEXT NOT NULL,
|
|
157
|
+
|
|
158
|
+
-- Permission level granted by this relationship
|
|
159
|
+
-- full: All permissions of target
|
|
160
|
+
-- limited: Subset of permissions
|
|
161
|
+
-- read_only: Read-only access
|
|
162
|
+
permission_level TEXT NOT NULL DEFAULT 'full',
|
|
163
|
+
|
|
164
|
+
-- For hierarchical relationships (e.g., transitive manager relationship)
|
|
165
|
+
is_transitive INTEGER DEFAULT 0,
|
|
166
|
+
|
|
167
|
+
-- Expiration (for temporary relationships)
|
|
168
|
+
expires_at INTEGER,
|
|
169
|
+
|
|
170
|
+
-- Bidirectional flag (if true, relationship works both ways)
|
|
171
|
+
is_bidirectional INTEGER DEFAULT 0,
|
|
172
|
+
|
|
173
|
+
-- Additional metadata (JSON)
|
|
174
|
+
metadata_json TEXT,
|
|
175
|
+
|
|
176
|
+
-- Audit fields
|
|
177
|
+
created_by TEXT, -- Admin user ID who created this relationship
|
|
178
|
+
created_at INTEGER NOT NULL,
|
|
179
|
+
updated_at INTEGER NOT NULL
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
-- =============================================================================
|
|
183
|
+
-- Indexes for admin_relationships
|
|
184
|
+
-- =============================================================================
|
|
185
|
+
|
|
186
|
+
CREATE INDEX IF NOT EXISTS idx_admin_rel_tenant ON admin_relationships(tenant_id);
|
|
187
|
+
CREATE INDEX IF NOT EXISTS idx_admin_rel_from ON admin_relationships(from_type, from_id);
|
|
188
|
+
CREATE INDEX IF NOT EXISTS idx_admin_rel_to ON admin_relationships(to_type, to_id);
|
|
189
|
+
CREATE INDEX IF NOT EXISTS idx_admin_rel_type ON admin_relationships(relationship_type);
|
|
190
|
+
CREATE INDEX IF NOT EXISTS idx_admin_rel_expires ON admin_relationships(expires_at);
|
|
191
|
+
|
|
192
|
+
-- Unique constraint: prevent duplicate relationships
|
|
193
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_admin_rel_unique
|
|
194
|
+
ON admin_relationships(tenant_id, relationship_type, from_type, from_id, to_type, to_id);
|
|
195
|
+
|
|
196
|
+
-- =============================================================================
|
|
197
|
+
-- admin_policies Table
|
|
198
|
+
-- =============================================================================
|
|
199
|
+
-- Policy definitions combining RBAC/ABAC/ReBAC conditions.
|
|
200
|
+
-- Policies define access rules using role, attribute, and relationship conditions.
|
|
201
|
+
-- =============================================================================
|
|
202
|
+
|
|
203
|
+
CREATE TABLE IF NOT EXISTS admin_policies (
|
|
204
|
+
-- Policy ID (UUID v4)
|
|
205
|
+
id TEXT PRIMARY KEY,
|
|
206
|
+
|
|
207
|
+
-- Multi-tenant support
|
|
208
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
209
|
+
|
|
210
|
+
-- Policy identification
|
|
211
|
+
name TEXT NOT NULL, -- Machine-readable name
|
|
212
|
+
display_name TEXT, -- Human-readable name
|
|
213
|
+
description TEXT,
|
|
214
|
+
|
|
215
|
+
-- Policy effect: allow or deny
|
|
216
|
+
effect TEXT NOT NULL DEFAULT 'allow', -- allow, deny
|
|
217
|
+
|
|
218
|
+
-- Priority (higher = evaluated first, useful for deny policies)
|
|
219
|
+
priority INTEGER DEFAULT 0,
|
|
220
|
+
|
|
221
|
+
-- Resource this policy applies to (supports wildcards)
|
|
222
|
+
-- e.g., "admin:users:*", "admin:settings:security", "admin:*"
|
|
223
|
+
resource_pattern TEXT NOT NULL,
|
|
224
|
+
|
|
225
|
+
-- Actions this policy applies to (supports wildcards)
|
|
226
|
+
-- e.g., ["read", "write"], ["*"]
|
|
227
|
+
actions_json TEXT NOT NULL DEFAULT '["*"]',
|
|
228
|
+
|
|
229
|
+
-- Conditions (JSON object with RBAC/ABAC/ReBAC conditions)
|
|
230
|
+
-- Format:
|
|
231
|
+
-- {
|
|
232
|
+
-- "roles": ["admin", "security_admin"], // RBAC: Any of these roles
|
|
233
|
+
-- "attributes": { // ABAC: Attribute conditions
|
|
234
|
+
-- "department": {"equals": "engineering"},
|
|
235
|
+
-- "clearance_level": {"gte": 3}
|
|
236
|
+
-- },
|
|
237
|
+
-- "relationships": { // ReBAC: Relationship conditions
|
|
238
|
+
-- "manager_of": {"target_type": "admin_user"}
|
|
239
|
+
-- },
|
|
240
|
+
-- "condition_type": "all" // "all" (AND) or "any" (OR)
|
|
241
|
+
-- }
|
|
242
|
+
conditions_json TEXT NOT NULL DEFAULT '{}',
|
|
243
|
+
|
|
244
|
+
-- Whether this policy is active
|
|
245
|
+
is_active INTEGER DEFAULT 1,
|
|
246
|
+
|
|
247
|
+
-- System policy flag (cannot be modified or deleted)
|
|
248
|
+
is_system INTEGER DEFAULT 0,
|
|
249
|
+
|
|
250
|
+
-- Lifecycle
|
|
251
|
+
created_at INTEGER NOT NULL,
|
|
252
|
+
updated_at INTEGER NOT NULL,
|
|
253
|
+
|
|
254
|
+
-- Unique constraint for policy name per tenant
|
|
255
|
+
UNIQUE(tenant_id, name)
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
-- =============================================================================
|
|
259
|
+
-- Indexes for admin_policies
|
|
260
|
+
-- =============================================================================
|
|
261
|
+
|
|
262
|
+
CREATE INDEX IF NOT EXISTS idx_admin_policies_tenant ON admin_policies(tenant_id);
|
|
263
|
+
CREATE INDEX IF NOT EXISTS idx_admin_policies_name ON admin_policies(tenant_id, name);
|
|
264
|
+
CREATE INDEX IF NOT EXISTS idx_admin_policies_resource ON admin_policies(resource_pattern);
|
|
265
|
+
CREATE INDEX IF NOT EXISTS idx_admin_policies_active ON admin_policies(is_active);
|
|
266
|
+
CREATE INDEX IF NOT EXISTS idx_admin_policies_priority ON admin_policies(priority DESC);
|
|
267
|
+
|
|
268
|
+
-- =============================================================================
|
|
269
|
+
-- Default Attributes
|
|
270
|
+
-- =============================================================================
|
|
271
|
+
|
|
272
|
+
-- Department attribute
|
|
273
|
+
INSERT OR IGNORE INTO admin_attributes (
|
|
274
|
+
id, tenant_id, name, display_name, description,
|
|
275
|
+
attribute_type, allowed_values_json, is_required, is_system,
|
|
276
|
+
created_at, updated_at
|
|
277
|
+
) VALUES (
|
|
278
|
+
'attr_department',
|
|
279
|
+
'default',
|
|
280
|
+
'department',
|
|
281
|
+
'Department',
|
|
282
|
+
'The department this admin belongs to',
|
|
283
|
+
'enum',
|
|
284
|
+
'["engineering", "security", "operations", "support", "management"]',
|
|
285
|
+
0,
|
|
286
|
+
1,
|
|
287
|
+
strftime('%s', 'now') * 1000,
|
|
288
|
+
strftime('%s', 'now') * 1000
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
-- Clearance Level attribute
|
|
292
|
+
INSERT OR IGNORE INTO admin_attributes (
|
|
293
|
+
id, tenant_id, name, display_name, description,
|
|
294
|
+
attribute_type, min_value, max_value, is_required, is_system,
|
|
295
|
+
created_at, updated_at
|
|
296
|
+
) VALUES (
|
|
297
|
+
'attr_clearance_level',
|
|
298
|
+
'default',
|
|
299
|
+
'clearance_level',
|
|
300
|
+
'Clearance Level',
|
|
301
|
+
'Security clearance level (1-5, higher = more access)',
|
|
302
|
+
'number',
|
|
303
|
+
1,
|
|
304
|
+
5,
|
|
305
|
+
0,
|
|
306
|
+
1,
|
|
307
|
+
strftime('%s', 'now') * 1000,
|
|
308
|
+
strftime('%s', 'now') * 1000
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
-- Location attribute
|
|
312
|
+
INSERT OR IGNORE INTO admin_attributes (
|
|
313
|
+
id, tenant_id, name, display_name, description,
|
|
314
|
+
attribute_type, is_required, is_system,
|
|
315
|
+
created_at, updated_at
|
|
316
|
+
) VALUES (
|
|
317
|
+
'attr_location',
|
|
318
|
+
'default',
|
|
319
|
+
'location',
|
|
320
|
+
'Location',
|
|
321
|
+
'Physical or regional location of the admin',
|
|
322
|
+
'string',
|
|
323
|
+
0,
|
|
324
|
+
1,
|
|
325
|
+
strftime('%s', 'now') * 1000,
|
|
326
|
+
strftime('%s', 'now') * 1000
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
-- =============================================================================
|
|
330
|
+
-- Migration Complete
|
|
331
|
+
-- =============================================================================
|
|
332
|
+
--
|
|
333
|
+
-- This migration adds ABAC and ReBAC support for Admin users:
|
|
334
|
+
--
|
|
335
|
+
-- ABAC (Attribute-Based):
|
|
336
|
+
-- - admin_attributes: Define attribute types (department, clearance_level, etc.)
|
|
337
|
+
-- - admin_attribute_values: Assign values to Admin users
|
|
338
|
+
--
|
|
339
|
+
-- ReBAC (Relationship-Based):
|
|
340
|
+
-- - admin_relationships: Define relationships (manager_of, delegate_of, etc.)
|
|
341
|
+
--
|
|
342
|
+
-- Combined Policies:
|
|
343
|
+
-- - admin_policies: Define access rules using RBAC + ABAC + ReBAC conditions
|
|
344
|
+
--
|
|
345
|
+
-- =============================================================================
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
-- =============================================================================
|
|
2
|
+
-- Migration: Admin Setup Tokens (D1_ADMIN)
|
|
3
|
+
-- =============================================================================
|
|
4
|
+
-- Created: 2025-01-25
|
|
5
|
+
-- Description: Creates admin_setup_tokens table for secure Admin UI passkey
|
|
6
|
+
-- registration during initial setup.
|
|
7
|
+
--
|
|
8
|
+
-- IMPORTANT: This migration is for D1_ADMIN (dedicated Admin database).
|
|
9
|
+
--
|
|
10
|
+
-- Use Case:
|
|
11
|
+
-- - After initial setup on Router, redirect to Admin UI with a setup token
|
|
12
|
+
-- - Admin UI verifies the token and allows passkey registration
|
|
13
|
+
-- - Token is single-use and time-limited for security
|
|
14
|
+
-- =============================================================================
|
|
15
|
+
|
|
16
|
+
-- =============================================================================
|
|
17
|
+
-- admin_setup_tokens Table
|
|
18
|
+
-- =============================================================================
|
|
19
|
+
-- Stores one-time setup tokens for Admin UI passkey registration.
|
|
20
|
+
-- These tokens allow secure passkey registration after initial setup.
|
|
21
|
+
--
|
|
22
|
+
-- Lifecycle:
|
|
23
|
+
-- 1. Created during initial setup (or via CLI for recovery)
|
|
24
|
+
-- 2. Used when admin visits Admin UI /setup/complete?token=xxx
|
|
25
|
+
-- 3. Invalidated after successful passkey registration
|
|
26
|
+
-- 4. Auto-expires after 24 hours
|
|
27
|
+
-- =============================================================================
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS admin_setup_tokens (
|
|
30
|
+
-- Token ID (the actual token value, UUID v4)
|
|
31
|
+
id TEXT PRIMARY KEY,
|
|
32
|
+
|
|
33
|
+
-- Multi-tenant support
|
|
34
|
+
tenant_id TEXT NOT NULL DEFAULT 'default',
|
|
35
|
+
|
|
36
|
+
-- Reference to admin user
|
|
37
|
+
admin_user_id TEXT NOT NULL REFERENCES admin_users(id) ON DELETE CASCADE,
|
|
38
|
+
|
|
39
|
+
-- Token status
|
|
40
|
+
-- pending: Created, waiting for use
|
|
41
|
+
-- used: Successfully used for passkey registration
|
|
42
|
+
-- expired: Expired without use
|
|
43
|
+
-- revoked: Manually revoked
|
|
44
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
45
|
+
|
|
46
|
+
-- Expiration (UNIX timestamp in milliseconds)
|
|
47
|
+
expires_at INTEGER NOT NULL,
|
|
48
|
+
|
|
49
|
+
-- Usage tracking
|
|
50
|
+
used_at INTEGER, -- When the token was used
|
|
51
|
+
used_ip TEXT, -- IP address that used the token
|
|
52
|
+
|
|
53
|
+
-- Audit fields
|
|
54
|
+
created_at INTEGER NOT NULL,
|
|
55
|
+
created_by TEXT -- 'initial_setup' | 'cli' | admin_user_id
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
-- =============================================================================
|
|
59
|
+
-- Indexes for admin_setup_tokens
|
|
60
|
+
-- =============================================================================
|
|
61
|
+
|
|
62
|
+
-- User's tokens lookup (for checking existing tokens)
|
|
63
|
+
CREATE INDEX IF NOT EXISTS idx_admin_setup_tokens_user ON admin_setup_tokens(admin_user_id);
|
|
64
|
+
|
|
65
|
+
-- Tenant-scoped lookup
|
|
66
|
+
CREATE INDEX IF NOT EXISTS idx_admin_setup_tokens_tenant ON admin_setup_tokens(tenant_id);
|
|
67
|
+
|
|
68
|
+
-- Status filter (for cleanup jobs)
|
|
69
|
+
CREATE INDEX IF NOT EXISTS idx_admin_setup_tokens_status ON admin_setup_tokens(status);
|
|
70
|
+
|
|
71
|
+
-- Expiration lookup (for cleanup jobs)
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_admin_setup_tokens_expires ON admin_setup_tokens(expires_at);
|
|
73
|
+
|
|
74
|
+
-- =============================================================================
|
|
75
|
+
-- admin_users: Add passkey_setup_completed column
|
|
76
|
+
-- =============================================================================
|
|
77
|
+
-- Track whether the admin user has completed passkey setup on Admin UI.
|
|
78
|
+
-- This is separate from having passkeys - it tracks the initial setup flow.
|
|
79
|
+
-- =============================================================================
|
|
80
|
+
|
|
81
|
+
ALTER TABLE admin_users ADD COLUMN passkey_setup_completed INTEGER DEFAULT 0;
|
|
82
|
+
|
|
83
|
+
-- =============================================================================
|
|
84
|
+
-- Migration Complete
|
|
85
|
+
-- =============================================================================
|
|
86
|
+
-- Usage:
|
|
87
|
+
-- 1. Router creates token during initial setup
|
|
88
|
+
-- 2. Admin visits Admin UI with token
|
|
89
|
+
-- 3. Admin UI verifies token and registers passkey
|
|
90
|
+
-- 4. Token is marked as 'used' and passkey_setup_completed is set to 1
|
|
91
|
+
-- =============================================================================
|