This is Alpha 2 Software. You can test the process and download content, but releases must still be committed by hand to svn:dist/release (see svn-dist Transition Plan 1B).

3.13. Authorization security

Up: 3. Developer guide

Prev: 3.12. Authentication security

Next: 3.14. Input validation

Sections:

Overview

ATR uses role-based access control (RBAC) where roles are derived from ASF LDAP group memberships. Authentication (covered in Authentication security) establishes who a user is; authorization determines what they can do.

The authorization model is committee-centric: most permissions are granted based on a user's relationship to a committee (PMC membership) or project (committer status).

Roles and principals

Note

This documents the current status of roles in the application, which will be reorganized, per these Issues:

ATR recognizes the following roles, derived from ASF LDAP:

  • Public: Unauthenticated users. Can view public information about releases and projects.

  • Committer: Any authenticated ASF committer. Can create Personal Access Tokens and view their own committees and projects. Determined by existence in LDAP ou=people,dc=apache,dc=org.

  • Project Participant: A committer who is a member of a specific project. Can start releases, upload artifacts, and cast votes for that project. Determined by the member attribute in the project's LDAP group.

  • PMC Member: A committer who is on the PMC (Project Management Committee) for a specific committee. Has all participant permissions plus can resolve votes, finish releases, configure project settings, and manage signing keys. Determined by the owner attribute in the committee's LDAP group.

  • Chair: A PMC chair. Currently has the same permissions as PMC Member in ATR. Determined by membership in cn=pmc-chairs,ou=groups,ou=services,dc=apache,dc=org.

  • ASF Member: An ASF Member. Currently has the same permissions as a regular committer in ATR, though this may change. Determined by membership in cn=member,ou=groups,dc=apache,dc=org.

  • Infrastructure Root: ASF Infrastructure team with root access. Has administrative capabilities. Determined by membership in cn=infrastructure-root,ou=groups,ou=services,dc=apache,dc=org.

  • Tooling Team: Members of the ASF Tooling team. Treated as PMC members of the "tooling" committee. Determined by membership in cn=tooling,ou=groups,ou=services,dc=apache,dc=org.

LDAP integration

Authorization data is fetched from ASF LDAP using the principal module. The key LDAP bases are:

  • ou=people,dc=apache,dc=org - All committers
  • ou=project,ou=groups,dc=apache,dc=org - Project and committee groups
  • cn=member,ou=groups,dc=apache,dc=org - ASF Members
  • cn=pmc-chairs,ou=groups,ou=services,dc=apache,dc=org - PMC Chairs
  • cn=infrastructure-root,ou=groups,ou=services,dc=apache,dc=org - Infrastructure root
  • cn=tooling,ou=groups,ou=services,dc=apache,dc=org - Tooling team

The Committer class fetches a user's full authorization profile from LDAP, including their committee memberships (PMC membership) and project participations (committer access).

Access control for releases

Release operations have the following access requirements:

View release information (public pages, download links):

  • Allowed for: Everyone, including unauthenticated users
  • This includes the following API endpoints, which are intentionally unauthenticated because they serve the same public information available on the website:
    • /api/checks/list/<project>/<version> — check results for a release
    • /api/checks/ongoing/<project>/<version> — count of ongoing checks
    • /api/release/paths/<project>/<version> — file paths in a release
    • /api/release/revisions/<project>/<version> — revision history of a release
    • /api/ssh-keys/list/<asf_uid> — enumerates SSH key fingerprints for any user
    • /api/keys/user/<asf_uid> — enumerates OpenPGP keys for any user
  • Rationale: ASF release artifacts, their check results, and their metadata are public by design. The release process is transparent and these endpoints support tooling that consumes public release data.

Start a new release:

  • Allowed for: Project participants (committers on the project)
  • Checked via: is_participant_of(project.committee_name)

Upload release artifacts:

  • Allowed for: Project participants
  • Additional constraint: Must be the user who started the release, or a PMC member

Cast a vote on a release:

  • Allowed for: Project participants
  • Constraint: Cannot vote multiple times; can change existing vote

Resolve a vote (tally votes and determine outcome):

  • Allowed for: PMC members only
  • Checked via: is_member_of(project.committee_name)

Finish a release (publish to distribution):

  • Allowed for: PMC members only
  • Constraint: Vote must be resolved with a passing result

Cancel or delete a release:

  • Draft releases: Project participants
  • Finished releases: ATR administrators only

Access control for tokens

Token operations apply to the authenticated user:

Create a Personal Access Token:

  • Allowed for: Any authenticated committer
  • Constraint: Can only create tokens for themselves

List own Personal Access Tokens:

  • Allowed for: Any authenticated committer
  • Constraint: Can only see their own tokens

Revoke a Personal Access Token:

  • Allowed for: The token owner, or administrators
  • Constraint: Users can only revoke their own tokens (unless admin)

Revoke all tokens for a user (admin):

  • Allowed for: ATR administrators only
  • Interface: Admin "Revoke user tokens" page
  • Constraint: Requires typing "REVOKE" as confirmation

Exchange PAT for JWT:

  • Allowed for: Anyone with a valid PAT
  • Note: This is an unauthenticated endpoint; the PAT serves as the credential

Access control for check ignores

Check ignores allow committee members to suppress specific check results from the warning and error counts. The ignores page is accessible to any authenticated committer, but only PMC members of the project's committee can add, update, or delete ignore rules. The storage writer validates that the user is a member of the committee that owns the target project by calling is_member_of(project.committee_name). As additional protection, the writer also validates that the project belongs to the authorized committee before performing any operation. This ensures that even if the calling code passes an incorrect project name, the operation will be rejected.

Implementation patterns

Authorization checks in ATR follow consistent patterns.

Checking PMC membership

To verify a user is a PMC member for a committee:

from atr.principal import Authorisation

auth = await Authorisation()
if not auth.is_member_of(committee_name):
    raise Forbidden("PMC membership required")

Checking project participation

To verify a user is a committer on a project:

auth = await Authorisation()
if not auth.is_participant_of(project.committee_name):
    raise Forbidden("Project participation required")

Getting all memberships

To get the set of committees or projects a user belongs to:

auth = await Authorisation()
committees = auth.member_of()      # Returns frozenset of committee names
projects = auth.participant_of()   # Returns frozenset of project names

Web vs API authorization

For web requests, the Authorisation class reads the session automatically:

auth = await Authorisation()  # Uses ASFQuart session

For API requests, the ASF UID is extracted from the JWT and passed explicitly:

auth = await Authorisation(asf_uid)  # Uses LDAP lookup

Both paths use the same authorization logic and caching.

Caching behavior

LDAP queries are expensive, so authorization data is cached in principal.Cache. The cache stores:

  • member_of - Set of committees where the user is a PMC member
  • participant_of - Set of projects where the user is a committer
  • last_refreshed - Timestamp of last LDAP query

The cache TTL is 300 seconds (cache_for_at_most_seconds). When the cache is stale, the next authorization check triggers an LDAP refresh.

The cache is per-user and in-memory. It does not persist across server restarts. If LDAP group memberships change, users may need to wait up to 5 minutes for ATR to reflect the change, or log out and back in.

Test mode

When ALLOW_TESTS is enabled in the configuration, a special "test" user and "test" committee are available. This should never be enabled in production. The security implications are significant:

  1. All authenticated users (not just the test user) are granted membership in the "test" committee and project principal.
  2. Authorization checks in the storage layer are completely skipped for the test committee release.
  3. Rate limiting is disabled server.
  4. A hardcoded "test" user bypasses LDAP verification.

If ALLOW_TESTS is accidentally left enabled in production, every authenticated user gains unauthorized access to the test committee and its resources. This flag is intended for use only in development and test environments where DEBUG_MODE is also set.

Implementation references

  • principal.py - Core authorization classes and LDAP integration
  • web.py - Request context and committer access
  • ldap.py - Low-level LDAP search functionality