wiki/appdoc/doc_userauth_process_concept_review.md
2025-12-29 23:54:13 +01:00

334 lines
13 KiB
Markdown

# Critical Review: User Authentication Process Concept
## Issues Found
### 1. **CRITICAL: Data Model Inconsistency**
**Location**: Line 277 in concept document
**Issue**: `resetTokenExpires` is shown as `Optional[str]` but should be `Optional[float]`
```python
# WRONG (line 277):
resetTokenExpires: Optional[str] = Field(None, description="Reset token expiration (ISO datetime)")
# CORRECT:
resetTokenExpires: Optional[float] = Field(None, description="Reset token expiration (UTC timestamp in seconds)")
```
**Impact**: Implementation confusion, type errors
### 2. **CRITICAL: Config Value Inconsistency**
**Location**: Line 429 in concept document
**Issue**: Config shows `48` hours but requirement is `24` hours
```ini
# WRONG (line 429):
Auth_RESET_TOKEN_EXPIRY_HOURS = 48
# CORRECT:
Auth_RESET_TOKEN_EXPIRY_HOURS = 24
```
**Impact**: Wrong expiration time in implementation
### 3. **SECURITY: Missing Rate Limiting**
**Issue**: Password reset request endpoint needs stricter rate limiting than registration
**Current**: Registration has `@limiter.limit("10/minute")`
**Needed**: Password reset request should have stricter limits to prevent:
- Email enumeration attacks
- Spam/DoS attacks
- Brute force attempts
**Recommendation**:
- Password reset request: `@limiter.limit("5/minute")` or `@limiter.limit("3/minute")`
- Password reset (token usage): `@limiter.limit("10/minute")` (less critical, token is single-use)
### 4. **SECURITY: Token Invalidation Strategy** ✅ CLARIFIED
**Issue**: What happens when user requests password reset multiple times?
**Current**: Concept doesn't specify behavior
**Clarification**:
- Token is stored in the `UserInDB` record (single field: `resetToken`)
- When new reset token is generated, **old token is overwritten** in the database
- **No risk**: Only one token can exist per user at any time (the last one generated)
- The old token is automatically invalidated because it no longer exists in the database
**Status**: ✅ No risk - token overwriting ensures only one valid token exists
### 5. **SECURITY: Token Reuse Prevention** ✅ CLARIFIED
**Issue**: What prevents token from being used multiple times?
**Current**: Concept says "Tokens are single-use (cleared after password reset)" but doesn't specify validation
**Clarification**:
- Token is **cleared immediately after successful password reset** (atomic operation)
- Once cleared, token no longer exists in database
- **No risk**: If token is used again, validation will fail because token doesn't exist
- Token reuse is prevented by the fact that token is removed from database after use
**Status**: ✅ No risk - token clearing after use prevents reuse automatically
### 6. **SECURITY: Email Case Sensitivity**
**Issue**: Email uniqueness check - are emails case-sensitive?
**Current**: Concept doesn't specify
**Risk**:
- `User@Example.com` and `user@example.com` could be treated as different
- Email enumeration could reveal accounts
**Recommendation**:
- Normalize emails to lowercase before storage and comparison
- Use `email.lower().strip()` in all email operations
- Document this in the concept
### 7. **SECURITY: Email Enumeration Prevention** ✅ APPROACH SELECTED
**Issue**: Registration endpoint reveals if email exists
**Current**: Registration rejects if email exists → reveals email is registered
**Risk**: Attacker can enumerate registered emails
**Selected Approach**:
-**If email exists for LOCAL auth user**: Send password reset email to existing user, don't create duplicate account
-**Return generic success message**: "Registration successful. Please check your email to set your password."
-**Don't reveal**: Whether email already existed or new account was created
- This prevents email enumeration while providing good UX
**Status**: ✅ Approach selected - send reset email to existing user if email exists
### 8. **EDGE CASE: Multiple Reset Requests** ✅ CLARIFIED
**Issue**: User requests reset multiple times before using first token
**Current**: Concept doesn't specify behavior
**Clarification**:
- Token is stored in `UserInDB` record (single field)
- **Only one token can exist at a time** - the last one generated
- When new reset request comes in, **old token is overwritten** in database
- **Only the last token is valid** - previous tokens are automatically invalidated
- No special handling needed - database structure ensures single token
**Status**: ✅ No risk - database structure prevents multiple tokens
### 9. **EDGE CASE: User State Changes During Reset**
**Issue**: What happens if user state changes while reset token is active?
**Scenarios**:
- User is disabled (`enabled=False`) while reset token is active
- User changes email while reset token is active
- User account is deleted while reset token is active
- User sets password via admin while reset token is active
**Recommendation**:
- On password reset, check user still exists and is enabled
- If user is disabled, allow reset but keep `enabled=False` (admin must activate)
- If email changed, token should still work (token is tied to user, not email)
- If user deleted, token validation should fail (user not found)
### 10. **EDGE CASE: Expired Token Cleanup** ✅ APPROACH SELECTED
**Issue**: Expired tokens remain in database indefinitely
**Current**: Concept doesn't mention cleanup
**Risk**: Database bloat, potential security issues
**Selected Approach**:
-**Check token expiration during user authentication** (on each login attempt)
-**Clear expired token if found** during authentication check
-**Also check during token validation** (password reset endpoint) and clear if expired
-**Simplest approach**: No separate cleanup job needed, tokens cleaned on access
- This ensures expired tokens are cleaned automatically without additional jobs
**Status**: ✅ Approach selected - check and clean expired tokens during auth/validation
### 11. **IMPLEMENTATION: Cross-Mandate Search**
**Issue**: How exactly to search across all mandates?
**Current**: Concept says "use root interface" but doesn't specify implementation
**Questions**:
- Does `getRecordsetWithRBAC` work with root interface?
- Should we bypass RBAC for this search?
- How to ensure we search ALL mandates?
**Recommendation**:
- Use root interface with `mandateId=None` or empty filter
- Use direct database query if RBAC filtering interferes
- Document exact implementation approach
### 12. **IMPLEMENTATION: Email Search Method**
**Issue**: No existing method to find user by email across mandates
**Current**: Concept mentions `findUserByEmailLocalAuth()` but doesn't specify how it works
**Questions**:
- Does database support case-insensitive email search?
- Should we use exact match or LIKE?
- How to handle NULL emails?
**Recommendation**:
- Implement method that:
1. Uses root interface
2. Searches with `recordFilter={"email": email.lower(), "authenticationAuthority": AuthAuthority.LOCAL}`
3. Returns first match or None
4. Handles NULL emails gracefully
### 13. **USER EXPERIENCE: Email Delivery Failure** ✅ MESSAGE TO ADD
**Issue**: What if user never receives email?
**Current**: Concept doesn't address this
**Scenarios**:
- Email goes to spam
- Email server is down
- User enters wrong email
- Email delivery is delayed
**Selected Approach**:
-**Show message about spam folder**: "If you don't receive an email within 5 minutes, please check your spam folder"
- ✅ Display this message after registration and password reset request
- Future enhancement: Consider "Resend email" functionality (with rate limiting)
**Status**: ✅ Message to add - show spam folder reminder
### 14. **USER EXPERIENCE: Password Reset After Registration** ✅ NO SPECIAL HANDLING
**Issue**: User registers, sets password, then immediately forgets it
**Current**: User must use password reset flow
**Decision**:
-**No special handling required** - use standard password reset flow
- ✅ User can request password reset like any other user
- ✅ Same token expiration (24 hours) applies to all reset tokens
**Status**: ✅ No special handling needed
### 15. **MISSING: Token Validation Order**
**Issue**: Order of validation checks not specified
**Current**: Concept lists validations but not order
**Risk**: Inefficient validation, potential security issues
**Recommendation**:
- Validate in this order:
1. Token format (UUID format check)
2. Token exists in database
3. User exists and is not deleted
4. Token matches user's resetToken
5. Token not expired (compare timestamps)
6. Password strength
7. Set password and clear token (atomic operation)
### 16. **MISSING: Atomic Operations** ✅ CONFIRMED
**Issue**: Password reset involves multiple database operations
**Current**: Concept doesn't specify transaction handling
**Risk**:
- Partial updates if operation fails
- Token cleared but password not set
- Race conditions
**Confirmation**:
-**Use database transaction** for password reset operation
-**Atomic operation** ensures all-or-nothing:
- Setting passwordHash
- Clearing resetToken and resetTokenExpires
- Setting enabled=True
- ✅ All operations succeed or all fail together
**Status**: ✅ Confirmed - atomic operations required
### 17. **MISSING: Audit Logging**
**Issue**: No mention of audit logging for security events
**Current**: Concept doesn't specify logging
**Risk**: No audit trail for security incidents
**Recommendation**:
- Log all password reset requests (with email hash for privacy)
- Log successful password resets
- Log failed token validations
- Log token generation events
### 18. **MISSING: Error Messages**
**Issue**: Error messages could reveal too much information
**Current**: Some error messages are specified, but not all
**Risk**: Information leakage
**Recommendation**:
- Use generic error messages:
- "Invalid or expired reset token" (don't specify which)
- "Registration failed" (don't specify why)
- "Password reset request processed" (always same message)
- Log detailed errors server-side only
### 19. **MISSING: Frontend Token Validation**
**Issue**: Frontend should validate token format before API call
**Current**: Concept doesn't specify frontend validation
**Risk**: Unnecessary API calls, poor UX
**Recommendation**:
- Validate UUID format in frontend before calling API
- Show error immediately if token format is invalid
- Extract token from URL and validate on page load
### 20. **MISSING: Magic Link Base URL** ✅ LOCATION SPECIFIED
**Issue**: Magic link generation needs frontend base URL
**Current**: Concept mentions "Should use frontend base URL from config" but doesn't specify
**Selected Approach**:
-**Add frontend URL to frontend env files**: `frontend_agents/public/config/env_*.env`
-**Files to update**:
- `env_int.env` - Integration environment URL
- `env_prod.env` - Production environment URL
- (Add `env_dev.env` if exists)
-**Variable name**: `APP_FRONTEND_URL` or `Frontend_BASE_URL`
-**Usage**: Backend reads from frontend config or gets from request origin
-**Environment-specific**: Each env file has its own URL
**Status**: ✅ Location specified - add to frontend env files
## Recommendations Summary
### High Priority (Security & Correctness)
1. ✅ Fix data model inconsistency (resetTokenExpires type)
2. ✅ Fix config value (24 hours, not 48)
3. ✅ Add rate limiting to password reset endpoints
4. ✅ Implement token invalidation on new reset request
5. ✅ Normalize emails to lowercase
6. ✅ Prevent token reuse (clear immediately after use)
7. ✅ Add atomic transaction for password reset
### Medium Priority (Edge Cases)
8. ✅ Handle user state changes during reset
9. ✅ Implement expired token cleanup
10. ✅ Add email delivery failure handling
11. ✅ Specify cross-mandate search implementation
12. ✅ Add audit logging
### Low Priority (UX & Polish)
13. ✅ Add frontend token validation
14. ✅ Specify magic link base URL configuration
15. ✅ Improve error messages (generic, secure)
16. ✅ Add resend email functionality (future enhancement)
## Security Checklist
- [ ] Rate limiting on all endpoints
- [ ] Token invalidation strategy implemented
- [ ] Token reuse prevention
- [ ] Email normalization (lowercase)
- [ ] Email enumeration prevention
- [ ] Atomic database operations
- [ ] Audit logging
- [ ] Generic error messages
- [ ] Token expiration validation
- [ ] User state validation during reset
- [ ] Cross-mandate search security (RBAC bypass only for root operations)
## Testing Checklist (Additional)
- [ ] Multiple reset requests (old token invalidated)
- [ ] Token reuse attempt (should fail)
- [ ] Expired token usage (should fail)
- [ ] User disabled during reset (should handle gracefully)
- [ ] Email case variations (User@Example.com vs user@example.com)
- [ ] Concurrent reset requests (race condition handling)
- [ ] Email delivery failure scenarios
- [ ] Invalid token format handling
- [ ] Cross-mandate email search accuracy
- [ ] Atomic operation rollback on failure