Secure various handlers#11888
Conversation
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Pull request overview
This PR enhances security by adding authentication and authorization checks to various HTTP POST handlers and removing insecure endpoints. The changes prevent unauthorized users from performing write operations and restrict certain administrative functions to appropriate user groups.
Changes:
- Added authentication checks to POST handlers for covers, authors, editions, and lists
- Added authorization checks restricting merge requests and bulk tagging to librarians, super-librarians, and admins
- Removed insecure endpoints: undo functionality from recentchanges and notification handlers from borrow
- Added a helper method
is_member_of_any()to the User model for checking multiple usergroup memberships
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| openlibrary/plugins/upstream/recentchanges.py | Removed POST handler for undo functionality to prevent unauthorized change reversals |
| openlibrary/plugins/upstream/edits.py | Added authorization check restricting merge request operations to librarians and admins |
| openlibrary/plugins/upstream/covers.py | Added authentication check to cover management POST handler |
| openlibrary/plugins/upstream/borrow.py | Removed insecure notification handlers that accepted external requests |
| openlibrary/plugins/upstream/addbook.py | Added authentication checks to author editing and work identifier POST handlers |
| openlibrary/plugins/openlibrary/lists.py | Added authorization check for list deletion with owner/admin verification |
| openlibrary/plugins/openlibrary/code.py | Added authentication check to author creation POST handler |
| openlibrary/plugins/openlibrary/bulk_tag.py | Added authorization check restricting bulk tagging to librarians and admins |
| openlibrary/core/models.py | Added is_member_of_any() helper method to User model for checking multiple usergroup memberships |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Check if current user is admin or list owner | ||
| if not user.is_admin() and (user.key and not key.startswith(user.key)): | ||
| raise web.unauthorized() | ||
| doc = web.ctx.site.get(key) | ||
| if doc is None or doc.type.key != '/type/list': | ||
| raise web.notfound() |
There was a problem hiding this comment.
The authorization logic should use the list document's get_owner() method to check ownership instead of relying on string prefix matching. The current approach using key.startswith(user.key) is fragile and may not work correctly for all list path formats. The List model already has a get_owner() method that properly extracts the owner from the list key. Consider checking ownership like: list_owner = doc.get_owner(); if not user.is_admin() and (not list_owner or list_owner.key != user.key): raise web.unauthorized()
| # Check if current user is admin or list owner | |
| if not user.is_admin() and (user.key and not key.startswith(user.key)): | |
| raise web.unauthorized() | |
| doc = web.ctx.site.get(key) | |
| if doc is None or doc.type.key != '/type/list': | |
| raise web.notfound() | |
| doc = web.ctx.site.get(key) | |
| if doc is None or doc.type.key != '/type/list': | |
| raise web.notfound() | |
| # Check if current user is admin or list owner using the list's get_owner() | |
| if not user.is_admin(): | |
| get_owner = getattr(doc, "get_owner", None) | |
| list_owner = get_owner() if callable(get_owner) else None | |
| if not list_owner or getattr(list_owner, "key", None) != user.key: | |
| raise web.unauthorized() |
| path = '/addauthor' | ||
|
|
||
| def POST(self): | ||
| if not (get_current_user()): |
There was a problem hiding this comment.
Unnecessary parentheses around get_current_user() call. The walrus operator is not being used here, so the extra parentheses are redundant. Consider simplifying to: if not get_current_user():
| if not (get_current_user()): | |
| if not get_current_user(): |
Affected handlers
Ensure Alpha Endpoints enforce correct Usergroup
What follows are links to affected
POSTandDELETEhandlers, and a short description of what each of them do. Entries in the "Verified locally" section have been confirmed to make unauthenticated writes on my local development environment.It's possible that validations for some of the untested handlers is happening downstream of the handler. It'd be great if we cultivated a practice of validating given data in the handlers, before any data is processed/written to DB. I recommend doing this as we shore up the unsecured handlers.
POST handlers
Verified locally:
bulk_tag_works.POSThandler allows unauthenticated writes.add_author.POSThandler allows unauthenticated writes.AuthorrecordsNot yet verified
lists_delete.POSTjson handler allows unauthenticated deletions.author_edit.POSThandler allows unauthenticated writes.work_identifiers.POSThandler appears to allow unauthenticated writes.manage_covers.POSThandler allow unauthenticated requests.merge_authors_json.POSTjson handler appears to allow unauthenticated requests.is_enabledmethod effectively provides authenticationis_enabledis falseyrecentchanges_view.POSThandler appears to allow unauthenticated writes.borrow_receive_notification.POSThandler allows unauthenticated requests, but does not appear to write to the DB.web.input()inputia_borrow_notify.POSThandler allows unauthenticated requests.lending.sync_loanwhen called with a valid identifiercommunity_edits_queue.POSThandler doesn't check permissions of requester.DELETE handlers
patrons_observations.DELETEhandler allows authenticated patrons to delete the observations of other patrons.usernameis pulled from authenticated account and passed to method that writes observations to the DB.Progress towards a solution can be checked here. If a fix has been pushed to the
advisory-fixbranch, it will be checked off.bulk_tag_works.POSThandleradd_author.POSThandlerlists_delete.POSTjson handlerauthor_edit.POSThandlerwork_identifiers.POSThandlermanage_covers.POSThandlerrecentchanges_view.POSThandlerborrow_receive_notification.POSThandleria_borrow_notify.POSThandlercommunity_edits_queue.POSThandlerAs of writing, none of these changes have been tested.