apache / apache/infrastructure-asfquart
OAuth Authentication Decisions Not Logged
- Dominant language
- Python
- Stars
- 7
- Forks
- 12
- PR merge metrics
- No merged PRs in 30d
Description
## Issue: FINDING-135 - OAuth Authentication Decisions Not Logged
**Labels:** bug, security, priority:medium, asvs-level:L1
**ASVS Level(s):** [L1]
**Description:**
### Summary
The OAuth authentication callback handler (`/auth` endpoint) makes critical authentication decisions but does not log any of them. Both successful logins and failures (invalid/expired state, OAuth provider rejection) occur silently. OAuth is the primary web authentication mechanism, making this a significant gap. The code validates state tokens, calls OAuth providers, and creates sessions without any audit trail, preventing detection of state token brute-force, replay attacks, or compromised accounts.
### Details
Affected locations:
- `src/asfquart/generics.py` lines 83-109: OAuth callback without logging
- `src/asfquart/generics.py` lines 52-115: Authentication flow without audit
The OAuth callback performs authentication but never logs success or failure, creating complete gap in audit trail for primary web authentication mechanism.
### Recommended Remediation
Implement an after_request hook to capture OAuth authentication decisions. In `atr/server.py`, add `@app.after_request` handler that checks if `request.path == '/auth'` and logs `oauth_login_success` (status 200 with uid) or `oauth_login_failure` (status 403):
```python
@app.after_request
async def log_oauth_decisions(response: quart.Response) -> quart.Response:
"""Log OAuth authentication decisions for audit trail."""
if quart.request.path == '/auth':
if response.status_code == 200:
# Successful login - extract uid from session
session_data = await asfquart.session.read()
log.info('oauth_login_success', extra={
'asf_uid': session_data.get('uid'),
'remote_addr': quart.request.remote_addr
})
elif response.status_code in (403, 401):
# Failed login
log.warning('oauth_login_failure', extra={
'state_token': quart.request.args.get('state', '')[:8] + '...', # Truncated
'remote_addr': quart.request.remote_addr,
'status': response.status_code
})
return response
```
Include `asf_uid` for success cases and failure reason for rejection cases.
### Acceptance Criteria
- [ ] OAuth authentication success is logged
- [ ] OAuth authentication failure is logged
- [ ] Log entries include user identity and remote address
- [ ] Audit trail is complete for OAuth flow
- [ ] Test cases verify OAuth logging
- [ ] Unit test verifying the fix
### References
- Source reports: L1:7.2.2.md
- Related findings: FINDING-134, FINDING-136, FINDING-250
- ASVS sections: 7.2.2
### Priority
Medium
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.