or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration-utilities.mdcore-application.mddatabase-models.mdindex.mdmonitoring-metrics.mdrbac-permissions.mdrest-api.mdservices-oauth.mdsingleuser-integration.mdspawners.md

rbac-permissions.mddocs/

0

# RBAC and Permissions

1

2

JupyterHub implements a comprehensive Role-Based Access Control (RBAC) system with fine-grained permissions through scopes. The system supports roles that can be assigned to users, groups, services, and API tokens, providing flexible authorization for all JupyterHub operations.

3

4

## Capabilities

5

6

### Role Management

7

8

Core functions for managing roles in the RBAC system.

9

10

```python { .api }

11

def get_default_roles() -> Dict[str, Dict[str, Any]]:

12

"""

13

Get the default role definitions for JupyterHub.

14

15

Returns:

16

Dictionary of default roles with their scopes and descriptions:

17

- 'user': Basic user permissions

18

- 'admin': Full system administrator permissions

19

- 'server': Permissions for single-user servers

20

- 'token': Permissions for API tokens

21

"""

22

23

# Default roles structure

24

DEFAULT_ROLES = {

25

'user': {

26

'description': 'Default permissions for users',

27

'scopes': [

28

'self',

29

'servers!user',

30

'access:servers!user'

31

]

32

},

33

'admin': {

34

'description': 'Unrestricted administrative privileges',

35

'scopes': ['admin:*']

36

},

37

'server': {

38

'description': 'Permissions for single-user servers',

39

'scopes': [

40

'access:servers!user',

41

'read:users:activity!user',

42

'read:servers!user'

43

]

44

},

45

'token': {

46

'description': 'Default permissions for API tokens',

47

'scopes': ['identify']

48

}

49

}

50

```

51

52

### Scope Definitions

53

54

Complete scope system defining all available permissions in JupyterHub.

55

56

```python { .api }

57

# Dictionary of all available scopes with descriptions

58

scope_definitions: Dict[str, str] = {

59

# Administrative scopes

60

'admin:*': 'Full administrative privileges (all permissions)',

61

'admin:users': 'Full user administration',

62

'admin:groups': 'Full group administration',

63

'admin:servers': 'Full server administration',

64

'admin:auth': 'Authentication administration',

65

66

# User management scopes

67

'users': 'Full user management (read/write)',

68

'users:activity': 'Read user activity information',

69

'read:users': 'Read user information',

70

'read:users:name': 'Read usernames',

71

'read:users:groups': 'Read user group membership',

72

'read:users:activity': 'Read user activity timestamps',

73

74

# Group management scopes

75

'groups': 'Full group management (read/write)',

76

'read:groups': 'Read group information',

77

'read:groups:name': 'Read group names',

78

79

# Server management scopes

80

'servers': 'Full server management (read/write/delete)',

81

'read:servers': 'Read server information',

82

'access:servers': 'Access servers (connect to running servers)',

83

'delete:servers': 'Stop/delete servers',

84

85

# Service scopes

86

'services': 'Full service management',

87

'read:services': 'Read service information',

88

89

# Role and token scopes

90

'roles': 'Full role management',

91

'read:roles': 'Read role information',

92

'tokens': 'Full token management',

93

'read:tokens': 'Read token information',

94

95

# Proxy scopes

96

'proxy': 'Full proxy management',

97

'read:proxy': 'Read proxy routing information',

98

99

# Hub scopes

100

'read:hub': 'Read hub information',

101

'shutdown': 'Shutdown the hub',

102

103

# Special scopes

104

'self': 'User\'s own resources (expands to user-specific scopes)',

105

'identify': 'Identify the token owner',

106

'inherit': 'Inherit permissions from user/service'

107

}

108

109

# Scope expansion functions

110

def expand_scopes(*scopes) -> Set[str]:

111

"""

112

Expand scope patterns into concrete scopes.

113

114

Args:

115

*scopes: Variable number of scope strings

116

117

Returns:

118

Set of expanded concrete scopes

119

"""

120

121

def check_scopes(required_scopes, available_scopes) -> bool:

122

"""

123

Check if available scopes satisfy required scopes.

124

125

Args:

126

required_scopes: Scopes needed for operation

127

available_scopes: Scopes granted to user/token

128

129

Returns:

130

True if access should be granted

131

"""

132

133

def describe_scope(scope: str) -> str:

134

"""

135

Get human-readable description of a scope.

136

137

Args:

138

scope: Scope string

139

140

Returns:

141

Description string

142

"""

143

```

144

145

### Role Assignment and Inheritance

146

147

Functions for assigning roles and managing permission inheritance.

148

149

```python { .api }

150

class Role(Base):

151

"""Role database model with permission management"""

152

153

name: str

154

description: str

155

scopes: List[str]

156

157

def has_scope(self, scope: str) -> bool:

158

"""

159

Check if role has specific scope.

160

161

Args:

162

scope: Scope to check

163

164

Returns:

165

True if role grants this scope

166

"""

167

168

def grant_scope(self, scope: str) -> None:

169

"""

170

Grant a scope to this role.

171

172

Args:

173

scope: Scope to grant

174

"""

175

176

def revoke_scope(self, scope: str) -> None:

177

"""

178

Revoke a scope from this role.

179

180

Args:

181

scope: Scope to revoke

182

"""

183

184

# Permission inheritance functions

185

def get_user_scopes(user: User) -> Set[str]:

186

"""

187

Get all scopes for a user (direct + inherited from groups/roles).

188

189

Args:

190

user: User object

191

192

Returns:

193

Set of all scopes available to user

194

"""

195

196

def get_token_scopes(token: APIToken) -> Set[str]:

197

"""

198

Get all scopes for an API token.

199

200

Args:

201

token: API token object

202

203

Returns:

204

Set of scopes granted to token

205

"""

206

```

207

208

## Usage Examples

209

210

### Basic Role Assignment

211

212

```python

213

from jupyterhub.orm import User, Group, Role

214

from jupyterhub.scopes import get_default_roles

215

216

# Create custom role

217

instructor_role = Role(

218

name='instructor',

219

description='Course instructor permissions',

220

scopes=[

221

'read:users',

222

'read:users:activity',

223

'servers!group=students',

224

'access:servers!group=students'

225

]

226

)

227

db.add(instructor_role)

228

229

# Assign role to user

230

instructor = db.query(User).filter(User.name == 'prof_smith').first()

231

instructor.roles.append(instructor_role)

232

db.commit()

233

```

234

235

### Group-based Permissions

236

237

```python

238

# Create student group with role

239

students_group = Group(name='students')

240

student_role = Role(

241

name='student',

242

description='Student permissions',

243

scopes=[

244

'self', # Own resources

245

'read:groups:name!group=students' # Read group member names

246

]

247

)

248

students_group.roles.append(student_role)

249

250

# Add users to group

251

alice = db.query(User).filter(User.name == 'alice').first()

252

students_group.users.append(alice)

253

db.commit()

254

```

255

256

### Service Permissions

257

258

```python

259

# Create service with specific permissions

260

monitoring_service = Service(

261

name='monitoring',

262

url='http://localhost:8002'

263

)

264

265

monitoring_role = Role(

266

name='monitoring-service',

267

description='Monitoring service permissions',

268

scopes=[

269

'read:users:activity',

270

'read:servers',

271

'read:hub'

272

]

273

)

274

monitoring_service.roles.append(monitoring_role)

275

276

# Create API token for service

277

token = monitoring_service.new_api_token(

278

note='Monitoring service token',

279

roles=['monitoring-service']

280

)

281

db.commit()

282

```

283

284

### Custom Scope Patterns

285

286

```python

287

# Scoped permissions using filters

288

custom_scopes = [

289

'servers!user=alice', # Alice's servers only

290

'read:users!group=students', # Users in students group

291

'access:servers!server=shared-*', # Servers with shared- prefix

292

'admin:users!user!=admin' # All users except admin

293

]

294

295

# Create role with scoped permissions

296

ta_role = Role(

297

name='teaching-assistant',

298

description='TA permissions for specific course',

299

scopes=[

300

'read:users!group=cs101-students',

301

'servers!group=cs101-students',

302

'read:users:activity!group=cs101-students'

303

]

304

)

305

```

306

307

### Token Scoping

308

309

```python

310

# Create limited-scope API token

311

user = db.query(User).filter(User.name == 'researcher').first()

312

limited_token = user.new_api_token(

313

note='Data analysis token',

314

scopes=[

315

'read:servers!user', # Only own servers

316

'access:servers!user', # Access own servers

317

'read:users:name' # Read usernames for sharing

318

],

319

expires_in=3600 # 1 hour expiration

320

)

321

```

322

323

## Advanced RBAC Patterns

324

325

### Hierarchical Permissions

326

327

```python

328

# Create hierarchy of roles

329

roles_hierarchy = {

330

'student': [

331

'self',

332

'read:groups:name'

333

],

334

'ta': [

335

'inherit:student', # Inherit student permissions

336

'read:users!group=assigned-students',

337

'servers!group=assigned-students'

338

],

339

'instructor': [

340

'inherit:ta', # Inherit TA permissions

341

'admin:users!group=course-students',

342

'admin:servers!group=course-students'

343

],

344

'admin': [

345

'admin:*' # Full admin access

346

]

347

}

348

349

# Apply hierarchical roles

350

for role_name, scopes in roles_hierarchy.items():

351

role = Role(name=role_name, scopes=scopes)

352

db.add(role)

353

```

354

355

### Conditional Permissions

356

357

```python

358

class ConditionalRole(Role):

359

"""Role with time-based or context-based conditions"""

360

361

conditions: Dict[str, Any] # Additional conditions

362

363

def check_conditions(self, context: Dict[str, Any]) -> bool:

364

"""

365

Check if role conditions are met.

366

367

Args:

368

context: Current request context

369

370

Returns:

371

True if conditions are satisfied

372

"""

373

# Time-based conditions

374

if 'time_range' in self.conditions:

375

current_time = datetime.now().time()

376

start, end = self.conditions['time_range']

377

if not (start <= current_time <= end):

378

return False

379

380

# IP-based conditions

381

if 'allowed_ips' in self.conditions:

382

client_ip = context.get('client_ip')

383

if client_ip not in self.conditions['allowed_ips']:

384

return False

385

386

return True

387

388

# Usage with conditions

389

lab_access_role = ConditionalRole(

390

name='lab-access',

391

scopes=['access:servers!server=lab-*'],

392

conditions={

393

'time_range': (time(9, 0), time(17, 0)), # 9 AM - 5 PM

394

'allowed_ips': ['192.168.1.0/24'] # Lab network only

395

}

396

)

397

```

398

399

### Dynamic Role Assignment

400

401

```python

402

async def assign_dynamic_roles(user: User, authenticator_data: Dict[str, Any]):

403

"""

404

Dynamically assign roles based on authentication data.

405

406

Args:

407

user: User object

408

authenticator_data: Data from authenticator (LDAP groups, OAuth claims, etc.)

409

"""

410

411

# Clear existing dynamic roles

412

user.roles = [role for role in user.roles if not role.name.startswith('dynamic-')]

413

414

# Assign roles based on LDAP groups

415

ldap_groups = authenticator_data.get('groups', [])

416

417

role_mapping = {

418

'faculty': 'instructor',

419

'graduate_students': 'ta',

420

'undergraduate_students': 'student'

421

}

422

423

for ldap_group, role_name in role_mapping.items():

424

if ldap_group in ldap_groups:

425

role = db.query(Role).filter(Role.name == role_name).first()

426

if role:

427

user.roles.append(role)

428

429

db.commit()

430

```

431

432

## Permission Checking

433

434

### API Permission Decorators

435

436

```python

437

from jupyterhub.scopes import needs_scope

438

439

class CustomAPIHandler(APIHandler):

440

"""API handler with scope-based permissions"""

441

442

@needs_scope('read:users')

443

def get(self):

444

"""Endpoint requiring read:users scope"""

445

users = self.db.query(User).all()

446

self.write({'users': [user.name for user in users]})

447

448

@needs_scope('admin:users')

449

def post(self):

450

"""Endpoint requiring admin:users scope"""

451

user_data = self.get_json_body()

452

user = User(**user_data)

453

self.db.add(user)

454

self.db.commit()

455

```

456

457

### Programmatic Permission Checks

458

459

```python

460

from jupyterhub.scopes import check_scopes

461

462

def check_user_permission(user: User, required_scope: str, resource: str = None) -> bool:

463

"""

464

Check if user has permission for specific operation.

465

466

Args:

467

user: User object

468

required_scope: Scope needed for operation

469

resource: Optional resource identifier

470

471

Returns:

472

True if user has permission

473

"""

474

user_scopes = get_user_scopes(user)

475

476

# Add resource context if provided

477

if resource:

478

required_scope = f"{required_scope}!{resource}"

479

480

return check_scopes([required_scope], user_scopes)

481

482

# Usage

483

if check_user_permission(user, 'servers', 'user=alice'):

484

# User can manage Alice's servers

485

pass

486

```

487

488

## Configuration Examples

489

490

### Role-based Hub Configuration

491

492

```python

493

# jupyterhub_config.py

494

495

# Define custom roles

496

c.JupyterHub.custom_roles = [

497

{

498

'name': 'instructor',

499

'description': 'Course instructor permissions',

500

'scopes': [

501

'read:users!group=students',

502

'servers!group=students',

503

'admin:users!group=students'

504

]

505

},

506

{

507

'name': 'grader',

508

'description': 'Grading assistant permissions',

509

'scopes': [

510

'read:users!group=students',

511

'access:servers!group=students'

512

]

513

}

514

]

515

516

# Load balancing with role-based spawning

517

c.JupyterHub.load_roles = [

518

{

519

'name': 'instructor',

520

'users': ['prof_smith', 'prof_jones'],

521

'scopes': ['inherit:instructor']

522

},

523

{

524

'name': 'grader',

525

'groups': ['teaching-assistants'],

526

'scopes': ['inherit:grader']

527

}

528

]

529

```