[CalendarServer-changes] [10129] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Dec 5 16:49:47 PST 2012


Revision: 10129
          http://trac.calendarserver.org//changeset/10129
Author:   sagen at apple.com
Date:     2012-12-05 16:49:47 -0800 (Wed, 05 Dec 2012)
Log Message:
-----------
Authentication factories not safe for unencrypted connections are automatically not advertised when an insecure (e.g. non-SSL) connection is made

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/provision/test/test_root.py
    CalendarServer/trunk/calendarserver/tap/util.py
    CalendarServer/trunk/conf/caldavd-apple.plist
    CalendarServer/trunk/conf/caldavd-test.plist
    CalendarServer/trunk/contrib/migration/calendarcommonextra.py
    CalendarServer/trunk/contrib/migration/test/test_commonextra.py
    CalendarServer/trunk/twext/web2/channel/http.py
    CalendarServer/trunk/twext/web2/dav/auth.py
    CalendarServer/trunk/twext/web2/dav/test/test_acl.py
    CalendarServer/trunk/twext/web2/dav/test/test_resource.py
    CalendarServer/trunk/twext/web2/test/test_metafd.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py

Added Paths:
-----------
    CalendarServer/trunk/twext/web2/dav/test/test_auth.py

Modified: CalendarServer/trunk/calendarserver/provision/test/test_root.py
===================================================================
--- CalendarServer/trunk/calendarserver/provision/test/test_root.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/calendarserver/provision/test/test_root.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -85,7 +85,8 @@
         self.root = auth.AuthenticationWrapper(
             root,
             portal,
-            credentialFactories=(basic.BasicCredentialFactory("Test realm"),),
+            (basic.BasicCredentialFactory("Test realm"),),
+            (basic.BasicCredentialFactory("Test realm"),),
             loginInterfaces=(auth.IPrincipal,))
 
         self.site = server.Site(self.root)

Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/calendarserver/tap/util.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -409,7 +409,8 @@
     #
     # Configure the Site and Wrappers
     #
-    credentialFactories = []
+    wireEncryptedCredentialFactories = []
+    wireUnencryptedCredentialFactories = []
 
     portal = Portal(auth.DavRealm())
 
@@ -464,7 +465,9 @@
                 log.error("Unknown scheme: %s" % (scheme,))
 
         if credFactory:
-            credentialFactories.append(credFactory)
+            wireEncryptedCredentialFactories.append(credFactory)
+            if schemeConfig.get("AllowedOverWireUnencrypted", False):
+                wireUnencryptedCredentialFactories.append(credFactory)
 
     #
     # Setup Resource hierarchy
@@ -685,9 +688,10 @@
     authWrapper = AuthenticationWrapper(
         root,
         portal,
-        credentialFactories,
+        wireEncryptedCredentialFactories,
+        wireUnencryptedCredentialFactories,
         (auth.IPrincipal,),
-        overrides=overrides,
+        overrides=overrides
     )
 
     logWrapper = DirectoryLogWrapperResource(

Modified: CalendarServer/trunk/conf/caldavd-apple.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-apple.plist	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/conf/caldavd-apple.plist	2012-12-06 00:49:47 UTC (rev 10129)
@@ -242,7 +242,7 @@
       <key>Basic</key>
       <dict>
         <key>Enabled</key>
-        <false/>
+        <true/>
       </dict>
 
       <!-- Digest challenge/response -->

Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/conf/caldavd-test.plist	2012-12-06 00:49:47 UTC (rev 10129)
@@ -507,6 +507,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
       </dict>
 
       <!-- Digest challenge/response -->
@@ -514,6 +516,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>Algorithm</key>
         <string>md5</string>
         <key>Qop</key>
@@ -525,6 +529,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>ServicePrincipal</key>
         <string></string>
       </dict>

Modified: CalendarServer/trunk/contrib/migration/calendarcommonextra.py
===================================================================
--- CalendarServer/trunk/contrib/migration/calendarcommonextra.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/contrib/migration/calendarcommonextra.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -146,6 +146,7 @@
 
     settings["EnableSSL"] = True
     settings["RedirectHTTPToHTTPS"] = True
+    settings.setdefault("Authentication", {}).setdefault("Basic", {})["Enabled"] = True
 
 def setCert(plistPath, otherCert):
     """

Modified: CalendarServer/trunk/contrib/migration/test/test_commonextra.py
===================================================================
--- CalendarServer/trunk/contrib/migration/test/test_commonextra.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/contrib/migration/test/test_commonextra.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -34,6 +34,7 @@
         orig = {
         }
         expected = {
+            'Authentication': {'Basic': {'Enabled': True}},
             'EnableSSL': True,
             'RedirectHTTPToHTTPS': True,
             'SSLAuthorityChain': '/test/pchain.pem',

Modified: CalendarServer/trunk/twext/web2/channel/http.py
===================================================================
--- CalendarServer/trunk/twext/web2/channel/http.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twext/web2/channel/http.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -637,11 +637,7 @@
                 self._cleanup()
 
     def getHostInfo(self):
-        t=self.channel.transport
-        secure = interfaces.ISSLTransport(t, None) is not None
-        host = t.getHost()
-        host.host = _cachedGetHostByAddr(host.host)
-        return host, secure
+        return self.channel._host, self.channel._secure
 
     def getRemoteHost(self):
         return self.channel.transport.getPeer()
@@ -783,6 +779,9 @@
         self.requests = []
         
     def connectionMade(self):
+        self._secure = interfaces.ISSLTransport(self.transport, None) is not None
+        address = self.transport.getHost()
+        self._host = _cachedGetHostByAddr(address.host)
         self.setTimeout(self.inputTimeOut)
         self.factory.addConnectedChannel(self)
     

Modified: CalendarServer/trunk/twext/web2/dav/auth.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/auth.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twext/web2/dav/auth.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -37,7 +37,9 @@
 
 
 class AuthenticationWrapper(WrapperResource):
-    def __init__(self, resource, portal, credentialFactories, loginInterfaces):
+    def __init__(self, resource, portal,
+        wireEncryptedCredentialFactories, wireUnencryptedCredentialFactories,
+        loginInterfaces):
         """
         Wrap the given resource and use the parameters to set up the request
         to allow anyone to challenge and handle authentication.
@@ -45,23 +47,42 @@
         @param resource: L{DAVResource} FIXME: This should get promoted to
             twext.web2.auth
         @param portal: The cred portal
-        @param credentialFactories: Sequence of credentialFactories that can
-            be used to authenticate by resources in this tree.
+        @param wireEncryptedCredentialFactories: Sequence of credentialFactories
+            that can be used to authenticate by resources in this tree over a
+            wire-encrypted channel (SSL).
+        @param wireUnencryptedCredentialFactories: Sequence of credentialFactories
+            that can be used to authenticate by resources in this tree over a
+            wire-unencrypted channel (non-SSL).
         @param loginInterfaces: More cred stuff
         """
         super(AuthenticationWrapper, self).__init__(resource)
 
         self.portal = portal
-        self.credentialFactories = dict([(factory.scheme, factory)
-                                         for factory in credentialFactories])
+        self.wireEncryptedCredentialFactories = dict([(factory.scheme, factory)
+                                         for factory in wireEncryptedCredentialFactories])
+        self.wireUnencryptedCredentialFactories = dict([(factory.scheme, factory)
+                                         for factory in wireUnencryptedCredentialFactories])
         self.loginInterfaces = loginInterfaces
 
+        # FIXME: some unit tests access self.credentialFactories, so assigning here
+        self.credentialFactories = self.wireEncryptedCredentialFactories
+
     def hook(self, req):
         req.portal = self.portal
-        req.credentialFactories = self.credentialFactories
         req.loginInterfaces = self.loginInterfaces
 
+        # If not using SSL, use the factory list which excludes "Basic"
+        if req.chanRequest is None: # This is only None in unit tests
+            secureConnection = True
+        else:
+            ignored, secureConnection = req.chanRequest.getHostInfo()
+        req.credentialFactories = (
+            self.wireEncryptedCredentialFactories
+            if secureConnection
+            else self.wireUnencryptedCredentialFactories
+        )
 
+
 class IPrincipal(Interface):
     pass
 

Modified: CalendarServer/trunk/twext/web2/dav/test/test_acl.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/test/test_acl.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twext/web2/dav/test/test_acl.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -72,6 +72,7 @@
             rootResource,
             portal,
             credentialFactories,
+            credentialFactories,
             loginInterfaces
         ))
 

Copied: CalendarServer/trunk/twext/web2/dav/test/test_auth.py (from rev 10125, CalendarServer/trunk/twext/web2/dav/test/test_auth.py)
===================================================================
--- CalendarServer/trunk/twext/web2/dav/test/test_auth.py	                        (rev 0)
+++ CalendarServer/trunk/twext/web2/dav/test/test_auth.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -0,0 +1,67 @@
+##
+# Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# DRI: Wilfredo Sanchez, wsanchez at apple.com
+##
+
+import collections
+from twext.web2.dav.auth import AuthenticationWrapper
+import twext.web2.dav.test.util
+
+class AutoWrapperTestCase(twext.web2.dav.test.util.TestCase):
+
+    def test_basicAuthPrevention(self):
+        """
+        Ensure authentication factories which are not safe to use over an
+        "unencrypted wire" are not advertised when an insecure (i.e. non-SSL
+        connection is made.
+        """
+        FakeFactory = collections.namedtuple("FakeFactory", ("scheme,"))
+        wireEncryptedfactories = [FakeFactory("basic"), FakeFactory("digest"), FakeFactory("xyzzy")]
+        wireUnencryptedfactories = [FakeFactory("digest"), FakeFactory("xyzzy")]
+
+        class FakeChannel(object):
+            def __init__(self, secure):
+                self.secure = secure
+            def getHostInfo(self):
+                return "ignored", self.secure
+
+        class FakeRequest(object):
+            def __init__(self, secure):
+                self.portal = None
+                self.loginInterfaces = None
+                self.credentialFactories = None
+                self.chanRequest = FakeChannel(secure)
+
+        wrapper = AuthenticationWrapper(None, None,
+            wireEncryptedfactories, wireUnencryptedfactories, None)
+        req = FakeRequest(True) # Connection is over SSL
+        wrapper.hook(req)
+        self.assertEquals(
+            set(req.credentialFactories.keys()),
+            set(["basic", "digest", "xyzzy"])
+        )
+        req = FakeRequest(False) # Connection is not over SSL
+        wrapper.hook(req)
+        self.assertEquals(
+            set(req.credentialFactories.keys()),
+            set(["digest", "xyzzy"])
+        )

Modified: CalendarServer/trunk/twext/web2/dav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/twext/web2/dav/test/test_resource.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twext/web2/dav/test/test_resource.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -240,6 +240,7 @@
             self.rootresource,
             portal,
             credentialFactories,
+            credentialFactories,
             loginInterfaces,
         ))
 

Modified: CalendarServer/trunk/twext/web2/test/test_metafd.py
===================================================================
--- CalendarServer/trunk/twext/web2/test/test_metafd.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twext/web2/test/test_metafd.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -53,7 +53,10 @@
             raise SocketError(ENOTCONN, "Transport endpoint not connected")
 
 
+    def getsockname(self):
+        return ("4.3.2.1", 4321)
 
+
 class InheritedPortForTesting(sendfdport.InheritedPort):
     """
     L{sendfdport.InheritedPort} subclass that prevents certain I/O operations

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -3023,11 +3023,13 @@
     """ AuthenticationWrapper implementation which allows overriding
         credentialFactories on a per-resource-path basis """
 
-    def __init__(self, resource, portal, credentialFactories, loginInterfaces,
-        overrides=None):
+    def __init__(self, resource, portal,
+        wireEncryptedCredentialFactories, wireUnencryptedCredentialFactories,
+        loginInterfaces, overrides=None):
 
         super(AuthenticationWrapper, self).__init__(resource, portal,
-            credentialFactories, loginInterfaces)
+            wireEncryptedCredentialFactories, wireUnencryptedCredentialFactories,
+            loginInterfaces)
 
         self.overrides = {}
         if overrides:
@@ -3043,7 +3045,7 @@
         super(AuthenticationWrapper, self).hook(req)
 
         factories = self.overrides.get(req.path.rstrip("/"),
-            self.credentialFactories)
+            req.credentialFactories)
         req.credentialFactories = factories
 
 

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-12-05 04:54:04 UTC (rev 10128)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-12-06 00:49:47 UTC (rev 10129)
@@ -406,15 +406,20 @@
     # Authentication
     #
     "Authentication": {
-        "Basic": { "Enabled": False }, # Clear text; best avoided
+        "Basic": {                         # Clear text; best avoided
+            "Enabled": True,
+            "AllowedOverWireUnencrypted": False, # Advertised over non-SSL?
+        },
         "Digest": {                        # Digest challenge/response
             "Enabled": True,
             "Algorithm": "md5",
             "Qop": "",
+            "AllowedOverWireUnencrypted": True, # Advertised over non-SSL?
         },
         "Kerberos": {                       # Kerberos/SPNEGO
             "Enabled": False,
-            "ServicePrincipal": ""
+            "ServicePrincipal": "",
+            "AllowedOverWireUnencrypted": True, # Advertised over non-SSL?
         },
         "Wiki": {
             "Enabled": False,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121205/d6927e54/attachment-0001.html>


More information about the calendarserver-changes mailing list