Skip to content

chore(auth): decide policy enforcement for missing or dangling oauth_authorizations.policy_id #141

@NotThatKindOfDrLiz

Description

@NotThatKindOfDrLiz

Background

oauth_authorizations.policy_id has no foreign-key constraint to policies.id. As a result, an OAuth authorization can reference a non-existent policy_id (typo, stale, deleted policy). When the signer loads such an authorization, oauth_auth.permissions(...) returns an empty Vec<Permission>, and validate_permissions_for_sign / validate_permissions_for_encrypt / validate_permissions_for_decrypt fall through the permissions.is_empty() → Ok(()) backward-compat branch.

Net effect: a typo'd, stale, or deleted policy_id silently disables policy enforcement.

PR #131's test_18_no_permissions_allows_encrypt_and_decrypt pins the analogous behavior for "valid policy_id with zero linked permissions" (intended backward-compat). PR #132 (test_20_oauth_invalid_policy_id_allows_signing) pins the dangling-FK case as a regression test for current behavior — but current behavior may not be desired behavior.

Decision needed

Should an invalid / dangling policy_id fail closed (deny) or remain permissive (allow)? The current behavior is permissive; the question is whether that's intentional or a security gap.

Possible fixes if we want fail-closed

  1. Add a FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE RESTRICT constraint via migration. Prevents the dangling state at the DB level.
  2. Distinguish "dangling policy_id" from "valid policy with zero permissions" in the load path; deny on the former, allow on the latter (preserve backward-compat).
  3. Both.

Out of scope

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions