feat(auth): optional IA S3 auth plugin for patron borrow requests#184
feat(auth): optional IA S3 auth plugin for patron borrow requests#184mekarpeles wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an opt-in Internet Archive (IA) patron authentication path for the borrow endpoint, allowing logged-out patrons to authenticate using IA S3 keys via an Authorization: LOW <access>:<secret> header and receive a Lenny session cookie, bypassing the OTP flow when enabled.
Changes:
- Introduces
IA_AUTH_ENABLEDconfiguration flag (default disabled) to gate the new behavior. - Adds
verify_ia_s3_keys()to validate IA S3 credentials againstarchive.org/services/xauthn/?op=s3authand derive a patron identity. - Updates
borrow_item()to acceptLOWcredentials when enabled, borrow the item, and set a session cookie on success.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
lenny/routes/api.py |
Adds the IA LOW Authorization-header borrow path and sets a session cookie on successful IA auth. |
lenny/core/auth.py |
Adds async IA S3 key verification via the IA xauthn endpoint. |
lenny/configs/__init__.py |
Adds IA_AUTH_ENABLED env flag and exports it from the configs module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…add tests - borrow_item(): split on any whitespace and compare scheme case-insensitively to handle 'low', 'Low', or tabs/extra spaces between scheme and keys - borrow_item(): validate both access and secret are non-empty after stripping - borrow_item(): pass client IP to create_session_cookie() so IA-auth sessions are IP-bound, matching the OTP session cookie behaviour - tests/test_auth.py: TestVerifyIaS3Keys with mocked httpx — success, screenname fallback, non-200, missing success field, network error - tests/test_direct_auth_mock.py: four tests for IA_AUTH_ENABLED paths — disabled flag, valid keys create loan+cookie, invalid falls through, lowercase scheme Addresses Copilot review threads on #184
017206f to
1a7952d
Compare
|
@copilot review |
Reviewed. Code review and CodeQL security scan both pass with no issues. One small follow-up was included in the latest commit: the two IA-auth tests that exercise the valid-key path now mock |
Adds an opt-in IA_AUTH_ENABLED flag (default: false). When enabled, borrow requests may authenticate via Authorization: LOW access:secret headers, bypassing the OTP flow. Only Lenny instances that explicitly set IA_AUTH_ENABLED=true use this path. Changes: - configs/__init__.py: add IA_AUTH_ENABLED env var - core/auth.py: add verify_ia_s3_keys() — validates S3 keys using internetarchive.get_session() against s3.us.archive.org?check_auth=1 (same library as ol_bootstrap.py; wrapped in asyncio.to_thread so the event loop is not blocked) - routes/api.py: in borrow_item(), before the OTP flow, check for a LOW auth header (case-insensitive, any whitespace); validate both parts non-empty; call verify_ia_s3_keys(); create an IP-bound session cookie on success - tests/test_auth.py: TestVerifyIaS3Keys — mocks internetarchive.get_session, covers authorized/unauthorized/non-200/error/screenname-fallback cases - tests/test_direct_auth_mock.py: four borrow_item tests via monkeypatch + AsyncMock — disabled flag ignores header, valid keys create loan+cookie, invalid keys fall through to 401, lowercase scheme accepted Closes #183
a12716d to
5102271
Compare
|
This feature is added in #185 |
Summary
Closes #183
Adds an optional IA auth plugin that allows a logged-out patron to borrow a book by supplying their Internet Archive S3 credentials as an
Authorization: LOW <access>:<secret>HTTP header. When valid, Lenny creates the loan and sets a session cookie — bypassing the OTP flow entirely.Opt-in: only Lenny instances that set
IA_AUTH_ENABLED=truein their environment will use this plugin. All other instances are unaffected.Changes
lenny/configs/__init__.pyIA_AUTH_ENABLEDenv var (defaultfalse)lenny/core/auth.pyverify_ia_s3_keys(access, secret) -> Optional[str]— validates credentials usinginternetarchive.get_session()againsthttps://s3.us.archive.org?check_auth=1(the same auth stack as theiaCLI; no privileged access required). Returns{username}@archive.orgorNone. The blocking network call is offloaded viaasyncio.to_thread.lenny/routes/api.pyborrow_item(), before the session-cookie check: ifIA_AUTH_ENABLEDand the request carriesAuthorization: LOW access:secret(parsed case-insensitively, any whitespace), validate viaverify_ia_s3_keys(). On success, create loan + IP-bound session cookie in one step.Flow
Why This Matters
The Internet Archive Labs Lenny instance hosts purchased EPUBs for OL patrons. IA patrons already have S3 keys. This plugin lets them borrow directly without going through the OTP email flow, while keeping the OTP path as the default for all other Lenny instances.
Companion PR
Test Plan
IA_AUTH_ENABLED=false(default): borrow endpoint behaviour unchanged, LOW header ignoredIA_AUTH_ENABLED=true, no Authorization header: falls through to OTP flow as beforeIA_AUTH_ENABLED=true,Authorization: LOW valid:keys: loan created, session cookie set in responseIA_AUTH_ENABLED=true,Authorization: LOW bad:keys:verify_ia_s3_keys()returnsNone, falls through to OTPIA_AUTH_ENABLED=trueAuthorization: low valid:keys(lowercase scheme): accepted identically toLOW