Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 43 additions & 5 deletions server/plugins/aaa.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,47 @@ def can_access_email(session: plugins.session.SessionObject, email: dict) -> boo
# If user can access the list, they can read the email
return can_access_list(session, email.get("list_raw", None))

def can_access_list(session: plugins.session.SessionObject, _listid: Optional[str]) -> bool:
def can_access_list(session: plugins.session.SessionObject, listid: Optional[str]) -> bool:
"""Determine if a list can be accessed by the current user"""
# If logged in via a known oauth, we assume access for now...TO BE CHANGED
if session.credentials and session.credentials.authoritative:
return True
return False
# Being authoritative (logged in via a configured OAuth domain) is REQUIRED
# but NOT sufficient: a user may only read a private list they are actually
# authorized for. Anything else fails closed.
if not (session.credentials and session.credentials.authoritative):
return False
if not listid:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This check should be first, as it is cheaper.
Though I wonder if listid should be optional here.

return False
return is_list_member(session, listid)


def is_list_member(session: plugins.session.SessionObject, listid: str) -> bool:
"""Determine whether the current user is authorized for THIS specific private list.

Wire _list_acl() to the deployment's source of truth (a per-list
owner/moderator/subscriber roster, or an explicit config ACL). Until a
membership model exists, only globally-configured admins are granted, and
everyone else is denied. Never grant a private list to every authoritative
user again.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The last sentence (Never … again) does not belong in the code.

"""
user = getattr(session.credentials, "email", None) or getattr(
session.credentials, "uid", None
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The above check - and the rest of the code - makes assumptions about the permission scheme, and may not be appropriate in all cases.

It should be up to the installer to provide the necessary code

if not user:
return False
acl = _list_acl(listid)
if acl is not None:
return user in acl
try:
admins = set(getattr(server.config, "admins", None) or [])
except NameError:
admins = set()
return user in admins


def _list_acl(listid: str):
"""Return the set of identities authorized for listid, or None if unknown.

TODO(ponymail): wire this to the real per-list membership / subscriber /
moderator source. Returning None (the default) makes is_list_member() fall
back to the admin-only check above, which is safe (fail closed).
"""
return None