Skip to main content
ACL Package - Usage Guide

==========================

WHAT IS THIS PACKAGE?
---------------------
This is a custom Access Control List (ACL) Python package that manages
permissions for users through roles, groups, and object-level rules.

It is a pure Python package with no external dependencies.


HOW TO INSTALL
--------------
From your project folder, run:

pip install -e /path/to/aclforall

Or copy the acl_package folder into your project and import directly.


QUICK START
-----------
from acl_package import User, Role, Permission, Group, PermissionRegistry

# 1. Create permissions
read_perm = Permission(1, "blog.read", "Read Blog Posts")
write_perm = Permission(2, "blog.write", "Write Blog Posts")

# 2. Create a role and assign permissions
editor = Role(1, "editor")
editor.assign_permissions(read_perm, write_perm)

# 3. Create a user and assign the role
user = User(1, "alice", "alice@example.com", "hashed_pw", False, True)
user.assign_role(editor)

# 4. Check permissions
print(user.has_perm("blog.read")) # True
print(user.has_perm("blog.delete")) # False


CLASSES AND WHAT THEY DO
========================

1. Permission
-------------
Represents a single permission like "blog.read" or "admin.delete".

perm = Permission(id=1, name="blog.read", label="Read Blog", effect="allow")

Attributes:
id - unique identifier
permission_name - the permission string (e.g. "blog.read")
label - human-readable description
effect - "allow" or "deny" (default: "allow")
created_at - optional timestamp

Methods:
perm.grant() - set effect to "allow"
perm.deny() - set effect to "deny"
perm.is_allow() - returns True if effect is "allow"
perm.is_deny() - returns True if effect is "deny"
perm.matches("x.y") - checks if this perm matches a name (supports wildcards)

Wildcard example:
perm = Permission(1, "blog.*", "All Blog")
perm.matches("blog.read") # True
perm.matches("blog.write") # True
perm.matches("user.read") # False


2. Role
-------
A role groups multiple permissions together.

editor = Role(1, "editor")

Methods:
editor.assign_permission(perm) - add one permission
editor.assign_permissions(p1, p2) - add multiple
editor.remove_permission(perm) - remove a permission
editor.has_permission("blog.read") - check if role has permission
editor.get_permission_names() - list all permission names
editor.clear_permissions() - remove all permissions


3. Group
--------
A group collects multiple roles. Groups inherit PermissionMixin,
so they can check permissions directly.

team = Group(1, "developers")

Methods:
team.assign_role(role) - add a role
team.assign_roles(r1, r2) - add multiple roles
team.remove_role(role) - remove a role
team.has_role("editor") - check if group has role
team.get_roles() - list roles
team.clear_roles() - remove all roles

Groups can also check permissions directly:
team.has_perm("blog.read") - checks via inherited roles


4. User
-------
The main class. Users can have roles, groups, direct permissions,
and object-level permissions. Users inherit PermissionMixin.

user = User(1, "alice", "alice@test.com", "pw", False, True)

Attributes:
id - unique identifier
username - username string
email - email string
password - password (hashed in real apps)
is_super_admin - True bypasses all permission checks
is_active - account active flag

Role management:
user.assign_role(role) - assign a role
user.assign_roles(r1, r2) - assign multiple
user.remove_role(role) - remove a role
user.has_role("editor") - check if user has role
user.get_roles() - list roles
user.clear_roles() - remove all roles

Group management:
user.add_to_group(group) - add to a group
user.add_to_groups(g1, g2) - add to multiple
user.remove_from_group(group) - remove from group
user.is_in_group("developers") - check group membership
user.get_groups() - list groups
user.clear_groups() - leave all groups

Direct permission management:
user.assign_permission(perm) - assign permission directly
user.assign_permissions(p1, p2) - assign multiple
user.remove_permission(perm) - remove direct permission
user.clear_permissions() - remove all direct permissions

Object-level permission management:
user.assign_object_permission(obj_perm)
user.remove_object_permission(obj_perm)
user.get_object_permissions("document", "doc_123")
user.clear_object_permissions()

Permission checking:
user.has_perm("blog.read") - basic check
user.has_perm("blog.read", "document", "doc_123") - object-level check
user.has_perms("p1", "p2") - ALL must match
user.has_any_perm("p1", "p2") - ANY must match
user.get_all_permission_names() - list all effective perms
user.get_denied_permissions() - list denied perms
user.get_allowed_permissions() - list allowed perms


5. ObjectPermission
-------------------
A permission tied to a specific object instance.

obj_perm = ObjectPermission(
id=1, user=user, group_id=None,
object_type="document", object_id="doc_123",
permission_name="document.read", effect="allow"
)

Methods:
obj_perm.is_allow() - check if allow
obj_perm.is_deny() - check if deny
obj_perm.matches("document", "doc_123") - check if matches object
obj_perm.matches_permission("document.read") - check permission name


6. PermissionRegistry
---------------------
A central store for all defined permissions.

registry = PermissionRegistry()

Methods:
registry.add_permission(perm) - store a permission
registry.add_permissions(p1, p2) - store multiple
registry.get("blog.read") - retrieve by name
registry.exists("blog.read") - check if exists
registry.remove("blog.read") - remove by name
registry.list_all() - list all Permission objects
registry.list_names() - list all permission names
registry.count() - number of permissions
registry.search("blog") - search by partial name
registry.search_by_prefix("blog.") - search by prefix
registry.get_allow_permissions() - list all allow perms
registry.get_deny_permissions() - list all deny perms
registry.clear() - remove all

Singleton pattern:
registry = PermissionRegistry.get_instance() # shared instance
PermissionRegistry.reset_instance() # reset singleton

Supports "in" operator:
if "blog.read" in registry: ...


7. PermissionMixin
------------------
Provides permission checking logic to any class that inherits it.

Methods provided:
has_perm(permission_name, obj_type=None, obj_id=None)
has_perms(*permissions)
has_any_perm(*permissions)
get_all_permission_names()
get_denied_permissions()
get_allowed_permissions()

Used by: User, Group


8. BaseAPI / AdminAPI / ReadOnlyAPI
-----------------------------------
API base classes that inherit PermissionMixin. Use these as base
classes for your API handlers or view classes.

class BlogAPI(BaseAPI):
required_permission = "blog.read"

def list_posts(self):
if not self.allowed():
return {"error": "Access denied"}
return {"posts": ["Post 1", "Post 2"]}

def create_post(self):
if not self.check_permission("blog.write"):
return {"error": "Access denied"}
return {"status": "Post created"}

# Usage
user = User(1, "writer", "w@test.com", "pw", False, True)
user.assign_role(editor_role)

api = BlogAPI(user=user)
api.list_posts() # returns {"posts": ["Post 1", "Post 2"]}
api.create_post() # returns {"status": "Post created"}

BaseAPI methods:
api.set_user(user) - set the user
api.check_permission("blog.read") - check a permission
api.allowed() - check required_permission
api.get_user_permissions() - list user permissions
api.get_effective_permissions() - list all effective perms

AdminAPI:
Inherits BaseAPI. Adds admin_allowed() which checks is_super_admin
or required_permission = "admin.*"

ReadOnlyAPI:
Inherits BaseAPI. Adds read_allowed() and list_allowed() helpers.


HOW PERMISSION CHECKING WORKS (Flow)
=====================================

When you call user.has_perm("blog.create"):

1. Check if user.is_super_admin is True
- If yes, return True immediately (bypass)

2. Collect ALL permissions from:
a. user.roles -> role.permissions
b. user.groups -> group.roles -> role.permissions
c. user.permissions (direct permissions)
d. user.object_permissions (if obj_type/obj_id provided)

3. Deduplicate collected permissions

4. First pass - check for DENY:
- If any matching permission has effect="deny", return False

5. Second pass - check for ALLOW:
- If any matching permission has effect="allow", return True

6. If nothing matched, return False

Wildcard matching:
"blog.*" matches "blog.read", "blog.write", "blog.anything"
"api.user.*" matches "api.user.read", "api.user.write"
Exact match: "blog.read" matches only "blog.read"


PRACTICAL EXAMPLE - COMPLETE SETUP
===================================

from acl_package import User, Role, Permission, Group, PermissionRegistry

# Setup permissions
registry = PermissionRegistry()
perms = {
"blog.read": Permission(1, "blog.read", "Read Blog", "allow"),
"blog.write": Permission(2, "blog.write", "Write Blog", "allow"),
"blog.delete": Permission(3, "blog.delete", "Delete Blog", "deny"),
"admin.*": Permission(4, "admin.*", "All Admin", "allow"),
}
registry.add_permissions(*perms.values())

# Setup roles
editor = Role(1, "editor")
editor.assign_permissions(perms["blog.read"], perms["blog.write"])

viewer = Role(2, "viewer")
viewer.assign_permission(perms["blog.read"])

admin = Role(3, "admin")
admin.assign_permission(perms["admin.*"])

# Setup groups
content_team = Group(1, "content_team")
content_team.assign_role(editor)

# Setup users
alice = User(1, "alice", "alice@test.com", "pw", False, True)
alice.assign_role(viewer)
alice.add_to_group(content_team)

bob = User(2, "bob", "bob@test.com", "pw", False, True)
bob.assign_role(admin)

# Check permissions
alice.has_perm("blog.read") # True (via viewer role + group)
alice.has_perm("blog.write") # True (via content_team group -> editor role)
alice.has_perm("blog.delete") # False (no one has this)
bob.has_perm("blog.delete") # True (admin.* wildcard matches)

# Method chaining
carol = (User(3, "carol", "c@test.com", "pw", False, True)
.assign_role(editor)
.add_to_group(content_team))
carol.has_perm("blog.write") # True


USING IN ANOTHER PROJECT
========================

Option 1: Install as package
pip install -e /path/to/aclforall

# In your project
from acl_package import User, Role, Permission

Option 2: Copy folder
Copy the acl_package folder into your project.

# In your project
from acl_package import User, Role, Permission

Option 3: Add to sys.path
import sys
sys.path.append("/path/to/aclforall")

from acl_package import User, Role, Permission

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aclforall-0.2.1.tar.gz (19.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aclforall-0.2.1-py3-none-any.whl (19.8 kB view details)

Uploaded Python 3

File details

Details for the file aclforall-0.2.1.tar.gz.

File metadata

  • Download URL: aclforall-0.2.1.tar.gz
  • Upload date:
  • Size: 19.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.9

File hashes

Hashes for aclforall-0.2.1.tar.gz
Algorithm Hash digest
SHA256 04af2e4d5cffa977f47e14163c5a0149f4d64aca874f00f58179e9dc8fc3baa1
MD5 f4c3f53a694b7342a8b19c054d44de74
BLAKE2b-256 7a8f1aafc0bbcecf0947bfd0401d82a990d6947d40b048a6054efa8148d0ccce

See more details on using hashes here.

File details

Details for the file aclforall-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: aclforall-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 19.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.9

File hashes

Hashes for aclforall-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1039a95a993b9fda653c0b9b06fc644c369ca56c565d80cb74f1f36e63ecd217
MD5 725486ee2a55f200a2acfbac92cb512a
BLAKE2b-256 84a9f5db47e9b21542190fc7766ef03d787cde5e2d6456df7b840f019513e15a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page