or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-backends.mddata-models.mdindex.mdrole-permission-management.mdsecurity-management.mduser-management.mdweb-views.md

data-models.mddocs/

0

# Data Models

1

2

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.

3

4

## Capabilities

5

6

### User Model

7

8

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

9

10

```python { .api }

11

class User(Model):

12

"""

13

Represents an Airflow user which has roles assigned to it.

14

15

Attributes:

16

- id: Integer primary key

17

- first_name: String(64), user's first name

18

- last_name: String(64), user's last name

19

- username: String(256), unique username

20

- password: String(256), hashed password

21

- active: Boolean, whether user account is active

22

- email: String(256), unique email address

23

- last_login: DateTime, timestamp of last login

24

- login_count: Integer, total number of logins

25

- fail_login_count: Integer, number of failed login attempts

26

- roles: Relationship to Role objects

27

- created_on: DateTime, account creation timestamp

28

- changed_on: DateTime, last modification timestamp

29

- created_by_fk: Foreign key to User who created this account

30

- changed_by_fk: Foreign key to User who last modified this account

31

- created_by: Relationship to User (creator)

32

- changed_by: Relationship to User (modifier)

33

"""

34

35

@classmethod

36

def get_user_id(cls) -> int | None:

37

"""Get current user ID from Flask context."""

38

39

@property

40

def is_authenticated(self) -> bool:

41

"""Check if user is authenticated (always True for User objects)."""

42

43

@property

44

def is_active(self) -> bool:

45

"""Check if user account is active."""

46

47

@property

48

def is_anonymous(self) -> bool:

49

"""Check if user is anonymous (always False for User objects)."""

50

51

@property

52

def perms(self) -> set[tuple[str, str]]:

53

"""Get user's permissions as set of (action, resource) tuples."""

54

55

def get_id(self) -> int:

56

"""Get user ID for session management."""

57

58

def get_full_name(self) -> str:

59

"""Get formatted full name (first_name last_name)."""

60

```

61

62

### Role Model

63

64

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

65

66

```python { .api }

67

class Role(Model):

68

"""

69

Represents a user role to which permissions can be assigned.

70

71

Attributes:

72

- id: Integer primary key

73

- name: String(64), unique role name

74

- permissions: Relationship to Permission objects assigned to this role

75

"""

76

```

77

78

### Permission Model

79

80

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

81

82

```python { .api }

83

class Permission(Model):

84

"""

85

Permission pair comprised of an Action + Resource combo.

86

87

Attributes:

88

- id: Integer primary key

89

- action_id: Foreign key to Action

90

- action: Relationship to Action object

91

- resource_id: Foreign key to Resource

92

- resource: Relationship to Resource object

93

"""

94

```

95

96

### Action Model

97

98

Represents permission actions that define what operations can be performed.

99

100

```python { .api }

101

class Action(Model):

102

"""

103

Represents permission actions such as 'can_read', 'can_edit', etc.

104

105

Attributes:

106

- id: Integer primary key

107

- name: String(100), unique action name

108

"""

109

```

110

111

### Resource Model

112

113

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

114

115

```python { .api }

116

class Resource(Model):

117

"""

118

Represents permission objects such as 'User', 'DAG', 'Connection', etc.

119

120

Attributes:

121

- id: Integer primary key

122

- name: String(250), unique resource name

123

"""

124

125

def __eq__(self, other) -> bool:

126

"""Check equality based on resource name."""

127

128

def __neq__(self, other) -> bool:

129

"""Check inequality based on resource name."""

130

```

131

132

### RegisterUser Model

133

134

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

135

136

```python { .api }

137

class RegisterUser(Model):

138

"""

139

Represents a user registration request.

140

141

Attributes:

142

- id: Integer primary key

143

- first_name: String(64), requested first name

144

- last_name: String(64), requested last name

145

- username: String(256), requested unique username

146

- password: String(256), hashed password

147

- email: String(256), email address

148

- registration_date: DateTime, when registration was requested

149

- registration_hash: String(256), unique hash for registration verification

150

"""

151

```

152

153

### Association Tables

154

155

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

156

157

```python { .api }

158

assoc_permission_role = Table(

159

"ab_permission_view_role",

160

Model.metadata,

161

Column("id", Integer, primary_key=True),

162

Column("permission_view_id", Integer, ForeignKey("ab_permission_view.id")),

163

Column("role_id", Integer, ForeignKey("ab_role.id")),

164

UniqueConstraint("permission_view_id", "role_id")

165

)

166

"""Many-to-many relationship table between Permission and Role."""

167

168

assoc_user_role = Table(

169

"ab_user_role",

170

Model.metadata,

171

Column("id", Integer, primary_key=True),

172

Column("user_id", Integer, ForeignKey("ab_user.id")),

173

Column("role_id", Integer, ForeignKey("ab_role.id")),

174

UniqueConstraint("user_id", "role_id")

175

)

176

"""Many-to-many relationship table between User and Role."""

177

```

178

179

## Database Schema

180

181

### Table Names

182

183

The models map to specific database tables:

184

- `User``ab_user`

185

- `Role``ab_role`

186

- `Permission``ab_permission_view`

187

- `Action``ab_permission`

188

- `Resource``ab_view_menu`

189

- `RegisterUser``ab_register_user`

190

191

### Relationships

192

193

- **User ↔ Role**: Many-to-many via `assoc_user_role`

194

- **Role ↔ Permission**: Many-to-many via `assoc_permission_role`

195

- **Permission → Action**: Many-to-one

196

- **Permission → Resource**: Many-to-one

197

- **User → User**: Self-referencing for created_by/changed_by

198

199

## Usage Examples

200

201

### Working with User Model

202

203

```python

204

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

205

206

# Create user instance

207

user = User()

208

user.username = "john_doe"

209

user.email = "john@example.com"

210

user.first_name = "John"

211

user.last_name = "Doe"

212

user.active = True

213

214

# Check user properties

215

if user.is_active:

216

print(f"Active user: {user.get_full_name()}")

217

218

# Access user permissions

219

for action, resource in user.perms:

220

print(f"Permission: {action} on {resource}")

221

```

222

223

### Role and Permission Relationships

224

225

```python

226

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

227

228

# Create role

229

role = Role(name="DataAnalyst")

230

231

# Create permission components

232

action = Action(name="can_read")

233

resource = Resource(name="Reports")

234

permission = Permission(action=action, resource=resource)

235

236

# Assign permission to role

237

role.permissions.append(permission)

238

239

# Access role permissions

240

for perm in role.permissions:

241

print(f"Role {role.name} can {perm.action.name} on {perm.resource.name}")

242

```

243

244

### Registration Workflow

245

246

```python

247

import uuid

248

from datetime import datetime

249

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

250

251

# Create registration request

252

registration = RegisterUser()

253

registration.username = "new_user"

254

registration.first_name = "New"

255

registration.last_name = "User"

256

registration.email = "new@example.com"

257

registration.registration_date = datetime.now()

258

registration.registration_hash = str(uuid.uuid1())

259

260

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

261

```

262

263

### Query Examples

264

265

```python

266

from sqlalchemy.orm import sessionmaker

267

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

268

269

# Query users by role

270

admin_role = session.query(Role).filter_by(name="Admin").first()

271

admin_users = session.query(User).filter(User.roles.contains(admin_role)).all()

272

273

# Query permissions for user

274

user = session.query(User).filter_by(username="john_doe").first()

275

if user:

276

# Get all permissions through roles

277

all_permissions = []

278

for role in user.roles:

279

all_permissions.extend(role.permissions)

280

```

281

282

## Model Constraints

283

284

### Unique Constraints

285

286

- `User.username`: Must be unique across all users

287

- `User.email`: Must be unique across all users

288

- `Role.name`: Must be unique across all roles

289

- `Action.name`: Must be unique across all actions

290

- `Resource.name`: Must be unique across all resources

291

- `Permission(action_id, resource_id)`: Unique combination constraint

292

293

### Foreign Key Constraints

294

295

- `Permission.action_id``Action.id`

296

- `Permission.resource_id``Resource.id`

297

- `User.created_by_fk``User.id` (self-reference)

298

- `User.changed_by_fk``User.id` (self-reference)

299

300

## Metadata Integration

301

302

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.