[Zope-Checkins] SVN: Zope/trunk/ - DAV: compatibility with Windows Web Folders restored by adding

Sidnei da Silva sidnei at enfoldsystems.com
Mon Jun 18 12:04:25 EDT 2007


Log message for revision 76767:
  
        - DAV: compatibility with Windows Web Folders restored by adding
          a configuration variable that controls the sending of the
          non-standard MS-Author-Via and Public headers. Thanks for
          PatrickD for the the hard work coming up with an initial
          patch.
          (http://zope.org/Collectors/Zope/1441)
  

Changed:
  U   Zope/trunk/doc/CHANGES.txt
  U   Zope/trunk/lib/python/Zope2/Startup/handlers.py
  U   Zope/trunk/lib/python/Zope2/Startup/tests/test_schema.py
  U   Zope/trunk/lib/python/Zope2/Startup/zopeschema.xml
  U   Zope/trunk/lib/python/webdav/Resource.py
  U   Zope/trunk/lib/python/webdav/__init__.py
  U   Zope/trunk/lib/python/webdav/tests/testResource.py
  U   Zope/trunk/skel/etc/zope.conf.in

-=-
Modified: Zope/trunk/doc/CHANGES.txt
===================================================================
--- Zope/trunk/doc/CHANGES.txt	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/doc/CHANGES.txt	2007-06-18 16:04:25 UTC (rev 76767)
@@ -97,6 +97,13 @@
 
     Bugs Fixed
 
+      - Collector #1441: WebDAV compatibility with Windows Web Folders
+        restored by adding a configuration variable that controls the
+        sending of the non-standard MS-Author-Via and Public
+        headers. Thanks for PatrickD for the the hard work coming up
+        with an initial patch.  
+        (http://zope.org/Collectors/Zope/1441)
+
       - DAV: litmus "notowner_modify" tests warn during a MOVE request
         because we returned "412 Precondition Failed" instead of "423
         Locked" when the resource attempting to be moved was itself
@@ -118,13 +125,14 @@
         for further rationale.
 
       - When Zope properties were set via DAV in the "null" namespace
-        (xmlns="") a subsequent PROPFIND for the property would cause the 
-        XML representation for that property to show a namespace of 
+        (xmlns="") a subsequent PROPFIND for the property would cause the
+        XML representation for that property to show a namespace of
         xmlns="None".  Fixed within OFS.PropertySheets.dav__propstat.
 
       - Relaxed requirements for context of
         Products.Five.browser.pagetemplatefile.ZopeTwoPageTemplateFile,
-        to reduce barriers for testing renderability of views which use them.
+        to reduce barriers for testing renderability of views which
+        use them.
         (http://www.zope.org/Collectors/Zope/2327)
 
       - Collector #2304: fixed markup issue in ptEdit.zpt
@@ -1296,7 +1304,8 @@
        x86_64 systems
 
      - ZReST: the charset used in the rendered HTML was not set to the
-       corresponding output_encoding property of the ZReST instance. In addition
+       corresponding output_encoding property of the ZReST instance. In
+addition
        changing the encodings through the Properties tab did not re-render
        the HTML.
 

Modified: Zope/trunk/lib/python/Zope2/Startup/handlers.py
===================================================================
--- Zope/trunk/lib/python/Zope2/Startup/handlers.py	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/Zope2/Startup/handlers.py	2007-06-18 16:04:25 UTC (rev 76767)
@@ -150,6 +150,14 @@
 def http_header_max_length(value):
     return value
 
+def enable_ms_author_via(value):
+    import webdav
+    webdav.enable_ms_author_via = value
+
+def enable_ms_public_header(value):
+    import webdav
+    webdav.enable_ms_public_header = value
+
 def catalog_getObject_raises(value):
 
     if value is not None:

Modified: Zope/trunk/lib/python/Zope2/Startup/tests/test_schema.py
===================================================================
--- Zope/trunk/lib/python/Zope2/Startup/tests/test_schema.py	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/Zope2/Startup/tests/test_schema.py	2007-06-18 16:04:25 UTC (rev 76767)
@@ -95,6 +95,50 @@
         items.sort()
         self.assertEqual(items, [("FEARFACTORY", "rocks"), ("NSYNC","doesnt")])
 
+    def test_ms_author_via(self):
+        import webdav
+        from Zope2.Startup.handlers import handleConfig
+
+        default_setting = webdav.enable_ms_author_via
+        try:
+            conf, handler = self.load_config_text("""\
+                instancehome <<INSTANCE_HOME>>
+                enable-ms-author-via true
+                """)
+            handleConfig(None, handler)
+            self.assert_(webdav.enable_ms_author_via == True)
+
+            conf, handler = self.load_config_text("""\
+                instancehome <<INSTANCE_HOME>>
+                enable-ms-author-via false
+                """)
+            handleConfig(None, handler)
+            self.assert_(webdav.enable_ms_author_via == False)
+        finally:
+            webdav.enable_ms_author_via = default_setting
+
+    def test_ms_public_header(self):
+        import webdav
+        from Zope2.Startup.handlers import handleConfig
+
+        default_setting = webdav.enable_ms_public_header
+        try:
+            conf, handler = self.load_config_text("""\
+                instancehome <<INSTANCE_HOME>>
+                enable-ms-public-header true
+                """)
+            handleConfig(None, handler)
+            self.assert_(webdav.enable_ms_public_header == True)
+
+            conf, handler = self.load_config_text("""\
+                instancehome <<INSTANCE_HOME>>
+                enable-ms-public-header false
+                """)
+            handleConfig(None, handler)
+            self.assert_(webdav.enable_ms_public_header == False)
+        finally:
+            webdav.enable_ms_public_header = default_setting
+
     def test_path(self):
         p1 = tempfile.mktemp()
         p2 = tempfile.mktemp()

Modified: Zope/trunk/lib/python/Zope2/Startup/zopeschema.xml
===================================================================
--- Zope/trunk/lib/python/Zope2/Startup/zopeschema.xml	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/Zope2/Startup/zopeschema.xml	2007-06-18 16:04:25 UTC (rev 76767)
@@ -553,6 +553,63 @@
     </description>
   </key>
 
+  <key name="enable-ms-author-via" datatype="boolean" handler="enable_ms_author_via" default="off">
+     <description>
+     Set this directive to 'true' to enable the "MS-Author-Via" header
+     in response to an OPTIONS WebDAV request. Early versions of
+     Microsoft Web Folders and Microsoft Office require this header to
+     be present to be able to connect to Zope via WebDAV.
+
+     This is disabled by default since it makes a lot of standards-compliant
+     things unhappy AND it tricks Microsoft Office into trying to edit Office
+     files stored in Zope via WebDAV even when the user isn't allowed to edit
+     them and is only trying to download them.
+
+     Check this collector entry for more information:
+     http://www.zope.org/Collectors/Zope/1441
+
+     Recent versions of Microsoft Web Folders, updated after January
+     2005, do not require this header anymore, and instead require a
+     "Public" header to be present in reply to the OPTIONS WebDAV
+     request.
+     (http://www.redmountainsw.com/wordpress/archives/webfolders-zope)
+ 
+     To get a recent Microsoft Web Folders implementation, refer to
+     Microsoft KB Article 907306.
+     (Software Update for Web Folders: May 18, 2007).
+     </description>
+     <metadefault>off</metadefault>
+  </key>
+
+  <key name="enable-ms-public-header" datatype="boolean" handler="enable_ms_public_header" default="off">
+     <description>
+     Set this directive to 'on' to enable sending the "Public" header
+     in response to an WebDAV OPTIONS request.
+
+     Though recent WebDAV drafts mention this header, the original
+     WebDAV RFC did not mention it as part of the standard. Very few
+     web servers out there include this header in their replies, most
+     notably IIS and Netscape Enterprise 3.6.
+
+     Since many best practices documents out in the web mention
+     turning off this header with the subject of "Mask Your Web Server
+     For Enhanced Security", this setting is off by
+     default. Presumably malicious people might take the presence of
+     this header as indication of an IIS Web Server and try to attack
+     your site, so be careful when turning it on.
+
+     Recent versions of Microsoft Web Folders, updated after January
+     2005, *do* require this header to be present in reply to the
+     OPTIONS WebDAV request.
+     (http://www.redmountainsw.com/wordpress/archives/webfolders-zope)
+ 
+     To get a recent Microsoft Web Folders implementation, refer to
+     Microsoft KB Article 907306.
+     (Software Update for Web Folders: May 18, 2007).
+     </description>
+     <metadefault>off</metadefault>
+  </key>
+
   <key name="dns-server" datatype=".dns_resolver" attribute="dns_resolver">
     <description>
      Specify the IP address of your DNS server in order to cause resolved

Modified: Zope/trunk/lib/python/webdav/Resource.py
===================================================================
--- Zope/trunk/lib/python/webdav/Resource.py	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/webdav/Resource.py	2007-06-18 16:04:25 UTC (rev 76767)
@@ -18,8 +18,10 @@
 import mimetypes
 import sys
 import warnings
+import re
 from urllib import unquote
 
+import webdav
 import ExtensionClass
 from Globals import InitializeClass
 from AccessControl import getSecurityManager
@@ -54,6 +56,7 @@
 from OFS.event import ObjectWillBeMovedEvent
 import OFS.subscribers
 
+ms_dav_agent = re.compile("Microsoft.*Internet Publishing.*")
 
 class Resource(ExtensionClass.Base, Lockable.LockableItem):
 
@@ -220,6 +223,15 @@
         RESPONSE.setHeader('Allow', ', '.join(self.__http_methods__))
         RESPONSE.setHeader('Content-Length', 0)
         RESPONSE.setHeader('DAV', '1,2', 1)
+
+        # Microsoft Web Folders compatibility, only enabled if
+        # User-Agent matches.
+        if ms_dav_agent.match(REQUEST.get_header('User-Agent', '')):
+            if webdav.enable_ms_public_header:
+                RESPONSE.setHeader('Public', ', '.join(self.__http_methods__))
+            if webdav.enable_ms_author_via:
+                RESPONSE.setHeader('MS-Author-Via', 'DAV')
+
         RESPONSE.setStatus(200)
         return RESPONSE
 

Modified: Zope/trunk/lib/python/webdav/__init__.py
===================================================================
--- Zope/trunk/lib/python/webdav/__init__.py	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/webdav/__init__.py	2007-06-18 16:04:25 UTC (rev 76767)
@@ -36,3 +36,6 @@
    Microsoft, U.C. Irvine, Netscape, Novell.  February, 1999."""
 
 __version__='$Revision: 1.7 $'[11:-2]
+
+enable_ms_author_via = False
+enable_ms_public_header = False

Modified: Zope/trunk/lib/python/webdav/tests/testResource.py
===================================================================
--- Zope/trunk/lib/python/webdav/tests/testResource.py	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/lib/python/webdav/tests/testResource.py	2007-06-18 16:04:25 UTC (rev 76767)
@@ -4,6 +4,26 @@
 from AccessControl.SecurityManager import setSecurityPolicy
 from Acquisition import Implicit
 
+
+MS_DAV_AGENT = "Microsoft Data Access Internet Publishing Provider DAV"
+
+def make_request_response(environ=None):
+    from StringIO import StringIO
+    from ZPublisher.HTTPRequest import HTTPRequest
+    from ZPublisher.HTTPResponse import HTTPResponse
+    
+    if environ is None:
+        environ = {}
+
+    stdout = StringIO()
+    stdin = StringIO()
+    resp = HTTPResponse(stdout=stdout)
+    environ.setdefault('SERVER_NAME', 'foo')
+    environ.setdefault('SERVER_PORT', '80')
+    environ.setdefault('REQUEST_METHOD', 'GET')
+    req = HTTPRequest(stdin, environ, resp)
+    return req, resp
+
 class TestResource(unittest.TestCase):
     def setUp(self):
         self.app = DummyContent()
@@ -34,6 +54,61 @@
         verifyClass(IDAVResource, Resource)
         verifyClass(IWriteLock, Resource)
 
+    def test_ms_author_via(self):
+        import webdav
+        from webdav.Resource import Resource
+
+        default_settings = webdav.enable_ms_author_via
+        try:
+            req, resp = make_request_response()
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(not resp.headers.has_key('ms-author-via'))
+
+            webdav.enable_ms_author_via = True
+            req, resp = make_request_response()
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(not resp.headers.has_key('ms-author-via'))
+
+            req, resp = make_request_response(
+                environ={'USER_AGENT': MS_DAV_AGENT})
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(resp.headers.has_key('ms-author-via'))
+            self.assert_(resp.headers['ms-author-via'] == 'DAV')
+
+        finally:
+            webdav.enable_ms_author_via = default_settings
+
+    def test_ms_public_header(self):
+        import webdav
+        from webdav.Resource import Resource
+        default_settings = webdav.enable_ms_public_header
+        try:
+            req, resp = make_request_response()
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(not resp.headers.has_key('public'))
+
+            webdav.enable_ms_public_header = True
+            req, resp = make_request_response()
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(not resp.headers.has_key('public'))
+            self.assert_(resp.headers.has_key('allow'))
+
+            req, resp = make_request_response(
+                environ={'USER_AGENT': MS_DAV_AGENT})
+            resource = Resource()
+            resource.OPTIONS(req, resp)
+            self.assert_(resp.headers.has_key('public'))
+            self.assert_(resp.headers.has_key('allow'))
+            self.assert_(resp.headers['public'] == resp.headers['allow'])
+
+        finally:
+            webdav.enable_ms_public_header = default_settings
+
     def test_MOVE_self_locked(self):
         """
         DAV: litmus"notowner_modify" tests warn during a MOVE request

Modified: Zope/trunk/skel/etc/zope.conf.in
===================================================================
--- Zope/trunk/skel/etc/zope.conf.in	2007-06-18 15:59:12 UTC (rev 76766)
+++ Zope/trunk/skel/etc/zope.conf.in	2007-06-18 16:04:25 UTC (rev 76767)
@@ -443,7 +443,71 @@
 #
 #     http-header-max-length 16384
 
+# Directive: enable-ms-author-via
+#
+# Description:
+#     Set this directive to 'true' to enable the "MS-Author-Via" header
+#     in response to an OPTIONS WebDAV request. Early versions of
+#     Microsoft Web Folders and Microsoft Office require this header to
+#     be present to be able to connect to Zope via WebDAV.
+#
+#     This is disabled by default since it makes a lot of standards-compliant
+#     things unhappy AND it tricks Microsoft Office into trying to edit Office
+#     files stored in Zope via WebDAV even when the user isn't allowed to edit
+#     them and is only trying to download them.
+#
+#     Check this collector entry for more information:
+#     http://www.zope.org/Collectors/Zope/1441
+#
+#     Recent versions of Microsoft Web Folders, updated after January
+#     2005, do not require this header anymore, and instead require a
+#     "Public" header to be present in reply to the OPTIONS WebDAV
+#     request.
+#     (http://www.redmountainsw.com/wordpress/archives/webfolders-zope)
+# 
+#     To get a recent Microsoft Web Folders implementation, refer to
+#     Microsoft KB Article 907306.
+#     (Software Update for Web Folders: May 18, 2007).
+#
+# Default: off
+#
+# Example:
+#
+#    enable-ms-author-via on
 
+# Directive: enable-ms-public-header
+#
+# Description:
+#     Set this directive to 'on' to enable sending the "Public" header
+#     in response to an WebDAV OPTIONS request.
+#
+#     Though recent WebDAV drafts mention this header, the original
+#     WebDAV RFC did not mention it as part of the standard. Very few
+#     web servers out there include this header in their replies, most
+#     notably IIS and Netscape Enterprise 3.6.
+#
+#     Since many best practices documents out in the web mention
+#     turning off this header with the subject of "Mask Your Web Server
+#     For Enhanced Security", this setting is off by
+#     default. Presumably malicious people might take the presence of
+#     this header as indication of an IIS Web Server and try to attack
+#     your site, so be careful when turning it on.
+#
+#     Recent versions of Microsoft Web Folders, updated after January
+#     2005, *do* require this header to be present in reply to the
+#     OPTIONS WebDAV request.
+#     (http://www.redmountainsw.com/wordpress/archives/webfolders-zope)
+#
+#     To get a recent Microsoft Web Folders implementation, refer to
+#     Microsoft KB Article 907306.
+#     (Software Update for Web Folders: May 18, 2007).
+#
+# Default: off
+#
+# Example:
+#
+#    enable-ms-public-header on
+
 # Directive: automatically-quote-dtml-request-data
 #
 # Description:



More information about the Zope-Checkins mailing list