[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