Configuration¶
This document describes the configuration options of a WsgiDAV server.
The WsgiDAVApp
object is configured by passing
a Python dict
with distinct options, that define
- Server options (hostname, port, SSL cert, …)
- List of share-name / WebDAV provider mappings
- Optional list of users for authentication
- Optional custom DAV providers (i.e. other than FilesystemProvider)
- Optional custom lock manager, property manager and domain controller
- Advanced debugging options
- (and more)
This section shows the available options and defaults:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # -*- coding: utf-8 -*-
# (c) 2009-2021 Martin Wendt and contributors; see WsgiDAV https://github.com/mar10/wsgidav
# Original PyFileServer (c) 2005 Ho Chun Wei.
# Licensed under the MIT license:
# http://www.opensource.org/licenses/mit-license.php
r"""
::
_ __ _ ___ ___ _ __
| | /| / /__ ___ (_) _ \/ _ | | / /
| |/ |/ (_-</ _ `/ / // / __ | |/ /
|__/|__/___/\_, /_/____/_/ |_|___/
/___/
Default confguration.
"""
from wsgidav.debug_filter import WsgiDavDebugFilter
from wsgidav.dir_browser import WsgiDavDirBrowser
from wsgidav.error_printer import ErrorPrinter
from wsgidav.http_authenticator import HTTPAuthenticator
from wsgidav.request_resolver import RequestResolver
__docformat__ = "reStructuredText"
# Use these settings, if config file does not define them (or is totally missing)
DEFAULT_VERBOSE = 3
DEFAULT_CONFIG = {
"server": "cheroot",
"server_args": {},
"host": "localhost",
"port": 8080,
"mount_path": None, # Application root, e.g. <mount_path>/<share_name>/<res_path>
"provider_mapping": {},
"add_header_MS_Author_Via": True,
"hotfixes": {
"emulate_win32_lastmod": False, # True: support Win32LastModifiedTime
"re_encode_path_info": None, # (See issue #73) None: activate on Python 3
"unquote_path_info": False, # See issue #8
"win_accept_anonymous_options": False,
"winxp_accept_root_share_login": False, # Was True in v2.4
},
"property_manager": None, # True: use property_manager.PropertyManager
"mutable_live_props": [],
"lock_manager": True, # True: use lock_manager.LockManager
"middleware_stack": [
WsgiDavDebugFilter,
ErrorPrinter,
HTTPAuthenticator,
WsgiDavDirBrowser, # configured under dir_browser option (see below)
RequestResolver, # this must be the last middleware item
],
# HTTP Authentication Options
"http_authenticator": {
# None: dc.simple_dc.SimpleDomainController(user_mapping)
"domain_controller": None,
"accept_basic": True, # Allow basic authentication, True or False
"accept_digest": True, # Allow digest authentication, True or False
"default_to_digest": True, # True (default digest) or False (default basic)
# Name of a header field that will be accepted as authorized user
"trusted_auth_header": None,
},
#: Used by SimpleDomainController only
"simple_dc": {"user_mapping": {}}, # NO anonymous access by default
# Verbose Output
# 0 - no output
# 1 - no output (excepting application exceptions)
# 2 - show warnings
# 3 - show single line request summaries (for HTTP logging)
# 4 - show additional events
# 5 - show full request/response header info (HTTP Logging)
# request body and GET response bodies not shown
"verbose": DEFAULT_VERBOSE,
# Error printer options
"error_printer": {"catch_all": True}, # False,
"enable_loggers": [],
"dir_browser": {
"enable": True, # Render HTML listing for GET requests on collections
# List of fnmatch patterns:
"ignore": [
".DS_Store", # macOS folder meta data
"._*", # macOS hidden data files
"Thumbs.db", # Windows image previews
],
"icon": True,
"response_trailer": True, # Raw HTML code, appended as footer (True: use a default)
"show_user": True, # Show authenticated user an realm
# Send <dm:mount> response if request URL contains '?davmount'
"davmount": False,
# Add an 'open as webfolder' link (requires Windows clients):
"ms_mount": False,
"ms_sharepoint_support": True, # Invoke MS Offce documents for editing using WebDAV
# "ms_sharepoint_plugin": False, # Invoke MS Offce documents for editing using WebDAV
# "ms_sharepoint_urls": False, # Prepend 'ms-word:ofe|u|' to URL for MS Offce documents
# The path to the directory that contains template.html and associated assets.
# The default is the htdocs directory within the dir_browser directory.
"htdocs_path": None,
},
}
|
When a Python dict is passed to the WsgiDAVApp
constructor, its values will override the defaults from above:
root_path = gettempdir()
provider = FilesystemProvider(root_path)
config = {
"host": "0.0.0.0",
"port": 8080,
"provider_mapping": {"/": provider},
"verbose": 1,
}
app = WsgiDAVApp(config)
Use a Configuration File¶
When running from the CLI (command line interface), some settings may be passed as arguments, e.g.:
$ wsgidav --host=0.0.0.0 --port=8080 --root=/tmp --auth=anonymous
Serving on http://0.0.0.0:8080 ...
Much more options are available when a configuration file is used.
By default wsgidav.yaml
, wsgidav.json
, and wsgidav.conf
are searched in the
local directory.
An alternative file name can be specified like so:
$ wsgidav --config=my_config.yaml
To prevent the use of of a local default configuration file, use this option:
$ wsgidav --no-config
The options described below can be defined for the CLI either
Note
The three supported file formats are just different ways for the CLI to
generate a Python dict that is then passed to the
WsgiDAVApp
constructor.
The YAML format is recommended.
For a start, copy
YAML Sample Configuration
and edit it to your needs.
(Alternatively use
JSON Sample Configuration
or
Python Sample Configuration
.)
Verbosity Level¶
The verbosity level can have a value from 0 to 5 (default: 3):
Verbosity | Option | Log level | Remarks |
---|---|---|---|
0 | -qqq | CRITICAL | quiet |
1 | ERROR | no output (excepting application exceptions) | |
2 | -q | WARN | warnings and errors only |
3 | INFO | show single line request summaries (for HTTP logging) | |
4 | -v | DEBUG | show additional events |
5 | -vv | DEBUG | show full request/response header info (HTTP Logging) request body and GET response bodies not shown |
Middleware Stack¶
WsgiDAV is built as WSGI application (WsgiDAVApp
)
that is extended by a list of middleware components which implement additional
functionality.
This stack is defined as a list of WSGI compliant application instances, e.g.:
from wsgidav.debug_filter import WsgiDavDebugFilter
debug_filter = WsgiDavDebugFilter(wsgidav_app, next_app, config)
conf = {
...
"middleware_stack": [
debug_filter,
...
],
...
}
If the middleware class constructor has a common signature, it is sufficient to
pass the class instead of the instantiated object.
The built-in middleware derives from BaseMiddleware
,
so we can simplify as:
from wsgidav.dir_browser import WsgiDavDirBrowser
from wsgidav.debug_filter import WsgiDavDebugFilter
from wsgidav.error_printer import ErrorPrinter
from wsgidav.http_authenticator import HTTPAuthenticator
from wsgidav.request_resolver import RequestResolver
conf = {
...
"middleware_stack": [
WsgiDavDebugFilter,
ErrorPrinter,
HTTPAuthenticator,
WsgiDavDirBrowser,
RequestResolver, # this must be the last middleware item
],
...
}
The middleware stack can be configured and extended. The following example removes the directory browser, and adds a third-party debugging tool:
import dozer
# from wsgidav.dir_browser import WsgiDavDirBrowser
from wsgidav.debug_filter import WsgiDavDebugFilter
from wsgidav.error_printer import ErrorPrinter
from wsgidav.http_authenticator import HTTPAuthenticator
from wsgidav.request_resolver import RequestResolver
# Enable online profiling and GC inspection. See https://github.com/mgedmin/dozer
# (Requires `pip install Dozer`):
dozer_app = dozer.Dozer(wsgidav_app)
dozer_profiler = dozer.Profiler(dozer_app, None, "/tmp")
conf = {
...
"middleware_stack": [
dozer_app,
dozer_profiler,
WsgiDavDebugFilter,
ErrorPrinter,
HTTPAuthenticator,
# WsgiDavDirBrowser,
RequestResolver, # this must be the last middleware item
],
...
}
The stack can also be defined in text files, for example YAML. Again, we can pass an import path for a WSGI compliant class if the signature is known. For third-party middleware however, the constructor’s positional arguments should be explicitly listed:
...
middleware_stack:
- dozer.Dozer:
- "${application}"
- dozer.Profiler:
- "${application}"
- null # global_conf
- /tmp # profile_path
- wsgidav.debug_filter.WsgiDavDebugFilter
- wsgidav.error_printer.ErrorPrinter
- wsgidav.http_authenticator.HTTPAuthenticator
- wsgidav.dir_browser.WsgiDavDirBrowser
- wsgidav.request_resolver.RequestResolver
Note that the external middleware must be available, for example by calling
pip install Doze
, so this will not be possible if WsgiDAV is running from
the MSI installer.
DAVProvider¶
A DAVProvider handles read and write requests for all URLs that start with a given share path.
WsgiDAV comes bundled with FilesystemProvider
, a DAVProvider that serves
DAV requests by reading and writing to the server’s file system.
However, custom DAVProviders may be implemented and used, that publish a
database backend, cloud drive, or any virtual data structure.
The provider_mapping
configuration routes share paths to specific
DAVProvider instances.
By default a writable FilesystemProvider is assumed, but can be forced to read-only. Note that a DomainController may still restrict access completely or prevent editing depending on authentication.
Three syntax variants are supported:
<mount_path>: <folder_path>
<mount_path>: { "root": <folder_path>, "readonly": <bool> }
<mount_path>: { "provider": <class_path>, "args:" ..., "kwargs": ... }
For example:
provider_mapping:
"/": "/path/to/share1"
"/home": "~"
"/pub":
root: "/path/to/share2"
readonly: true
"/share3":
provider: path.to.CustomDAVProviderClass
args: ["/path/to/share3", "second_arg"]
kwargs: {"another_arg": 42}
Property Manager¶
Todo
TODO
Lock Manager¶
Todo
TODO
Domain Controller¶
The HTTP authentication middleware relies on a domain controller. Currently three variants are supported.
SimpleDomainController¶
Allows to authenticate against a plain mapping of shares and user names.
The pseudo-share "*"
maps all URLs that are not explicitly listed.
A value of true
can be used to enable anonymous access.
Example YAML configuration:
http_authenticator:
domain_controller: null # Same as wsgidav.dc.simple_dc.SimpleDomainController
accept_basic: true # Pass false to prevent sending clear text passwords
accept_digest: true
default_to_digest: true
simple_dc:
user_mapping:
"*":
"user1":
password: "abc123"
"user2":
password: "qwerty"
"/pub": true
An optional roles list will be passed in environ[“wsgidav.auth.roles”] to downstream middleware. This is currently not used by the provided middleware, but may be handy for custom handlers:
simple_dc:
user_mapping:
"*":
"user1":
password: "abc123"
roles: ["editor", "admin"]
"user2":
password: "abc123"
roles: []
If no config file is used, anonymous authentication can be enabled on the command line like:
$ wsgidav ... --auth=anonymous
which simply defines this setting:
simple_dc:
user_mapping:
"*": true
NTDomainController¶
Allows users to authenticate against a Windows NT domain or a local computer.
The NTDomainController
requires basic authentication
and therefore should use SSL.
Example YAML configuration:
ssl_certificate: wsgidav/server/sample_bogo_server.crt
ssl_private_key: wsgidav/server/sample_bogo_server.key
ssl_certificate_chain: None
http_authenticator:
domain_controller: wsgidav.dc.nt_dc.NTDomainController
accept_basic: true
accept_digest: false
default_to_digest: false
nt_dc:
preset_domain: null
preset_server: null
If no config file is used, NT authentication can be enabled on the command line like:
$ wsgidav ... --auth=nt
PAMDomainController¶
Allows users to authenticate against a PAM (Pluggable Authentication Modules), that are at the core of user authentication in any modern linux distribution and macOS.
The PAMDomainController
requires basic
authentication and therefore should use SSL.
Example YAML configuration that authenticates users against the server’s known user accounts:
ssl_certificate: wsgidav/server/sample_bogo_server.crt
ssl_private_key: wsgidav/server/sample_bogo_server.key
ssl_certificate_chain: None
http_authenticator:
domain_controller: wsgidav.dc.pam_dc.PAMDomainController
accept_basic: true
accept_digest: false
default_to_digest: false
pam_dc:
service: "login"
If no config file is used, PAM authentication can be enabled on the command line like:
$ wsgidav ... --auth=pam-login
Sample wsgidav.yaml
¶
The YAML syntax is probably the most concise format to define configuration:
Download Sample Configuration
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | # WsgiDAV configuration file
#
# 1. Rename this file to `wsgidav.yaml`
# 2. Adjust settings as appropriate
# 3. Run `wsgidav` from the same directory or pass file path with `--config` option.
#
# See http://wsgidav.readthedocs.io/en/latest/user_guide_configure.html
#
# ============================================================================
# SERVER OPTIONS
server: "cheroot"
# Server specific arguments, for example
# cheroot: https://cheroot.cherrypy.org/en/latest/pkg/cheroot.wsgi.html#cheroot.wsgi.Server
# server_args:
# numthreads: 50
host: 0.0.0.0
port: 8080
# Add custom response headers (list of header-name / header-value tuples):
#response_headers:
# - ["Access-Control-Allow-Origin", "http://example.org"]
# Transfer block size in bytes
block_size: 8192
#: Add the MS-Author-Via Response Header to OPTIONS command to allow editing
#: with Microsoft Office (default: true)
add_header_MS_Author_Via: true
hotfixes:
winxp_accept_root_share_login: false
win_accept_anonymous_options: false
#: See issue #8
unquote_path_info: false
#: (See issue #73) Set null to activate on Python 3 only
re_encode_path_info: null
# Handle Microsoft's Win32LastModifiedTime property.
# This is useful only in the case when you copy files from a Windows
# client into a WebDAV share. Windows sends the "last modified" time of
# the file in a Microsoft extended property called "Win32LastModifiedTime"
# instead of the standard WebDAV property "getlastmodified". So without
# this config option set to "True", the "last modified" time of the copied
# file will be "now" instead of its original value.
# The proper solution for dealing with the Windows WebDAV client is to use
# a persistent property manager. This setting is merely a work-around.
# NOTE: Works with Win10, can't work with Win7. Other versions untested.
emulate_win32_lastmod: true
# ----------------------------------------------------------------------------
# SSL Support
#: The certificate should match the servers hostname, so the bogus certs will
#: not work in all scenarios.
#: (Paths can be absolute or relative to this config file.)
# ssl_certificate: "wsgidav/server/sample_bogo_server.crt"
# ssl_private_key: "wsgidav/server/sample_bogo_server.key"
# ssl_certificate_chain: null
#: Cheroot server supports 'builtin' and 'pyopenssl' (default: 'builtin')
# ssl_adapter: "pyopenssl"
# ----------------------------------------------------------------------------
#: Modify to customize the WSGI application stack:
middleware_stack:
- wsgidav.debug_filter.WsgiDavDebugFilter
- wsgidav.error_printer.ErrorPrinter
- wsgidav.http_authenticator.HTTPAuthenticator
- wsgidav.dir_browser.WsgiDavDirBrowser
- wsgidav.request_resolver.RequestResolver # this must be the last middleware item
# ==============================================================================
# SHARES
#: Application root, applied before provider mapping shares,
#: e.g. <mount_path>/<share_name>/<res_path>
mount_path: null
#: Route share paths to DAVProvider instances
#: By default a writable `FilesystemProvider` is assumed, but can be forced
#: to read-only.
#: Note that a DomainController may still restrict access completely or prevent
#: editing depending on authentication.
#: The following syntax variants are supported:
#: <mount_path>: <folder_path>
#: or
#: <mount_path>: { "root": <folder_path>, "readonly": <bool> }
#: or
#: <mount_path>: { "provider": <class_path>, "args": [<pos-args>, ...] }
provider_mapping:
"/": "/path/to/share1"
"/pub":
root: "/path/to/share2"
readonly: true
"/share3":
provider: path.to.CustomDAVProviderClass
args: ["/path/to/share3", "second_arg"]
kwargs: {"another_arg": 42}
# ==============================================================================
# AUTHENTICATION
http_authenticator:
#: Allow basic authentication
accept_basic: true
#: Allow digest authentication
accept_digest: true
#: true (default digest) or false (default basic)
default_to_digest: true
#: Header field that will be accepted as authorized user.
#: Including quotes, for example: trusted_auth_header = "REMOTE_USER"
trusted_auth_header: null
#: Domain controller that is used to resolve realms and authorization.
#: Default null: which uses SimpleDomainController and the
#: `simple_dc.user_mapping` option below.
#: (See http://wsgidav.readthedocs.io/en/latest/user_guide_configure.html
#: for details.)
domain_controller: null
# domain_controller: wsgidav.dc.simple_dc.SimpleDomainController
# domain_controller: wsgidav.dc.pam_dc.PAMDomainController
# domain_controller: wsgidav.dc.nt_dc.NTDomainController
# Additional options for SimpleDomainController only:
simple_dc:
# Access control per share.
# These routes must match the provider mapping.
# NOTE: Provider routes without a matching entry here, are inaccessible.
user_mapping:
"*": # default (used for all shares that are not explicitly listed)
"user1":
password: "abc123"
# Optional: passed to downstream middleware as environ["wsgidav.auth.roles"]
roles: ["editor"]
"user2":
password: "def456"
password: "qwerty"
"/pub": true # Pass true to allow anonymous access
# Additional options for NTDomainController only:
nt_dc:
preset_domain: null
preset_server: null
# Additional options for PAMDomainController only:
pam_dc:
service: "login"
encoding: "utf-8"
resetcreds: true
# ==============================================================================
# DEBUGGING
#: Set verbosity level (but will be overridden by -v or -q arguments)
verbose: 3
#: Set logging output format
#: (see https://docs.python.org/3/library/logging.html#logging.Formatter)
logger_format: "%(asctime)s.%(msecs)03d - <%(thread)05d> %(name)-27s %(levelname)-8s: %(message)s"
#logger_format: "%(asctime)s.%(msecs)03d - %(levelname)-8s: %(message)s"
logger_date_format: "%H:%M:%S"
#: Let ErrorPrinter middleware catch all exceptions to return as 500 Internal Error
error_printer:
catch_all: true
# Enable specific module loggers
# E.g. ["lock_manager", "property_manager", "http_authenticator", ...]
# enable_loggers: ["http_authenticator", ]
# Enable max. logging for certain http methods
# E.g. ["COPY", "DELETE", "GET", "HEAD", "LOCK", "MOVE", "OPTIONS", "PROPFIND", "PROPPATCH", "PUT", "UNLOCK"]
debug_methods: []
# Enable max. logging during litmus suite tests that contain certain strings
# E.g. ["lock_excl", "notowner_modify", "fail_cond_put_unlocked", ...]
debug_litmus: []
# ----------------------------------------------------------------------------
# WsgiDavDirBrowser
dir_browser:
enable: true
#: List of fnmatch patterns that will be hidden in the directory listing
ignore:
- ".DS_Store" # macOS folder meta data
- "Thumbs.db" # Windows image previews
- "._*" # macOS hidden data files
#: Display WsgiDAV icon in header
icon: true
#: Raw HTML code, appended as footer (true: use a default trailer)
response_trailer: true
#: Display the name and realm of the authenticated user (or 'anomymous')
show_user: true
show_logout: true
#: Send <dm:mount> response if request URL contains '?davmount'
#: Also add a respective link at the top of the listing
#: (See https://tools.ietf.org/html/rfc4709)
davmount: false
#: Add an 'open as webfolder' link (requires Windows IE <= 7!)
ms_mount: false
#: Invoke MS Office documents for editing using WebDAV by adding a JavaScript
#: click handler.
#: - For IE 11 and below invokes the SharePoint ActiveXObject("SharePoint.OpenDocuments")
#: - If the custom legacy Firefox plugin is available, it will be used
#: https://docs.microsoft.com/en-us/previous-versions/office/developer/sharepoint-2010/ff407576(v%3Doffice.14)
#: - Otherwise the Office URL prefix is used (e.g. 'ms-word:ofe|u|http://server/path/file.docx')
ms_sharepoint_support: true
#: The path to the directory that contains template.html and associated
#: assets.
#: The default is the htdocs directory within the dir_browser directory.
htdocs_path: null
# ----------------------------------------------------------------------------
# Property Manager
# null: (default) Don't support dead properties
# true: Use in-memory property manager (NOT persistent)
property_manager: true
# Example:
# Use PERSISTENT shelve based property manager
# from wsgidav.prop_man.property_manager import ShelvePropertyManager
# property_manager: ShelvePropertyManager("wsgidav-props.shelve")
# Optional additional live property modification
mutable_live_props:
# Enable to allow clients to use e.g. the touch or cp / rsync commands with the
# preserve-timestamp flags in a mounted DAV share (may be RFC4918 incompliant)
- "{DAV:}getlastmodified"
# ----------------------------------------------------------------------------
# Lock Manager
lock_manager: true
# Example:
# Use PERSISTENT shelve based lock manager
# from wsgidav.lock_storage import LockStorageShelve
# lock_manager = LockStorageShelve("wsgidav-locks.shelve")
|
Sample wsgidav.json
¶
We can also use a JSON file for configuration. The structure is identical to the YAML format.
See the sample_wsgidav.json example. (Note that the parser allows JavaScript-style comments)
Sample wsgidav.conf
¶
This format uses plain Python syntax, which allows us to use Python data structures, and even write helper functions, etc.
This is the most powerful and flexible format, that can be used in complex scenarios.
See the Sample wsgidav.conf example.