浏览代码

Merge pull request #1559 from pbiering/fixes-3.2.2

Fixes for 3.2.2
Peter Bieringer 1 年之前
父节点
当前提交
368c43137a
共有 10 个文件被更改,包括 47 次插入20 次删除
  1. 1 0
      CHANGELOG.md
  2. 6 0
      DOCUMENTATION.md
  3. 3 1
      config
  4. 14 8
      contrib/apache/radicale.conf
  5. 2 2
      radicale/app/__init__.py
  6. 8 4
      radicale/app/base.py
  7. 1 1
      radicale/app/put.py
  8. 4 0
      radicale/config.py
  9. 1 1
      radicale/httputils.py
  10. 7 3
      radicale/rights/from_file.py

+ 1 - 0
CHANGELOG.md

@@ -8,6 +8,7 @@
 * Enhancement: Added 'max_freebusy_occurrences` setting to avoid potential DOS on reports
 * Enhancement: Added 'max_freebusy_occurrences` setting to avoid potential DOS on reports
 * Enhancement: remove unexpected control codes from uploaded items
 * Enhancement: remove unexpected control codes from uploaded items
 * Enhancement: add 'strip_domain' setting for username handling
 * Enhancement: add 'strip_domain' setting for username handling
+* Enhancement: add option to toggle debug log of rights rule with doesn't match
 * Drop: remove unused requirement "typeguard"
 * Drop: remove unused requirement "typeguard"
 * Improve: Refactored some date parsing code
 * Improve: Refactored some date parsing code
 
 

+ 6 - 0
DOCUMENTATION.md

@@ -978,6 +978,12 @@ Log response on level=debug
 
 
 Default: `False`
 Default: `False`
 
 
+##### rights_rule_doesnt_match_on_debug = True
+
+Log rights rule which doesn't match on level=debug
+
+Default: `False`
+
 #### headers
 #### headers
 
 
 In this section additional HTTP headers that are sent to clients can be
 In this section additional HTTP headers that are sent to clients can be

+ 3 - 1
config

@@ -158,6 +158,8 @@
 # Log response content on level=debug
 # Log response content on level=debug
 #response_content_on_debug = False
 #response_content_on_debug = False
 
 
+# Log rights rule which doesn't match on level=debug
+#rights_rule_doesnt_match_on_debug = False
 
 
 [headers]
 [headers]
 
 
@@ -177,4 +179,4 @@
 
 
 # When returning a free-busy report, limit the number of returned
 # When returning a free-busy report, limit the number of returned
 # occurences per event to prevent DOS attacks.
 # occurences per event to prevent DOS attacks.
-#max_freebusy_occurrence = 10000
+#max_freebusy_occurrence = 10000

+ 14 - 8
contrib/apache/radicale.conf

@@ -57,13 +57,15 @@
 		Require all granted
 		Require all granted
 		</IfDefine>
 		</IfDefine>
 
 
-		## You may want to use apache's authentication (config: [auth] type = remote_user)
+		## You may want to use apache's authentication (config: [auth] type = http_x_remote_user)
+		##  e.g. create a new file with a testuser: htpasswd -c -B /etc/httpd/conf/htpasswd-radicale testuser
 		#AuthBasicProvider file
 		#AuthBasicProvider file
 		#AuthType Basic
 		#AuthType Basic
 		#AuthName "Enter your credentials"
 		#AuthName "Enter your credentials"
-		#AuthUserFile /path/to/httpdfile/
+		#AuthUserFile /etc/httpd/conf/htpasswd-radicale
 		#AuthGroupFile /dev/null
 		#AuthGroupFile /dev/null
 		#Require valid-user
 		#Require valid-user
+		#RequestHeader set X-Remote-User expr=%{REMOTE_USER}
 
 
 		<IfDefine RADICALE_ENFORCE_SSL>
 		<IfDefine RADICALE_ENFORCE_SSL>
 			<IfModule !ssl_module>
 			<IfModule !ssl_module>
@@ -106,13 +108,15 @@
 		Require all granted
 		Require all granted
 		</IfDefine>
 		</IfDefine>
 
 
-		## You may want to use apache's authentication (config: [auth] type = remote_user)
+		## You may want to use apache's authentication (config: [auth] type = http_x_remote_user)
+		##  e.g. create a new file with a testuser: htpasswd -c -B /etc/httpd/conf/htpasswd-radicale testuser
 		#AuthBasicProvider file
 		#AuthBasicProvider file
 		#AuthType Basic
 		#AuthType Basic
 		#AuthName "Enter your credentials"
 		#AuthName "Enter your credentials"
-		#AuthUserFile /path/to/httpdfile/
+		#AuthUserFile /etc/httpd/conf/htpasswd-radicale
 		#AuthGroupFile /dev/null
 		#AuthGroupFile /dev/null
 		#Require valid-user
 		#Require valid-user
+		#RequestHeader set X-Remote-User expr=%{REMOTE_USER}
 
 
 		<IfDefine RADICALE_ENFORCE_SSL>
 		<IfDefine RADICALE_ENFORCE_SSL>
 			<IfModule !ssl_module>
 			<IfModule !ssl_module>
@@ -179,11 +183,12 @@ CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
 		Require all granted
 		Require all granted
 		</IfDefine>
 		</IfDefine>
 
 
-		## You may want to use apache's authentication (config: [auth] type = remote_user)
+		## You may want to use apache's authentication (config: [auth] type = http_x_remote_user)
+		##  e.g. create a new file with a testuser: htpasswd -c -B /etc/httpd/conf/htpasswd-radicale testuser
 		#AuthBasicProvider file
 		#AuthBasicProvider file
 		#AuthType Basic
 		#AuthType Basic
 		#AuthName "Enter your credentials"
 		#AuthName "Enter your credentials"
-		#AuthUserFile /path/to/httpdfile/
+		#AuthUserFile /etc/httpd/conf/htpasswd-radicale
 		#AuthGroupFile /dev/null
 		#AuthGroupFile /dev/null
 		#Require valid-user
 		#Require valid-user
 	</Location>
 	</Location>
@@ -221,11 +226,12 @@ CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
 		Require all granted
 		Require all granted
 		</IfDefine>
 		</IfDefine>
 
 
-		## You may want to use apache's authentication (config: [auth] type = remote_user)
+		## You may want to use apache's authentication (config: [auth] type = http_x_remote_user)
+		##  e.g. create a new file with a testuser: htpasswd -c -B /etc/httpd/conf/htpasswd-radicale testuser
 		#AuthBasicProvider file
 		#AuthBasicProvider file
 		#AuthType Basic
 		#AuthType Basic
 		#AuthName "Enter your credentials"
 		#AuthName "Enter your credentials"
-		#AuthUserFile /path/to/httpdfile/
+		#AuthUserFile /etc/httpd/conf/htpasswd-radicale
 		#AuthGroupFile /dev/null
 		#AuthGroupFile /dev/null
 		#Require valid-user
 		#Require valid-user
 	</Location>
 	</Location>

+ 2 - 2
radicale/app/__init__.py

@@ -146,7 +146,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
                     if self._response_content_on_debug:
                     if self._response_content_on_debug:
                         logger.debug("Response content:\n%s", answer)
                         logger.debug("Response content:\n%s", answer)
                     else:
                     else:
-                        logger.debug("Response content: suppressed by config/option [auth] response_content_on_debug")
+                        logger.debug("Response content: suppressed by config/option [logging] response_content_on_debug")
                     headers["Content-Type"] += "; charset=%s" % self._encoding
                     headers["Content-Type"] += "; charset=%s" % self._encoding
                     answer = answer.encode(self._encoding)
                     answer = answer.encode(self._encoding)
                 accept_encoding = [
                 accept_encoding = [
@@ -196,7 +196,7 @@ class Application(ApplicationPartDelete, ApplicationPartHead,
             logger.debug("Request header:\n%s",
             logger.debug("Request header:\n%s",
                          pprint.pformat(self._scrub_headers(environ)))
                          pprint.pformat(self._scrub_headers(environ)))
         else:
         else:
-            logger.debug("Request header: suppressed by config/option [auth] request_header_on_debug")
+            logger.debug("Request header: suppressed by config/option [logging] request_header_on_debug")
 
 
         # SCRIPT_NAME is already removed from PATH_INFO, according to the
         # SCRIPT_NAME is already removed from PATH_INFO, according to the
         # WSGI specification.
         # WSGI specification.

+ 8 - 4
radicale/app/base.py

@@ -51,6 +51,7 @@ class ApplicationBase:
         self._encoding = configuration.get("encoding", "request")
         self._encoding = configuration.get("encoding", "request")
         self._log_bad_put_request_content = configuration.get("logging", "bad_put_request_content")
         self._log_bad_put_request_content = configuration.get("logging", "bad_put_request_content")
         self._response_content_on_debug = configuration.get("logging", "response_content_on_debug")
         self._response_content_on_debug = configuration.get("logging", "response_content_on_debug")
+        self._request_content_on_debug = configuration.get("logging", "request_content_on_debug")
         self._hook = hook.load(configuration)
         self._hook = hook.load(configuration)
 
 
     def _read_xml_request_body(self, environ: types.WSGIEnviron
     def _read_xml_request_body(self, environ: types.WSGIEnviron
@@ -66,17 +67,20 @@ class ApplicationBase:
             logger.debug("Request content (Invalid XML):\n%s", content)
             logger.debug("Request content (Invalid XML):\n%s", content)
             raise RuntimeError("Failed to parse XML: %s" % e) from e
             raise RuntimeError("Failed to parse XML: %s" % e) from e
         if logger.isEnabledFor(logging.DEBUG):
         if logger.isEnabledFor(logging.DEBUG):
-            logger.debug("Request content:\n%s",
-                         xmlutils.pretty_xml(xml_content))
+            if self._request_content_on_debug:
+                logger.debug("Request content (XML):\n%s",
+                             xmlutils.pretty_xml(xml_content))
+            else:
+                logger.debug("Request content (XML): suppressed by config/option [logging] request_content_on_debug")
         return xml_content
         return xml_content
 
 
     def _xml_response(self, xml_content: ET.Element) -> bytes:
     def _xml_response(self, xml_content: ET.Element) -> bytes:
         if logger.isEnabledFor(logging.DEBUG):
         if logger.isEnabledFor(logging.DEBUG):
             if self._response_content_on_debug:
             if self._response_content_on_debug:
-                logger.debug("Response content:\n%s",
+                logger.debug("Response content (XML):\n%s",
                              xmlutils.pretty_xml(xml_content))
                              xmlutils.pretty_xml(xml_content))
             else:
             else:
-                logger.debug("Response content: suppressed by config/option [auth] response_content_on_debug")
+                logger.debug("Response content (XML): suppressed by config/option [logging] response_content_on_debug")
         f = io.BytesIO()
         f = io.BytesIO()
         ET.ElementTree(xml_content).write(f, encoding=self._encoding,
         ET.ElementTree(xml_content).write(f, encoding=self._encoding,
                                           xml_declaration=True)
                                           xml_declaration=True)

+ 1 - 1
radicale/app/put.py

@@ -150,7 +150,7 @@ class ApplicationPartPut(ApplicationBase):
             if self._log_bad_put_request_content:
             if self._log_bad_put_request_content:
                 logger.warning("Bad PUT request content of %r:\n%s", path, content)
                 logger.warning("Bad PUT request content of %r:\n%s", path, content)
             else:
             else:
-                logger.debug("Bad PUT request content: suppressed by config/option [auth] bad_put_request_content")
+                logger.debug("Bad PUT request content: suppressed by config/option [logging] bad_put_request_content")
             return httputils.BAD_REQUEST
             return httputils.BAD_REQUEST
         (prepared_items, prepared_tag, prepared_write_whole_collection,
         (prepared_items, prepared_tag, prepared_write_whole_collection,
          prepared_props, prepared_exc_info) = prepare(
          prepared_props, prepared_exc_info) = prepare(

+ 4 - 0
radicale/config.py

@@ -292,6 +292,10 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
             "value": "False",
             "value": "False",
             "help": "log response content on level=debug",
             "help": "log response content on level=debug",
             "type": bool}),
             "type": bool}),
+        ("rights_rule_doesnt_match_on_debug", {
+            "value": "False",
+            "help": "log rights rules which doesn't match on level=debug",
+            "type": bool}),
         ("mask_passwords", {
         ("mask_passwords", {
             "value": "True",
             "value": "True",
             "help": "mask passwords in logs",
             "help": "mask passwords in logs",

+ 1 - 1
radicale/httputils.py

@@ -146,7 +146,7 @@ def read_request_body(configuration: "config.Configuration",
     if configuration.get("logging", "request_content_on_debug"):
     if configuration.get("logging", "request_content_on_debug"):
         logger.debug("Request content:\n%s", content)
         logger.debug("Request content:\n%s", content)
     else:
     else:
-        logger.debug("Request content: suppressed by config/option [auth] request_content_on_debug")
+        logger.debug("Request content: suppressed by config/option [logging] request_content_on_debug")
     return content
     return content
 
 
 
 

+ 7 - 3
radicale/rights/from_file.py

@@ -48,6 +48,7 @@ class Rights(rights.BaseRights):
     def __init__(self, configuration: config.Configuration) -> None:
     def __init__(self, configuration: config.Configuration) -> None:
         super().__init__(configuration)
         super().__init__(configuration)
         self._filename = configuration.get("rights", "file")
         self._filename = configuration.get("rights", "file")
+        self._log_rights_rule_doesnt_match_on_debug = configuration.get("logging", "rights_rule_doesnt_match_on_debug")
 
 
     def authorization(self, user: str, path: str) -> str:
     def authorization(self, user: str, path: str) -> str:
         user = user or ""
         user = user or ""
@@ -61,6 +62,8 @@ class Rights(rights.BaseRights):
         except Exception as e:
         except Exception as e:
             raise RuntimeError("Failed to load rights file %r: %s" %
             raise RuntimeError("Failed to load rights file %r: %s" %
                                (self._filename, e)) from e
                                (self._filename, e)) from e
+        if not self._log_rights_rule_doesnt_match_on_debug:
+            logger.debug("logging of rules which doesn't match suppressed by config/option [logging] rights_rule_doesnt_match_on_debug")
         for section in rights_config.sections():
         for section in rights_config.sections():
             try:
             try:
                 user_pattern = rights_config.get(section, "user")
                 user_pattern = rights_config.get(section, "user")
@@ -80,8 +83,9 @@ class Rights(rights.BaseRights):
                              user, sane_path, user_pattern,
                              user, sane_path, user_pattern,
                              collection_pattern, section, permission)
                              collection_pattern, section, permission)
                 return permission
                 return permission
-            logger.debug("Rule %r:%r doesn't match %r:%r from section %r",
-                         user, sane_path, user_pattern, collection_pattern,
-                         section)
+            if self._log_rights_rule_doesnt_match_on_debug:
+                logger.debug("Rule %r:%r doesn't match %r:%r from section %r",
+                             user, sane_path, user_pattern, collection_pattern,
+                             section)
         logger.info("Rights: %r:%r doesn't match any section", user, sane_path)
         logger.info("Rights: %r:%r doesn't match any section", user, sane_path)
         return ""
         return ""