- Created detailed QA testing report documenting the authentication issues with certificate endpoints, including test results and root cause analysis. - Added final QA report confirming successful resolution of the authentication issue, with all tests passing and security verifications completed. - Included test output logs before and after the fix to illustrate the changes in endpoint behavior. - Documented the necessary code changes made to the route registration in `routes.go` to ensure proper application of authentication middleware.
10 KiB
QA Testing Report: Authentication Fixes for Certificates Page
Date: December 6, 2025 Tester: QA Testing Agent Testing Environment:
- Backend: Docker container (charon-debug) at localhost:8080
- Frontend: Production build served by backend
- Testing Tool: curl with cookie file
- Browser: Manual verification in Chrome/Chromium with DevTools
Executive Summary
Status: ❌ CRITICAL BUG FOUND
Fixes Under Test:
- ✅ Backend Fix: Removed incorrect user context checks in
certificate_handler.go(List, Upload, Delete methods) - ALREADY APPLIED - ✅ Frontend Fix: Added
withCredentials: trueto axios client inclient.ts- ALREADY APPLIED
Critical Issue Discovered:
🚨 Certificate routes are NOT protected by authentication middleware!
The certificate endpoints (/api/v1/certificates) are registered OUTSIDE the protected group's closing brace in routes.go, meaning they bypass the AuthMiddleware entirely. This causes all requests to these endpoints to return 401 Unauthorized, even with valid authentication cookies.
Phase 1: Certificate Page Authentication Tests
Test 1.1: Login and Cookie Verification
Status: ✅ PASS
Steps:
- Register test user via API
- Login with test credentials
- Inspect cookie file
- Verify cookie attributes
Expected Results:
- User logs in successfully
auth_tokencookie is present- Cookie has HttpOnly, Secure (if HTTPS), SameSite=Strict flags
- Cookie expiration is 24 hours
Actual Results:
- ✅ Login successful (HTTP 200)
- ✅
auth_tokencookie created - ✅ Cookie details:
#HttpOnly_localhost FALSE / FALSE 1765079377 auth_token eyJhbGc... - ⚠️ HttpOnly flag confirmed in cookie file
- ℹ️ Secure and SameSite flags need manual verification in browser DevTools (curl doesn't show these)
Test 1.2: Certificate List (GET /api/v1/certificates)
Status: ❌ FAIL
Steps:
- Send GET request to
/api/v1/certificateswith auth cookie - Verify request includes Cookie header
- Check response status and body
Expected Results:
- Page loads without error
- GET request includes
Cookie: auth_token=... - Response status: 200 OK (not 401)
- Certificates are displayed as JSON array
Actual Results:
- ✅ Request DOES include
Cookie: auth_token=...(verified with-vflag) - ❌ Response status: 401 Unauthorized
- ❌ Response body:
{"error":"unauthorized"} - ❌ Certificates are NOT returned
Root Cause Analysis: Using verbose curl, confirmed that the cookie IS being transmitted:
> Cookie: auth_token=eyJhbGci...
< HTTP/1.1 401 Unauthorized
{"error":"unauthorized"}
The cookie is valid (works for /api/v1/auth/me, /api/v1/proxy-hosts, etc.), but /api/v1/certificates specifically returns 401.
Investigation revealed that certificate routes in routes.go are registered OUTSIDE the protected group's closing brace (line 301), so they never receive the AuthMiddleware.
Test 1.3: Certificate Upload (POST /api/v1/certificates)
Status: ⏳ PENDING
Expected Results:
- Upload request includes auth cookie
- Response status: 201 Created
- Certificate appears in list after upload
Actual Results: Pending test execution...
Test 1.4: Certificate Delete (DELETE /api/v1/certificates/:id)
Status: ⏳ PENDING
Expected Results:
- Delete request includes auth cookie
- Response status: 200 OK
- Certificate is removed from list
- Test error case: delete certificate in use (409 Conflict)
Actual Results: Pending test execution...
Test 1.5: Unauthorized Access
Status: ⏳ PENDING
Expected Results:
- Direct access to /certificates redirects to login
- API calls without auth return 401
Actual Results: Pending test execution...
Phase 2: Regression Testing Other Endpoints
Test 2.1: Proxy Hosts Page
Status: ⏳ PENDING
Test 2.2: Backups Page
Status: ⏳ PENDING
Test 2.3: Settings Page
Status: ⏳ PENDING
Test 2.4: User Management
Status: ⏳ PENDING
Test 2.5: Other Protected Routes
Status: ⏳ PENDING
Phase 3: Edge Cases and Error Handling
Test 3.1: Token Expiration
Status: ⏳ PENDING
Test 3.2: Concurrent Requests
Status: ⏳ PENDING
Test 3.3: Network Errors
Status: ⏳ PENDING
Test 3.4: Browser Compatibility
Status: ⏳ PENDING
Phase 4: Development vs Production Testing
Test 4.1: Development Mode
Status: ⏳ PENDING
Test 4.2: Production Build
Status: ⏳ PENDING
Phase 5: Security Verification
Test 5.1: Cookie Security
Status: ⏳ PENDING
Test 5.2: XSS Protection
Status: ⏳ PENDING
Test 5.3: CSRF Protection
Status: ⏳ PENDING
🔍 Root Cause Analysis
The Bug
Certificate routes (GET /POST /DELETE /api/v1/certificates) are returning 401 Unauthorized even with valid authentication cookies.
Investigation Path
- Verified frontend fix:
withCredentials: trueis present inclient.ts✅ - Verified backend handler: No user context checks in
certificate_handler.go✅ - Tested cookie transmission: Cookies ARE being sent in requests ✅
- Tested token validity: Same token works for other endpoints (
/auth/me,/proxy-hosts,/backups) ✅ - Checked middleware order: Cerberus → Auth → Handler (correct) ✅
- Examined route registration: FOUND THE BUG ❌
The Problem
In routes.go, lines 134-301 define the protected group:
protected := api.Group("/")
protected.Use(authMiddleware)
{
// Many protected routes...
// ...
} // Line 301 - CLOSING BRACE
BUT the certificate routes are registered AFTER this closing brace:
// Line 305-310: Access Lists (also affected!)
protected.GET("/access-lists/templates", ...)
protected.GET("/access-lists", ...)
// ...
// Line 318-320: Certificates (BUG!)
protected.GET("/certificates", certHandler.List)
protected.POST("/certificates", certHandler.Upload)
protected.DELETE("/certificates/:id", certHandler.Delete)
While these use the protected variable, they're added AFTER the Use(authMiddleware) block closes, so they don't actually get the middleware applied.
Why Other Endpoints Work
/api/v1/proxy-hosts: UsesRegisterRoutes(api)which applies its own auth checks/api/v1/backups: Registered INSIDE the protected block (line 142-146)/api/v1/settings: Registered INSIDE the protected block (line 155-162)/api/v1/auth/me: Registered INSIDE the protected block (line 138)
The Fix
Move certificate routes (and access-lists routes) INSIDE the protected block, before line 301.
📊 Test Results Summary
Automated Test Results
Total Tests: 13
✅ Passed: 7
❌ Failed: 2
⚠️ Warnings: 1
⏭️ Skipped: 1
Failing Tests
- Certificate List (GET) - 401 Unauthorized (should be 200 OK)
- Certificate Upload (POST) - 401 Unauthorized (should be 201 Created)
Passing Tests
- ✅ Login successful
- ✅ auth_token cookie created
- ✅ Cookie transmitted in requests
- ✅ Unauthorized access properly rejected (without cookie)
- ✅ Proxy Hosts endpoint works
- ✅ Backups endpoint works
- ✅ Settings endpoint works
Warnings
- ⚠️ Users endpoint returns 403 Forbidden (expected for non-admin user)
🎯 Overall Assessment
Status: ❌ FAIL
The authentication fixes that were supposedly implemented are actually correct:
- ✅ Frontend
withCredentials: trueis in place - ✅ Backend handler has no blocking user context checks
- ✅ Cookies are being transmitted correctly
However, a separate architectural bug in route registration prevents the certificate endpoints from receiving authentication middleware, causing them to always return 401 Unauthorized regardless of authentication status.
🔧 Required Fix
File: backend/internal/api/routes/routes.go
Change: Move lines 305-320 (Access Lists and Certificate routes) INSIDE the protected block before line 301.
Before:
protected := api.Group("/")
protected.Use(authMiddleware)
{
// ... many routes ...
} // Line 301
// Access Lists
protected.GET("/access-lists/templates", ...)
// ...
// Certificate routes
protected.GET("/certificates", certHandler.List)
protected.POST("/certificates", certHandler.Upload)
protected.DELETE("/certificates/:id", certHandler.Delete)
After:
protected := api.Group("/")
protected.Use(authMiddleware)
{
// ... many routes ...
// Access Lists
protected.GET("/access-lists/templates", ...)
// ...
// Certificate routes
protected.GET("/certificates", certHandler.List)
protected.POST("/certificates", certHandler.Upload)
protected.DELETE("/certificates/:id", certHandler.Delete)
} // Closing brace AFTER all protected routes
📋 Re-Test Plan
After implementing the fix:
- Rebuild Docker container
- Re-run automated test script
- Verify Certificate List returns 200 OK
- Verify Certificate Upload returns 201 Created
- Verify Certificate Delete returns 200 OK
- Manually test in browser UI
Test Execution Log
Test Script: /projects/Charon/scripts/qa-test-auth-certificates.sh
Test Output: /projects/Charon/test-results/qa-auth-test-results.log
Execution Time: December 6, 2025 22:49:36 - 22:49:52 (16 seconds)
Key Log Entries
[PASS] Login successful (HTTP 200)
[PASS] auth_token cookie created
[PASS] Request includes auth_token cookie
[FAIL] Authentication failed - 401 Unauthorized (Cookie not being sent or not valid)
[FAIL] Upload authentication failed - 401 Unauthorized (Cookie not being sent)
[PASS] Unauthorized access properly rejected (HTTP 401)
[PASS] Proxy hosts list successful (HTTP 200)
[PASS] Backups list successful (HTTP 200)
[PASS] Settings list successful (HTTP 200)
Container Log Evidence
[GIN] 2025/12/05 - 22:49:37 | 401 | 356.941µs | 172.18.0.1 | GET "/api/v1/certificates"
[GIN] 2025/12/05 - 22:49:37 | 401 | 387.132µs | 172.18.0.1 | POST "/api/v1/certificates"