def add_provider(self, share, provider, readonly=False): """Add a provider to the provider_map routing table.""" # Make sure share starts with, or is '/' share = "/" + share.strip("/") assert share not in self.provider_map if compat.is_basestring(provider): # Syntax: # <mount_path>: <folder_path> # We allow a simple string as 'provider'. In this case we interpret # it as a file system root folder that is published. provider = FilesystemProvider(provider, readonly) elif type(provider) in (dict, ): if "provider" in provider: # Syntax: # <mount_path>: {"provider": <class_path>, "args": <pos_args>, "kwargs": <named_args} prov_class = dynamic_import_class(provider["provider"]) provider = prov_class(*provider.get("args", []), **provider.get("kwargs", {})) else: # Syntax: # <mount_path>: {"root": <path>, "redaonly": <bool>} provider = FilesystemProvider( provider["root"], bool(provider.get("readonly", False))) elif type(provider) in (list, tuple): raise ValueError( "Provider {}: tuple/list syntax is no longer supported".format( provider)) # provider = FilesystemProvider(provider[0], provider[1]) if not isinstance(provider, DAVProvider): raise ValueError("Invalid provider {}".format(provider)) provider.set_share_path(share) if self.mount_path: provider.set_mount_path(self.mount_path) # TODO: someday we may want to configure different lock/prop # managers per provider provider.set_lock_manager(self.lock_manager) provider.set_prop_manager(self.prop_manager) self.provider_map[share] = provider # self.provider_map[share] = {"provider": provider, "allow_anonymous": False} # Store the list of share paths, ordered by length, so route lookups # will return the most specific match self.sorted_share_list = [s.lower() for s in self.provider_map.keys()] self.sorted_share_list = sorted(self.sorted_share_list, key=len, reverse=True) return provider
def add_provider(self, share, provider, readonly=False): """Add a provider to the provider_map routing table.""" # Make sure share starts with, or is '/' share = "/" + share.strip("/") assert share not in self.provider_map if compat.is_basestring(provider): # Syntax: # <mount_path>: <folder_path> # We allow a simple string as 'provider'. In this case we interpret # it as a file system root folder that is published. provider = FilesystemProvider(provider, readonly) elif type(provider) in (dict,): if "provider" in provider: # Syntax: # <mount_path>: {"provider": <class_path>, "args": <pos_args>, "kwargs": <named_args} prov_class = dynamic_import_class(provider["provider"]) provider = prov_class( *provider.get("args", []), **provider.get("kwargs", {}) ) else: # Syntax: # <mount_path>: {"root": <path>, "redaonly": <bool>} provider = FilesystemProvider( provider["root"], bool(provider.get("readonly", False)) ) elif type(provider) in (list, tuple): raise ValueError( "Provider {}: tuple/list syntax is no longer supported".format(provider) ) # provider = FilesystemProvider(provider[0], provider[1]) if not isinstance(provider, DAVProvider): raise ValueError("Invalid provider {}".format(provider)) provider.set_share_path(share) if self.mount_path: provider.set_mount_path(self.mount_path) # TODO: someday we may want to configure different lock/prop # managers per provider provider.set_lock_manager(self.lock_manager) provider.set_prop_manager(self.prop_manager) self.provider_map[share] = provider # self.provider_map[share] = {"provider": provider, "allow_anonymous": False} # Store the list of share paths, ordered by length, so route lookups # will return the most specific match self.sorted_share_list = [s.lower() for s in self.provider_map.keys()] self.sorted_share_list = sorted(self.sorted_share_list, key=len, reverse=True) return provider
def make_domain_controller(config): dc = config.get("http_authenticator", {}).get("domain_controller") if dc is True or not dc: # True or null: dc = SimpleDomainController if compat.is_basestring(dc): # If a plain string is passed, try to import it as class dc = dynamic_import_class(dc) if inspect.isclass(dc): # If a class is passed, instantiate that dc = dc(config) # print("make_domain_controller", dc) return dc
def make_domain_controller(wsgidav_app, config): dc = config.get("http_authenticator", {}).get("domain_controller") org_dc = dc if dc is True or not dc: # True or null: dc = SimpleDomainController elif compat.is_basestring(dc): # If a plain string is passed, try to import it as class dc = dynamic_import_class(dc) if inspect.isclass(dc): # If a class is passed, instantiate that dc = dc(wsgidav_app, config) else: raise RuntimeError( "Could not resolve domain controller class (got {})".format(org_dc) ) # print("make_domain_controller", dc) return dc
def __init__(self, config): self.config = copy.deepcopy(DEFAULT_CONFIG) util.deep_update(self.config, config) # self.config.update(config) config = self.config # Evaluate configuration and set defaults _check_config(config) # response_trailer = config.get("response_trailer", "") self.verbose = config.get("verbose", 3) lockStorage = config.get("lock_manager") if lockStorage is True: lockStorage = LockStorageDict() if not lockStorage: self.locksManager = None else: self.locksManager = LockManager(lockStorage) self.propsManager = config.get("property_manager") if not self.propsManager: # Normalize False, 0 to None self.propsManager = None elif self.propsManager is True: self.propsManager = PropertyManager() self.mount_path = config.get("mount_path") # Instantiate DAV resource provider objects for every share # provider_mapping may contain the args that are passed to a `FilesystemProvider` # instance: # <mount_path>: <folder_path> # or # <mount_path>: [folder_path, is_readonly] # or contain a complete new instance: # <mount_path>: <DAVProvider Instance> provider_mapping = self.config["provider_mapping"] self.providerMap = {} self.sortedShareList = None for share, provider in provider_mapping.items(): self.add_provider(share, provider) domain_controller = None # Define WSGI application stack middleware_stack = config.get("middleware_stack", []) mw_list = [] # This is the 'outer' application, i.e. the WSGI application object that # is eventually called by the server. self.application = self # When building up the middleware stack, this app will be wrapped and replaced by the # next middleware in the list. # The `middleware_stack` is configured such that the first app in the list should be # called first. But since every app wraps its predecessor, we iterate in reverse # order: for mw in reversed(middleware_stack): # The middleware stack configuration may contain plain strings, dicts, # classes, or objects app = None if compat.is_basestring(mw): # If a plain string is passed, try to import it, assuming BaseMiddleware # signature app_class = dynamic_import_class(mw) app = app_class(self, self.application, config) elif type(mw) is dict: # If a dict with one entry is passed, use the key as module/class name # and the value as constructor arguments (positional or kwargs). assert len(mw) == 1 name, args = list(mw.items())[0] expand = {"${application}": self.application} app = dynamic_instantiate_middleware(name, args, expand) elif inspect.isclass(mw): # If a class is passed, assume BaseMiddleware (or compatible) assert issubclass( mw, BaseMiddleware ) # TODO: remove this assert with 3.0 app = mw(self, self.application, config) else: # Otherwise assume an initialized middleware instance app = mw # TODO: We should try to generalize this specific code: if isinstance(app, HTTPAuthenticator): domain_controller = app.get_domain_controller() # Check anonymous access for share, data in self.providerMap.items(): if app.allow_anonymous_access(share): data["allow_anonymous"] = True # Add middleware to the stack if app: mw_list.append(app) self.application = app else: _logger.error("Could not add middleware {}.".format(mw)) # Print info _logger.info( "WsgiDAV/{} Python/{} {}".format( __version__, util.PYTHON_VERSION, platform.platform(aliased=True) ) ) if self.verbose >= 4: _logger.info( "Default encoding: {!r} (file system: {!r})".format( sys.getdefaultencoding(), sys.getfilesystemencoding() ) ) _logger.info("Lock manager: {}".format(self.locksManager)) _logger.info("Property manager: {}".format(self.propsManager)) _logger.info("Domain controller: {}".format(domain_controller)) # We traversed the stack in reverse order. Now revert again, so # we see the order that was configured: _logger.info("Middleware stack:") for mw in reversed(mw_list): _logger.info(" - {}".format(mw)) _logger.info("Registered DAV providers by route:") for share in self.sortedShareList: data = self.providerMap[share] hint = " (anonymous)" if data["allow_anonymous"] else "" _logger.info(" - '{}': {}{}".format(share, data["provider"], hint)) for share, data in self.providerMap.items(): if data["allow_anonymous"]: # TODO: we should only warn here, if --no-auth is not given _logger.warn("Share '{}' will allow anonymous access.".format(share)) return
def __init__(self, config): self.config = copy.deepcopy(DEFAULT_CONFIG) util.deep_update(self.config, config) config = self.config # Evaluate configuration and set defaults _check_config(config) self.verbose = config.get("verbose", 3) hotfixes = config.get("hotfixes", {}) self.re_encode_path_info = hotfixes.get("re_encode_path_info", None) if self.re_encode_path_info is None: self.re_encode_path_info = compat.PY3 self.unquote_path_info = hotfixes.get("unquote_path_info", False) lock_storage = config.get("lock_manager") if lock_storage is True: lock_storage = LockStorageDict() if not lock_storage: self.lock_manager = None else: self.lock_manager = LockManager(lock_storage) self.prop_manager = config.get("property_manager") if not self.prop_manager: # Normalize False, 0 to None self.prop_manager = None elif self.prop_manager is True: self.prop_manager = PropertyManager() self.mount_path = config.get("mount_path") auth_conf = config.get("http_authenticator", {}) # Instantiate DAV resource provider objects for every share. # provider_mapping may contain the args that are passed to a # `FilesystemProvider` instance: # <mount_path>: <folder_path> # or # <mount_path>: { "root": <folder_path>, "readonly": True } # or contain a complete new instance: # <mount_path>: <DAVProvider Instance> provider_mapping = self.config["provider_mapping"] self.provider_map = {} self.sorted_share_list = None for share, provider in provider_mapping.items(): self.add_provider(share, provider) self.http_authenticator = None domain_controller = None # Define WSGI application stack middleware_stack = config.get("middleware_stack", []) mw_list = [] # This is the 'outer' application, i.e. the WSGI application object that # is eventually called by the server. self.application = self # The `middleware_stack` is configured such that the first app in the # list should be called first. Since every app wraps its predecessor, we # iterate in reverse order: for mw in reversed(middleware_stack): # The middleware stack configuration may contain plain strings, dicts, # classes, or objects app = None if compat.is_basestring(mw): # If a plain string is passed, try to import it, assuming # `BaseMiddleware` signature app_class = dynamic_import_class(mw) app = app_class(self, self.application, config) elif type(mw) is dict: # If a dict with one entry is passed, use the key as module/class name # and the value as constructor arguments (positional or kwargs). assert len(mw) == 1 name, args = list(mw.items())[0] expand = {"${application}": self.application} app = dynamic_instantiate_middleware(name, args, expand) elif inspect.isclass(mw): # If a class is passed, assume BaseMiddleware (or compatible) assert issubclass( mw, BaseMiddleware) # TODO: remove this assert with 3.0 app = mw(self, self.application, config) else: # Otherwise assume an initialized middleware instance app = mw # Remember if isinstance(app, HTTPAuthenticator): self.http_authenticator = app domain_controller = app.get_domain_controller() # Add middleware to the stack if app: if callable(getattr(app, "is_disabled", None)) and app.is_disabled(): _logger.warning( "App {}.is_disabled() returned True: skipping.".format( app)) else: mw_list.append(app) self.application = app else: _logger.error("Could not add middleware {}.".format(mw)) domain_controller # Print info _logger.info("WsgiDAV/{} Python/{} {}".format( __version__, util.PYTHON_VERSION, platform.platform(aliased=True))) if self.verbose >= 4: _logger.info("Default encoding: {!r} (file system: {!r})".format( sys.getdefaultencoding(), sys.getfilesystemencoding())) if self.verbose >= 3: _logger.info("Lock manager: {}".format(self.lock_manager)) _logger.info("Property manager: {}".format(self.prop_manager)) _logger.info("Domain controller: {}".format(domain_controller)) if self.verbose >= 4: # We traversed the stack in reverse order. Now revert again, so # we see the order that was configured: _logger.info("Middleware stack:") for mw in reversed(mw_list): _logger.info(" - {}".format(mw)) if self.verbose >= 3: _logger.info("Registered DAV providers by route:") for share in self.sorted_share_list: provider = self.provider_map[share] hint = (" (anonymous)" if domain_controller.is_share_anonymous(share) else "") _logger.info(" - '{}': {}{}".format(share, provider, hint)) if auth_conf.get("accept_basic") and not config.get("ssl_certificate"): _logger.warning( "Basic authentication is enabled: It is highly recommended to enable SSL." ) if domain_controller: for share, provider in self.provider_map.items(): if domain_controller.is_share_anonymous(share): _logger.warning( "Share '{}' will allow anonymous {} access.".format( share, "read" if provider.is_readonly() else "write")) return
def __init__(self, config): self.config = copy.deepcopy(DEFAULT_CONFIG) util.deep_update(self.config, config) config = self.config # Evaluate configuration and set defaults _check_config(config) self.verbose = config.get("verbose", 3) hotfixes = config.get("hotfixes", {}) self.re_encode_path_info = hotfixes.get("re_encode_path_info", None) if self.re_encode_path_info is None: self.re_encode_path_info = compat.PY3 self.unquote_path_info = hotfixes.get("unquote_path_info", False) lock_storage = config.get("lock_manager") if lock_storage is True: lock_storage = LockStorageDict() if not lock_storage: self.lock_manager = None else: self.lock_manager = LockManager(lock_storage) self.prop_manager = config.get("property_manager") if not self.prop_manager: # Normalize False, 0 to None self.prop_manager = None elif self.prop_manager is True: self.prop_manager = PropertyManager() self.mount_path = config.get("mount_path") auth_conf = config.get("http_authenticator", {}) # Instantiate DAV resource provider objects for every share. # provider_mapping may contain the args that are passed to a # `FilesystemProvider` instance: # <mount_path>: <folder_path> # or # <mount_path>: { "root": <folder_path>, "readonly": True } # or contain a complete new instance: # <mount_path>: <DAVProvider Instance> provider_mapping = self.config["provider_mapping"] self.provider_map = {} self.sorted_share_list = None for share, provider in provider_mapping.items(): self.add_provider(share, provider) self.http_authenticator = None domain_controller = None # Define WSGI application stack middleware_stack = config.get("middleware_stack", []) mw_list = [] # This is the 'outer' application, i.e. the WSGI application object that # is eventually called by the server. self.application = self # The `middleware_stack` is configured such that the first app in the # list should be called first. Since every app wraps its predecessor, we # iterate in reverse order: for mw in reversed(middleware_stack): # The middleware stack configuration may contain plain strings, dicts, # classes, or objects app = None if compat.is_basestring(mw): # If a plain string is passed, try to import it, assuming # `BaseMiddleware` signature app_class = dynamic_import_class(mw) app = app_class(self, self.application, config) elif type(mw) is dict: # If a dict with one entry is passed, use the key as module/class name # and the value as constructor arguments (positional or kwargs). assert len(mw) == 1 name, args = list(mw.items())[0] expand = {"${application}": self.application} app = dynamic_instantiate_middleware(name, args, expand) elif inspect.isclass(mw): # If a class is passed, assume BaseMiddleware (or compatible) assert issubclass( mw, BaseMiddleware ) # TODO: remove this assert with 3.0 app = mw(self, self.application, config) else: # Otherwise assume an initialized middleware instance app = mw # Remember if isinstance(app, HTTPAuthenticator): self.http_authenticator = app domain_controller = app.get_domain_controller() # Add middleware to the stack if app: if callable(getattr(app, "is_disabled", None)) and app.is_disabled(): _logger.warning( "App {}.is_disabled() returned True: skipping.".format(app) ) else: mw_list.append(app) self.application = app else: _logger.error("Could not add middleware {}.".format(mw)) domain_controller # Print info _logger.info( "WsgiDAV/{} Python/{} {}".format( __version__, util.PYTHON_VERSION, platform.platform(aliased=True) ) ) if self.verbose >= 4: _logger.info( "Default encoding: {!r} (file system: {!r})".format( sys.getdefaultencoding(), sys.getfilesystemencoding() ) ) if self.verbose >= 3: _logger.info("Lock manager: {}".format(self.lock_manager)) _logger.info("Property manager: {}".format(self.prop_manager)) _logger.info("Domain controller: {}".format(domain_controller)) if self.verbose >= 4: # We traversed the stack in reverse order. Now revert again, so # we see the order that was configured: _logger.info("Middleware stack:") for mw in reversed(mw_list): _logger.info(" - {}".format(mw)) if self.verbose >= 3: _logger.info("Registered DAV providers by route:") for share in self.sorted_share_list: provider = self.provider_map[share] hint = ( " (anonymous)" if domain_controller.is_share_anonymous(share) else "" ) _logger.info(" - '{}': {}{}".format(share, provider, hint)) if auth_conf.get("accept_basic") and not config.get("ssl_certificate"): _logger.warning( "Basic authentication is enabled: It is highly recommended to enable SSL." ) if domain_controller: for share, provider in self.provider_map.items(): if domain_controller.is_share_anonymous(share): _logger.warning( "Share '{}' will allow anonymous {} access.".format( share, "read" if provider.is_readonly() else "write" ) ) return