Skip to content

feat(accounts): require valid IA S3 keys on OTP service endpoints#12841

Open
mekarpeles wants to merge 4 commits into
masterfrom
12840/otp-require-s3-auth
Open

feat(accounts): require valid IA S3 keys on OTP service endpoints#12841
mekarpeles wants to merge 4 commits into
masterfrom
12840/otp-require-s3-auth

Conversation

@mekarpeles
Copy link
Copy Markdown
Member

Summary

Closes #12840

The OTP service endpoints (POST /account/otp/issue and /account/otp/redeem) are used by Lenny to implement patron passwordless login. Lenny already sends Authorization: LOW <access>:<secret> headers on every OTP call (via ol_auth_headers()), but OL was silently ignoring them.

This PR adds validation: both endpoints now require a valid IA S3 Authorization: LOW header before processing the request. Invalid or missing credentials return {"error": "unauthorized"}.

Changes

openlibrary/plugins/upstream/account.py

  • New module-level _parse_low_auth_header() helper — parses Authorization: LOW access:secret from the WSGI env (same pattern as the existing account_anonymize._parse_auth_header() instance method)
  • otp_service_issue.POST() — validate S3 keys via InternetArchiveAccount.s3auth() before issuing OTP
  • otp_service_redeem.POST() — same validation before redeeming OTP

Why This Matters

Without this, any HTTP client can hit /account/otp/issue and cause OL to send unsolicited OTP emails to arbitrary addresses. Requiring valid IA S3 keys ties OTP access to Lenny instances that have been explicitly linked to an IA account via make ol-login.

Companion PR

Test Plan

  • Request without Authorization header → {"error": "missing_or_invalid_authorization"}
  • Request with invalid S3 keys → {"error": "unauthorized"}
  • Request with valid S3 keys → OTP issued/redeemed normally
  • Local dev: fake S3 auth endpoint (/internal/fake/s3auth) accepts foo:foo, so existing local tests are unaffected
  • make test passes

Adds Authorization: LOW <access>:<secret> validation to
/account/otp/issue and /account/otp/redeem. Callers (Lenny instances)
must supply valid IA S3 credentials — validated via s3auth — before
OTP emails are issued or redeemed.

Lenny already sends ol_auth_headers() with every OTP request; OL was
previously ignoring them. This closes the gap so only Lenny nodes
that have been configured with a linked IA/OL account can trigger OTP
emails.

Closes #12840
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens access control for the legacy web.py OTP service endpoints (POST /account/otp/issue and POST /account/otp/redeem) by requiring callers to present valid IA S3 credentials via an Authorization: LOW access:secret header (intended to restrict OTP issuance/redemption to authorized Lenny instances).

Changes:

  • Adds a module-level _parse_low_auth_header() helper to parse the Authorization: LOW ... header.
  • Validates parsed credentials via InternetArchiveAccount.s3auth() at the start of both OTP endpoints.
  • Returns JSON error payloads for missing/malformed auth headers and invalid credentials.

Comment thread openlibrary/plugins/upstream/account.py Outdated
Comment thread openlibrary/plugins/upstream/account.py Outdated
Comment thread openlibrary/plugins/upstream/account.py Outdated
Comment thread openlibrary/plugins/upstream/account.py Outdated
Comment thread openlibrary/plugins/upstream/account.py Outdated
…outages; add tests

- _parse_low_auth_header(): strip both parts and raise ValueError if
  either is empty (catches 'LOW access:' or 'LOW :secret')
- Extract _require_s3_auth() helper used by both OTP handlers; returns
  a distinct error when s3auth responds with a 5xx (auth_service_unavailable)
  vs invalid credentials (unauthorized)
- Add TestOtpServiceS3Auth: tests for missing header, empty secret,
  invalid keys, 5xx outage, and valid keys proceeding to OTP issue/redeem

Addresses Copilot review threads on #12841
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(accounts): Validate caller IA S3 keys on OTP service endpoints to restrict access to authorized Lenny instances

2 participants