0
# Authentication & Authorization
1
2
User authentication and permission management systems providing flexible approaches to FTP user management. pyftpdlib supports virtual users, system users, and custom authorization schemes with fine-grained permission control.
3
4
## Capabilities
5
6
### Virtual User Authorization
7
8
Basic authorizer for managing virtual users with in-memory user database, suitable for most FTP server deployments.
9
10
```python { .api }
11
class DummyAuthorizer:
12
# Permission constants
13
read_perms: str = "elr" # Read permissions: examine, list, retrieve
14
write_perms: str = "adfmwMT" # Write permissions: append, delete, file/mkdir, write, modify time
15
16
def __init__(self):
17
"""Initialize empty user database."""
18
19
def add_user(self, username, password, homedir, perm='elr', msg_login="Login successful.", msg_quit="Goodbye."):
20
"""
21
Add virtual user to database.
22
23
Parameters:
24
- username: user login name
25
- password: user password
26
- homedir: user home directory path
27
- perm: permission string (combination of elradfmwMT)
28
- msg_login: custom login message
29
- msg_quit: custom quit message
30
"""
31
32
def add_anonymous(self, homedir, **kwargs):
33
"""
34
Add anonymous user access.
35
36
Parameters:
37
- homedir: anonymous user home directory
38
- **kwargs: same options as add_user() except username/password
39
"""
40
41
def remove_user(self, username):
42
"""Remove user from database."""
43
44
def override_perm(self, username, directory, perm, recursive=False):
45
"""
46
Override permissions for specific directory.
47
48
Parameters:
49
- username: target user
50
- directory: directory path (relative to user home)
51
- perm: permission string to override
52
- recursive: apply to subdirectories
53
"""
54
55
def validate_authentication(self, username, password, handler):
56
"""
57
Validate user credentials.
58
59
Parameters:
60
- username: provided username
61
- password: provided password
62
- handler: FTPHandler instance
63
64
Raises:
65
- AuthenticationFailed: if credentials invalid
66
"""
67
68
def get_home_dir(self, username):
69
"""Get user home directory path."""
70
71
def impersonate_user(self, username, password):
72
"""Impersonate user (no-op in DummyAuthorizer)."""
73
74
def terminate_impersonation(self, username):
75
"""Terminate user impersonation (no-op in DummyAuthorizer)."""
76
77
def has_user(self, username):
78
"""Check if user exists in database."""
79
80
def has_perm(self, username, perm, path=None):
81
"""
82
Check if user has specific permission.
83
84
Parameters:
85
- username: user to check
86
- perm: permission letter (e,l,r,a,d,f,m,w,M,T)
87
- path: optional path for directory-specific permissions
88
"""
89
90
def get_perms(self, username):
91
"""Get user permission string."""
92
93
def get_msg_login(self, username):
94
"""Get user login message."""
95
96
def get_msg_quit(self, username):
97
"""Get user quit message."""
98
```
99
100
### Unix System User Authorization
101
102
Authorizer that authenticates against Unix system users, providing integration with existing system accounts. Available on POSIX systems only.
103
104
```python { .api }
105
class BaseUnixAuthorizer: # POSIX only
106
def __init__(self, anonymous_user=None):
107
"""
108
Initialize Unix authorizer.
109
110
Parameters:
111
- anonymous_user: system user for anonymous access (optional)
112
"""
113
114
def validate_authentication(self, username, password, handler):
115
"""Authenticate against system shadow database."""
116
117
def impersonate_user(self, username, password):
118
"""Change effective UID/GID to match system user."""
119
120
def terminate_impersonation(self, username):
121
"""Revert to original UID/GID."""
122
123
def has_user(self, username):
124
"""Check if system user exists."""
125
126
def get_home_dir(self, username):
127
"""Get system user home directory from passwd database."""
128
129
class UnixAuthorizer(BaseUnixAuthorizer): # POSIX only
130
def __init__(self, global_perm="elradfmwMT", allowed_users=None, rejected_users=None,
131
require_valid_shell=True, anonymous_user=None, msg_login="Login successful.",
132
msg_quit="Goodbye."):
133
"""
134
Initialize Unix authorizer with access controls.
135
136
Parameters:
137
- global_perm: default permissions for all users
138
- allowed_users: list/set of allowed usernames (None = all allowed)
139
- rejected_users: list/set of rejected usernames
140
- require_valid_shell: require valid shell in /etc/shells
141
- anonymous_user: system user for anonymous access
142
- msg_login/msg_quit: default messages
143
"""
144
```
145
146
### Windows System User Authorization
147
148
Authorizer that authenticates against Windows system users using Windows API. Available on Windows only.
149
150
```python { .api }
151
class BaseWindowsAuthorizer: # Windows only
152
def __init__(self, anonymous_user=None):
153
"""
154
Initialize Windows authorizer.
155
156
Parameters:
157
- anonymous_user: Windows user for anonymous access (optional)
158
"""
159
160
def validate_authentication(self, username, password, handler):
161
"""Authenticate against Windows user database."""
162
163
def impersonate_user(self, username, password):
164
"""Impersonate Windows user account."""
165
166
def terminate_impersonation(self, username):
167
"""End user impersonation."""
168
169
class WindowsAuthorizer(BaseWindowsAuthorizer): # Windows only
170
def __init__(self, global_perm="elradfmwMT", allowed_users=None, rejected_users=None,
171
anonymous_user=None, msg_login="Login successful.", msg_quit="Goodbye."):
172
"""Initialize Windows authorizer with same parameters as UnixAuthorizer."""
173
```
174
175
## Exception Classes
176
177
```python { .api }
178
class AuthorizerError(Exception):
179
"""Base class for authorizer-related exceptions."""
180
181
class AuthenticationFailed(Exception):
182
"""Raised when user authentication fails."""
183
```
184
185
## Utility Functions
186
187
```python { .api }
188
def replace_anonymous(callable):
189
"""
190
Decorator to replace anonymous user references.
191
Used internally for handling anonymous user in system authorizers.
192
"""
193
```
194
195
## Permission System
196
197
### Permission Letters
198
199
- **e** - examine: Change directory (CWD, CDUP commands)
200
- **l** - list: List directory contents (LIST, NLST, STAT commands)
201
- **r** - retrieve: Download files (RETR command)
202
- **a** - append: Append to files (APPE command)
203
- **d** - delete: Delete files and directories (DELE, RMD commands)
204
- **f** - file operations: Create files, rename (STOR, MKD, RNFR, RNTO commands)
205
- **m** - mode: Change file mode/permissions (SITE CHMOD command)
206
- **w** - write: Full write access (covers adf permissions)
207
- **M** - modify: Change file modification time (MFMT command)
208
- **T** - transfer mode: Change transfer mode (MODE, STRU, TYPE commands)
209
210
### Common Permission Combinations
211
212
- **"elr"** - Read-only access (browse and download)
213
- **"elradfmwMT"** - Full access (all permissions)
214
- **"elrw"** - Read and write access (equivalent to elradfm)
215
216
## Usage Examples
217
218
### Virtual Users with Different Permissions
219
220
```python
221
from pyftpdlib.authorizers import DummyAuthorizer
222
223
authorizer = DummyAuthorizer()
224
225
# Full access user
226
authorizer.add_user("admin", "secret", "/home/admin", perm="elradfmwMT")
227
228
# Read-only user
229
authorizer.add_user("guest", "guest", "/home/guest", perm="elr")
230
231
# User with limited write access (no delete)
232
authorizer.add_user("upload", "pass", "/home/upload", perm="elrafmwMT")
233
234
# Anonymous read-only access
235
authorizer.add_anonymous("/home/public", perm="elr")
236
```
237
238
### Directory-Specific Permissions
239
240
```python
241
authorizer = DummyAuthorizer()
242
authorizer.add_user("user", "pass", "/home/user", perm="elr")
243
244
# Allow write access only to uploads directory
245
authorizer.override_perm("user", "uploads", "elradfmwMT", recursive=True)
246
247
# Allow delete access only to temp directory
248
authorizer.override_perm("user", "temp", "elrd")
249
```
250
251
### Unix System Users
252
253
```python
254
from pyftpdlib.authorizers import UnixAuthorizer
255
256
# Allow all system users with valid shells
257
authorizer = UnixAuthorizer()
258
259
# Restrict to specific users only
260
authorizer = UnixAuthorizer(
261
allowed_users=["john", "jane", "bob"],
262
require_valid_shell=True
263
)
264
265
# Block specific users
266
authorizer = UnixAuthorizer(
267
rejected_users=["root", "daemon", "nobody"],
268
global_perm="elr" # Read-only for all users
269
)
270
271
# Enable anonymous access using 'ftp' system user
272
authorizer = UnixAuthorizer(anonymous_user="ftp")
273
```
274
275
### Windows System Users
276
277
```python
278
from pyftpdlib.authorizers import WindowsAuthorizer
279
280
# Allow all Windows users
281
authorizer = WindowsAuthorizer()
282
283
# Restrict access and enable anonymous
284
authorizer = WindowsAuthorizer(
285
allowed_users=["Administrator", "User1"],
286
anonymous_user="Guest",
287
global_perm="elr"
288
)
289
```
290
291
### Custom Authorizer
292
293
```python
294
class CustomAuthorizer(DummyAuthorizer):
295
def validate_authentication(self, username, password, handler):
296
# Custom authentication logic (database, LDAP, etc.)
297
if self.authenticate_user(username, password):
298
return
299
raise AuthenticationFailed("Invalid credentials")
300
301
def has_perm(self, username, perm, path=None):
302
# Custom permission logic
303
if path and path.startswith("/restricted/"):
304
return False
305
return super().has_perm(username, perm, path)
306
```
307
308
## Integration with FTP Handlers
309
310
```python
311
from pyftpdlib.handlers import FTPHandler
312
313
# Assign authorizer to handler
314
handler = FTPHandler
315
handler.authorizer = authorizer
316
317
# Or subclass for custom behavior
318
class CustomFTPHandler(FTPHandler):
319
authorizer = authorizer
320
321
def on_login(self, username):
322
print(f"User {username} logged in from {self.remote_ip}")
323
```