CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-apache-airflow-fab-security

Flask-AppBuilder (FAB) security integration component within Apache Airflow core, providing authentication, authorization, and security management features

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

data-models.mddocs/

Data Models

SQLAlchemy models representing the security schema including users, roles, permissions, actions, resources, and their relationships. These models provide the data layer foundation for all security operations.

Capabilities

User Model

Represents an Airflow user with authentication information, profile data, and role assignments.

class User(Model):
    """
    Represents an Airflow user which has roles assigned to it.
    
    Attributes:
    - id: Integer primary key
    - first_name: String(64), user's first name  
    - last_name: String(64), user's last name
    - username: String(256), unique username
    - password: String(256), hashed password
    - active: Boolean, whether user account is active
    - email: String(256), unique email address
    - last_login: DateTime, timestamp of last login
    - login_count: Integer, total number of logins
    - fail_login_count: Integer, number of failed login attempts
    - roles: Relationship to Role objects
    - created_on: DateTime, account creation timestamp
    - changed_on: DateTime, last modification timestamp
    - created_by_fk: Foreign key to User who created this account
    - changed_by_fk: Foreign key to User who last modified this account
    - created_by: Relationship to User (creator)
    - changed_by: Relationship to User (modifier)
    """
    
    @classmethod
    def get_user_id(cls) -> int | None:
        """Get current user ID from Flask context."""
    
    @property
    def is_authenticated(self) -> bool:
        """Check if user is authenticated (always True for User objects)."""
    
    @property  
    def is_active(self) -> bool:
        """Check if user account is active."""
    
    @property
    def is_anonymous(self) -> bool:
        """Check if user is anonymous (always False for User objects)."""
    
    @property
    def perms(self) -> set[tuple[str, str]]:
        """Get user's permissions as set of (action, resource) tuples."""
    
    def get_id(self) -> int:
        """Get user ID for session management."""
    
    def get_full_name(self) -> str:
        """Get formatted full name (first_name last_name)."""

Role Model

Represents a user role that can be assigned permissions and associated with users.

class Role(Model):
    """
    Represents a user role to which permissions can be assigned.
    
    Attributes:
    - id: Integer primary key
    - name: String(64), unique role name
    - permissions: Relationship to Permission objects assigned to this role
    """

Permission Model

Represents a permission pairing an action with a resource for granular access control.

class Permission(Model):
    """
    Permission pair comprised of an Action + Resource combo.
    
    Attributes:
    - id: Integer primary key
    - action_id: Foreign key to Action
    - action: Relationship to Action object
    - resource_id: Foreign key to Resource  
    - resource: Relationship to Resource object
    """

Action Model

Represents permission actions that define what operations can be performed.

class Action(Model):
    """
    Represents permission actions such as 'can_read', 'can_edit', etc.
    
    Attributes:
    - id: Integer primary key
    - name: String(100), unique action name
    """

Resource Model

Represents permission objects/resources that can be protected by permissions.

class Resource(Model):
    """
    Represents permission objects such as 'User', 'DAG', 'Connection', etc.
    
    Attributes:
    - id: Integer primary key
    - name: String(250), unique resource name
    """
    
    def __eq__(self, other) -> bool:
        """Check equality based on resource name."""
    
    def __neq__(self, other) -> bool:
        """Check inequality based on resource name."""

RegisterUser Model

Represents a user registration request for user self-registration workflows.

class RegisterUser(Model):
    """
    Represents a user registration request.
    
    Attributes:
    - id: Integer primary key
    - first_name: String(64), requested first name
    - last_name: String(64), requested last name
    - username: String(256), requested unique username
    - password: String(256), hashed password
    - email: String(256), email address
    - registration_date: DateTime, when registration was requested
    - registration_hash: String(256), unique hash for registration verification
    """

Association Tables

Many-to-many relationship tables connecting the core models.

assoc_permission_role = Table(
    "ab_permission_view_role",
    Model.metadata,
    Column("id", Integer, primary_key=True),
    Column("permission_view_id", Integer, ForeignKey("ab_permission_view.id")),
    Column("role_id", Integer, ForeignKey("ab_role.id")),
    UniqueConstraint("permission_view_id", "role_id")
)
"""Many-to-many relationship table between Permission and Role."""

assoc_user_role = Table(
    "ab_user_role", 
    Model.metadata,
    Column("id", Integer, primary_key=True),
    Column("user_id", Integer, ForeignKey("ab_user.id")),
    Column("role_id", Integer, ForeignKey("ab_role.id")),
    UniqueConstraint("user_id", "role_id")
)
"""Many-to-many relationship table between User and Role."""

Database Schema

Table Names

The models map to specific database tables:

  • Userab_user
  • Roleab_role
  • Permissionab_permission_view
  • Actionab_permission
  • Resourceab_view_menu
  • RegisterUserab_register_user

Relationships

  • User ↔ Role: Many-to-many via assoc_user_role
  • Role ↔ Permission: Many-to-many via assoc_permission_role
  • Permission → Action: Many-to-one
  • Permission → Resource: Many-to-one
  • User → User: Self-referencing for created_by/changed_by

Usage Examples

Working with User Model

from airflow.www.fab_security.sqla.models import User, Role

# Create user instance
user = User()
user.username = "john_doe"  
user.email = "john@example.com"
user.first_name = "John"
user.last_name = "Doe"
user.active = True

# Check user properties
if user.is_active:
    print(f"Active user: {user.get_full_name()}")

# Access user permissions
for action, resource in user.perms:
    print(f"Permission: {action} on {resource}")

Role and Permission Relationships

from airflow.www.fab_security.sqla.models import Role, Permission, Action, Resource

# Create role
role = Role(name="DataAnalyst")

# Create permission components
action = Action(name="can_read")
resource = Resource(name="Reports")
permission = Permission(action=action, resource=resource)

# Assign permission to role
role.permissions.append(permission)

# Access role permissions
for perm in role.permissions:
    print(f"Role {role.name} can {perm.action.name} on {perm.resource.name}")

Registration Workflow

import uuid
from datetime import datetime
from airflow.www.fab_security.sqla.models import RegisterUser

# Create registration request
registration = RegisterUser()
registration.username = "new_user"
registration.first_name = "New" 
registration.last_name = "User"
registration.email = "new@example.com"
registration.registration_date = datetime.now()
registration.registration_hash = str(uuid.uuid1())

print(f"Registration hash: {registration.registration_hash}")

Query Examples

from sqlalchemy.orm import sessionmaker
from airflow.www.fab_security.sqla.models import User, Role

# Query users by role
admin_role = session.query(Role).filter_by(name="Admin").first()
admin_users = session.query(User).filter(User.roles.contains(admin_role)).all()

# Query permissions for user
user = session.query(User).filter_by(username="john_doe").first()
if user:
    # Get all permissions through roles
    all_permissions = []
    for role in user.roles:
        all_permissions.extend(role.permissions)

Model Constraints

Unique Constraints

  • User.username: Must be unique across all users
  • User.email: Must be unique across all users
  • Role.name: Must be unique across all roles
  • Action.name: Must be unique across all actions
  • Resource.name: Must be unique across all resources
  • Permission(action_id, resource_id): Unique combination constraint

Foreign Key Constraints

  • Permission.action_idAction.id
  • Permission.resource_idResource.id
  • User.created_by_fkUser.id (self-reference)
  • User.changed_by_fkUser.id (self-reference)

Metadata Integration

All models inherit from Flask-AppBuilder's Model class and use Airflow's base metadata for table creation and management, ensuring compatibility with Airflow's database migration system.

Install with Tessl CLI

npx tessl i tessl/pypi-apache-airflow-fab-security

docs

authentication-backends.md

data-models.md

index.md

role-permission-management.md

security-management.md

user-management.md

web-views.md

tile.json