0
# Models
1
2
SQLAlchemy models for user management, role assignment, and permission tracking. These models define the database schema for Flask-AppBuilder's security system as integrated with Airflow.
3
4
## Capabilities
5
6
### User Model
7
8
Represents an Airflow user with authentication credentials and role assignments.
9
10
```python { .api }
11
class User(Model, BaseUser):
12
"""Represents an Airflow user which has roles assigned to it."""
13
14
# Database fields
15
id: int # Primary key
16
first_name: str # User's first name (max 256 chars)
17
last_name: str # User's last name (max 256 chars)
18
username: str # Unique username (max 512 chars)
19
password: str # Hashed password (max 256 chars)
20
active: bool # Whether user account is active
21
email: str # Unique email address (max 512 chars)
22
last_login: datetime.datetime | None # Last login timestamp
23
login_count: int | None # Number of successful logins
24
fail_login_count: int | None # Number of failed login attempts
25
roles: list[Role] # Associated roles
26
created_on: datetime.datetime | None # Account creation timestamp
27
changed_on: datetime.datetime | None # Last modification timestamp
28
created_by_fk: int | None # ID of user who created this account
29
changed_by_fk: int | None # ID of user who last modified this account
30
31
# Relationships
32
created_by: User | None # User who created this account
33
changed_by: User | None # User who last modified this account
34
35
# Properties
36
@property
37
def is_authenticated(self) -> bool:
38
"""Always returns True for authenticated users."""
39
40
@property
41
def is_active(self) -> bool:
42
"""Returns the active status of the user."""
43
44
@property
45
def is_anonymous(self) -> bool:
46
"""Always returns False for registered users."""
47
48
@property
49
def perms(self) -> set[tuple[str, str]]:
50
"""Returns set of permission tuples (action, resource) for the user."""
51
52
# Methods
53
def get_id(self) -> int:
54
"""Returns the user's ID."""
55
56
def get_name(self) -> str:
57
"""Returns username, email, or user_id as identifier."""
58
59
def get_full_name(self) -> str:
60
"""Returns formatted full name."""
61
62
@classmethod
63
def get_user_id(cls) -> int | None:
64
"""Returns current user ID from Flask global context."""
65
```
66
67
### Role Model
68
69
Represents a user role to which permissions can be assigned.
70
71
```python { .api }
72
class Role(Model):
73
"""Represents a user role to which permissions can be assigned."""
74
75
id: int # Primary key
76
name: str # Unique role name (max 64 chars)
77
permissions: list[Permission] # Associated permissions
78
```
79
80
### Permission Model
81
82
Permission pair comprised of an Action + Resource combination.
83
84
```python { .api }
85
class Permission(Model):
86
"""Permission pair comprised of an Action + Resource combo."""
87
88
id: int # Primary key
89
action_id: int # Foreign key to Action
90
action: Action # Action relationship
91
resource_id: int # Foreign key to Resource
92
resource: Resource # Resource relationship
93
```
94
95
### Action Model
96
97
Represents permission actions such as `can_read`, `can_edit`, etc.
98
99
```python { .api }
100
class Action(Model):
101
"""Represents permission actions such as `can_read`."""
102
103
id: int # Primary key
104
name: str # Unique action name (max 100 chars)
105
```
106
107
### Resource Model
108
109
Represents permission objects such as `User`, `Dag`, `Connection`, etc.
110
111
```python { .api }
112
class Resource(Model):
113
"""Represents permission object such as `User` or `Dag`."""
114
115
id: int # Primary key
116
name: str # Unique resource name (max 250 chars)
117
118
def __eq__(self, other) -> bool:
119
"""Equality comparison based on name."""
120
121
def __neq__(self, other) -> bool:
122
"""Inequality comparison based on name."""
123
```
124
125
### RegisterUser Model
126
127
Represents a user registration before account activation.
128
129
```python { .api }
130
class RegisterUser(Model):
131
"""Represents a user registration."""
132
133
id: int # Primary key
134
first_name: str # First name (max 256 chars)
135
last_name: str # Last name (max 256 chars)
136
username: str # Unique username (max 512 chars)
137
password: str # Hashed password (max 256 chars)
138
email: str # Email address (max 512 chars)
139
registration_date: datetime.datetime | None # Registration timestamp
140
registration_hash: str # Registration verification hash (max 256 chars)
141
```
142
143
## Usage Examples
144
145
### Creating and Querying Users
146
147
```python
148
from airflow.providers.fab.auth_manager.models import User, Role
149
from sqlalchemy.orm import Session
150
151
# Query users
152
with Session() as session:
153
# Get all active users
154
active_users = session.query(User).filter(User.active == True).all()
155
156
# Get user by username
157
user = session.query(User).filter(User.username == "admin").first()
158
if user:
159
print(f"User: {user.get_full_name()}")
160
print(f"Email: {user.email}")
161
print(f"Active: {user.is_active}")
162
print(f"Roles: {[role.name for role in user.roles]}")
163
```
164
165
### Working with Permissions
166
167
```python
168
from airflow.providers.fab.auth_manager.models import User, Permission, Action, Resource
169
170
# Get user permissions
171
user = session.query(User).filter(User.username == "analyst").first()
172
if user:
173
# Get all permissions for user
174
user_perms = user.perms
175
print(f"User permissions: {user_perms}")
176
177
# Check specific permission
178
has_dag_read = ("can_read", "DAG") in user_perms
179
print(f"Can read DAGs: {has_dag_read}")
180
```
181
182
### Role Management
183
184
```python
185
from airflow.providers.fab.auth_manager.models import Role, Permission, Action, Resource
186
187
# Query roles and their permissions
188
admin_role = session.query(Role).filter(Role.name == "Admin").first()
189
if admin_role:
190
print(f"Role: {admin_role.name}")
191
for perm in admin_role.permissions:
192
print(f" {perm.action.name} on {perm.resource.name}")
193
```
194
195
### User Authentication Properties
196
197
```python
198
# Check user authentication status
199
if user.is_authenticated and user.is_active and not user.is_anonymous:
200
print(f"User {user.get_name()} is properly authenticated")
201
print(f"Login count: {user.login_count}")
202
print(f"Last login: {user.last_login}")
203
```
204
205
## Types
206
207
```python { .api }
208
import datetime
209
from typing import TYPE_CHECKING
210
from flask_appbuilder.models.sqla import Model
211
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
212
from sqlalchemy.orm import relationship
213
from airflow.auth.managers.models.base_user import BaseUser
214
215
if TYPE_CHECKING:
216
from sqlalchemy import Identity
217
```
218
219
## Database Tables
220
221
The models map to the following database tables:
222
223
- `ab_user`: User accounts
224
- `ab_role`: User roles
225
- `ab_permission_view`: Permissions (action + resource pairs)
226
- `ab_permission`: Actions
227
- `ab_view_menu`: Resources
228
- `ab_user_role`: User-role associations (many-to-many)
229
- `ab_permission_view_role`: Permission-role associations (many-to-many)
230
- `ab_register_user`: Pending user registrations