Very fast asynchronous FTP server library providing RFC-959 compliant FTP servers with advanced features including FTPS, IPv6, Unicode support, and flexible authentication systems
—
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.
Basic authorizer for managing virtual users with in-memory user database, suitable for most FTP server deployments.
class DummyAuthorizer:
# Permission constants
read_perms: str = "elr" # Read permissions: examine, list, retrieve
write_perms: str = "adfmwMT" # Write permissions: append, delete, file/mkdir, write, modify time
def __init__(self):
"""Initialize empty user database."""
def add_user(self, username, password, homedir, perm='elr', msg_login="Login successful.", msg_quit="Goodbye."):
"""
Add virtual user to database.
Parameters:
- username: user login name
- password: user password
- homedir: user home directory path
- perm: permission string (combination of elradfmwMT)
- msg_login: custom login message
- msg_quit: custom quit message
"""
def add_anonymous(self, homedir, **kwargs):
"""
Add anonymous user access.
Parameters:
- homedir: anonymous user home directory
- **kwargs: same options as add_user() except username/password
"""
def remove_user(self, username):
"""Remove user from database."""
def override_perm(self, username, directory, perm, recursive=False):
"""
Override permissions for specific directory.
Parameters:
- username: target user
- directory: directory path (relative to user home)
- perm: permission string to override
- recursive: apply to subdirectories
"""
def validate_authentication(self, username, password, handler):
"""
Validate user credentials.
Parameters:
- username: provided username
- password: provided password
- handler: FTPHandler instance
Raises:
- AuthenticationFailed: if credentials invalid
"""
def get_home_dir(self, username):
"""Get user home directory path."""
def impersonate_user(self, username, password):
"""Impersonate user (no-op in DummyAuthorizer)."""
def terminate_impersonation(self, username):
"""Terminate user impersonation (no-op in DummyAuthorizer)."""
def has_user(self, username):
"""Check if user exists in database."""
def has_perm(self, username, perm, path=None):
"""
Check if user has specific permission.
Parameters:
- username: user to check
- perm: permission letter (e,l,r,a,d,f,m,w,M,T)
- path: optional path for directory-specific permissions
"""
def get_perms(self, username):
"""Get user permission string."""
def get_msg_login(self, username):
"""Get user login message."""
def get_msg_quit(self, username):
"""Get user quit message."""Authorizer that authenticates against Unix system users, providing integration with existing system accounts. Available on POSIX systems only.
class BaseUnixAuthorizer: # POSIX only
def __init__(self, anonymous_user=None):
"""
Initialize Unix authorizer.
Parameters:
- anonymous_user: system user for anonymous access (optional)
"""
def validate_authentication(self, username, password, handler):
"""Authenticate against system shadow database."""
def impersonate_user(self, username, password):
"""Change effective UID/GID to match system user."""
def terminate_impersonation(self, username):
"""Revert to original UID/GID."""
def has_user(self, username):
"""Check if system user exists."""
def get_home_dir(self, username):
"""Get system user home directory from passwd database."""
class UnixAuthorizer(BaseUnixAuthorizer): # POSIX only
def __init__(self, global_perm="elradfmwMT", allowed_users=None, rejected_users=None,
require_valid_shell=True, anonymous_user=None, msg_login="Login successful.",
msg_quit="Goodbye."):
"""
Initialize Unix authorizer with access controls.
Parameters:
- global_perm: default permissions for all users
- allowed_users: list/set of allowed usernames (None = all allowed)
- rejected_users: list/set of rejected usernames
- require_valid_shell: require valid shell in /etc/shells
- anonymous_user: system user for anonymous access
- msg_login/msg_quit: default messages
"""Authorizer that authenticates against Windows system users using Windows API. Available on Windows only.
class BaseWindowsAuthorizer: # Windows only
def __init__(self, anonymous_user=None):
"""
Initialize Windows authorizer.
Parameters:
- anonymous_user: Windows user for anonymous access (optional)
"""
def validate_authentication(self, username, password, handler):
"""Authenticate against Windows user database."""
def impersonate_user(self, username, password):
"""Impersonate Windows user account."""
def terminate_impersonation(self, username):
"""End user impersonation."""
class WindowsAuthorizer(BaseWindowsAuthorizer): # Windows only
def __init__(self, global_perm="elradfmwMT", allowed_users=None, rejected_users=None,
anonymous_user=None, msg_login="Login successful.", msg_quit="Goodbye."):
"""Initialize Windows authorizer with same parameters as UnixAuthorizer."""class AuthorizerError(Exception):
"""Base class for authorizer-related exceptions."""
class AuthenticationFailed(Exception):
"""Raised when user authentication fails."""def replace_anonymous(callable):
"""
Decorator to replace anonymous user references.
Used internally for handling anonymous user in system authorizers.
"""from pyftpdlib.authorizers import DummyAuthorizer
authorizer = DummyAuthorizer()
# Full access user
authorizer.add_user("admin", "secret", "/home/admin", perm="elradfmwMT")
# Read-only user
authorizer.add_user("guest", "guest", "/home/guest", perm="elr")
# User with limited write access (no delete)
authorizer.add_user("upload", "pass", "/home/upload", perm="elrafmwMT")
# Anonymous read-only access
authorizer.add_anonymous("/home/public", perm="elr")authorizer = DummyAuthorizer()
authorizer.add_user("user", "pass", "/home/user", perm="elr")
# Allow write access only to uploads directory
authorizer.override_perm("user", "uploads", "elradfmwMT", recursive=True)
# Allow delete access only to temp directory
authorizer.override_perm("user", "temp", "elrd")from pyftpdlib.authorizers import UnixAuthorizer
# Allow all system users with valid shells
authorizer = UnixAuthorizer()
# Restrict to specific users only
authorizer = UnixAuthorizer(
allowed_users=["john", "jane", "bob"],
require_valid_shell=True
)
# Block specific users
authorizer = UnixAuthorizer(
rejected_users=["root", "daemon", "nobody"],
global_perm="elr" # Read-only for all users
)
# Enable anonymous access using 'ftp' system user
authorizer = UnixAuthorizer(anonymous_user="ftp")from pyftpdlib.authorizers import WindowsAuthorizer
# Allow all Windows users
authorizer = WindowsAuthorizer()
# Restrict access and enable anonymous
authorizer = WindowsAuthorizer(
allowed_users=["Administrator", "User1"],
anonymous_user="Guest",
global_perm="elr"
)class CustomAuthorizer(DummyAuthorizer):
def validate_authentication(self, username, password, handler):
# Custom authentication logic (database, LDAP, etc.)
if self.authenticate_user(username, password):
return
raise AuthenticationFailed("Invalid credentials")
def has_perm(self, username, perm, path=None):
# Custom permission logic
if path and path.startswith("/restricted/"):
return False
return super().has_perm(username, perm, path)from pyftpdlib.handlers import FTPHandler
# Assign authorizer to handler
handler = FTPHandler
handler.authorizer = authorizer
# Or subclass for custom behavior
class CustomFTPHandler(FTPHandler):
authorizer = authorizer
def on_login(self, username):
print(f"User {username} logged in from {self.remote_ip}")Install with Tessl CLI
npx tessl i tessl/pypi-pyftpdlib