[CalendarServer-changes] [1542] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon May 21 11:23:56 PDT 2007


Revision: 1542
          http://trac.macosforge.org/projects/calendarserver/changeset/1542
Author:   cdaboo at apple.com
Date:     2007-05-21 11:23:56 -0700 (Mon, 21 May 2007)

Log Message:
-----------
Have the server auto-detect its own Kerberos principal given the hostname.

Modified Paths:
--------------
    CalendarServer/trunk/run
    CalendarServer/trunk/twistedcaldav/authkerb.py
    CalendarServer/trunk/twistedcaldav/tap.py
    CalendarServer/trunk/twistedcaldav/test/test_kerberos.py
    CalendarServer/trunk/twistedcaldav/test/test_tap.py

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2007-05-21 18:01:59 UTC (rev 1541)
+++ CalendarServer/trunk/run	2007-05-21 18:23:56 UTC (rev 1542)
@@ -464,7 +464,7 @@
   if ! py_have_module kerberos; then
     kerberos="${top}/PyKerberos";
 
-    svn_get "PyKerberos" "${kerberos}" "${svn_uri_base}/PyKerberos/trunk" 1213;
+    svn_get "PyKerberos" "${kerberos}" "${svn_uri_base}/PyKerberos/trunk" 1541;
     py_build "PyKerberos" "${kerberos}" false; # FIXME: make optional
     py_install "PyKerberos" "${kerberos}";
 

Modified: CalendarServer/trunk/twistedcaldav/authkerb.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/authkerb.py	2007-05-21 18:01:59 UTC (rev 1541)
+++ CalendarServer/trunk/twistedcaldav/authkerb.py	2007-05-21 18:23:56 UTC (rev 1542)
@@ -55,6 +55,17 @@
     """
 
     def __init__(self, username, password, service, realm):
+        """
+        
+        @param username:   user name of user to authenticate
+        @type username:    str
+        @param password:   password for user being authenticated
+        @type password:    str
+        @param service:    service principal
+        @type service:     str
+        @param hostname:   realm
+        @type hostname:    str
+        """
         credentials.UsernamePassword.__init__(self, username, password)
         
         # Convert Kerberos principal spec into service and realm
@@ -73,15 +84,43 @@
 
     scheme = 'basic'
 
-    def __init__(self, service, realm):
+    def __init__(self, principal=None, type=None, hostname=None):
         """
-        The realm string can be of the form service/realm at domain. We split that
-        into service at domain, and realm.
+        
+        @param principal:  full Kerberos principal (e.g., 'http/server.example.com at EXAMPLE.COM'). If C{None}
+            then the type and hostname arguments are used instead.
+        @type service:     str
+        @param type:       service type for Kerberos (e.g., 'http'). Must be C{None} if principal used.
+        @type type:        str
+        @param hostname:   hostname for this server. Must be C{None} if principal used.
+        @type hostname:    str
         """
-        self.service = service
+
+        # Only certain combinations of arguments allowed
+        assert (principal and not type and not hostname) or (not principal and type and hostname)
+
+        if not principal:
+            # Look up the Kerberos principal given the service type and hostname, and extract
+            # the realm and a service principal value for later use.
+            try:
+                principal = kerberos.getServerPrincipalDetails(type, hostname)
+            except kerberos.KrbError, ex:
+                logging.err("getServerPrincipalDetails: %s" % (ex[0],), system="BasicKerberosCredentialFactory")
+                raise ValueError('Authentication System Failure: %s' % (ex[0],))
+
+        try:
+            splits = principal.split("/")
+            servicetype = splits[0]
+            splits = splits[1].split("@")
+            realm = splits[1]
+        except IndexError:
+            logging.err("Invalid Kerberos principal: %s" % (principal,), system="BasicKerberosCredentialFactory")
+            raise ValueError('Authentication System Failure: Invalid Kerberos principal: %s' % (principal,))
+                
+        self.service = "%s@%s" % (servicetype, realm,)
         self.realm = realm
 
-    def getChallenge(self, peer):
+    def getChallenge(self, _ignore_peer):
         return {'realm': self.realm}
 
     def decode(self, response, request): #@UnusedVariable
@@ -142,19 +181,50 @@
 
     scheme = 'negotiate'
 
-    def __init__(self, service, realm):
+    def __init__(self, principal=None, type=None, hostname=None):
+        """
+        
+        @param principal:  full Kerberos principal (e.g., 'http/server.example.com at EXAMPLE.COM'). If C{None}
+            then the type and hostname arguments are used instead.
+        @type service:     str
+        @param type:       service type for Kerberos (e.g., 'http'). Must be C{None} if principal used.
+        @type type:        str
+        @param hostname:   hostname for this server. Must be C{None} if principal used.
+        @type hostname:    str
+        """
 
-        self.service = service
+        # Only certain combinations of arguments allowed
+        assert (principal and not type and not hostname) or (not principal and type and hostname)
+
+        if not principal:
+            # Look up the Kerberos principal given the service type and hostname, and extract
+            # the realm and a service principal value for later use.
+            try:
+                principal = kerberos.getServerPrincipalDetails(type, hostname)
+            except kerberos.KrbError, ex:
+                logging.err("getServerPrincipalDetails: %s" % (ex[0],), system="NegotiateCredentialFactory")
+                raise ValueError('Authentication System Failure: %s' % (ex[0],))
+
+        try:
+            splits = principal.split("/")
+            servicetype = splits[0]
+            splits = splits[1].split("@")
+            realm = splits[1]
+        except IndexError:
+            logging.err("Invalid Kerberos principal: %s" % (principal,), system="NegotiateCredentialFactory")
+            raise ValueError('Authentication System Failure: Invalid Kerberos principal: %s' % (principal,))
+                
+        self.service = "%s@%s" % (servicetype, realm,)
         self.realm = realm
 
-    def getChallenge(self, peer):
+    def getChallenge(self, _ignore_peer):
         return {}
 
     def decode(self, base64data, request):
         
         # Init GSSAPI first
         try:
-            result, context = kerberos.authGSSServerInit(self.service);
+            _ignore_result, context = kerberos.authGSSServerInit(self.service);
         except kerberos.GSSError, ex:
             logging.err("authGSSServerInit: %s(%s)" % (ex[0][0], ex[1][0],), system="NegotiateCredentialFactory")
             raise error.LoginFailed('Authentication System Failure: %s(%s)' % (ex[0][0], ex[1][0],))
@@ -191,7 +261,7 @@
 
         # Close the context
         try:
-            result = kerberos.authGSSServerClean(context);
+            kerberos.authGSSServerClean(context);
         except kerberos.GSSError, ex:
             logging.err("authGSSServerClean: %s" % (ex[0][0], ex[1][0],), system="NegotiateCredentialFactory")
             raise error.LoginFailed('Authentication System Failure %s(%s)' % (ex[0][0], ex[1][0],))

Modified: CalendarServer/trunk/twistedcaldav/tap.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/tap.py	2007-05-21 18:01:59 UTC (rev 1541)
+++ CalendarServer/trunk/twistedcaldav/tap.py	2007-05-21 18:23:56 UTC (rev 1542)
@@ -415,18 +415,12 @@
                         log.msg("Kerberos support not available")
                         continue
 
-                    service = schemeConfig['ServicePrincipal']
-
-                    if '@' in service:
-                        rest, kerbRealm = service.split('@', 1)
+                    principal = schemeConfig['ServicePrincipal']
+                    if not principal:
+                        credFactory = NegotiateCredentialFactory(type="http", hostname=config.ServerHostName)
                     else:
-                        kerbRealm = config.ServerHostName
+                        credFactory = NegotiateCredentialFactory(principal=principal)
 
-                    credFactory = NegotiateCredentialFactory(
-                        service,
-                        kerbRealm
-                    )
-
                 elif scheme == 'digest':
                     credFactory = QopDigestCredentialFactory(
                         schemeConfig['Algorithm'],

Modified: CalendarServer/trunk/twistedcaldav/test/test_kerberos.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_kerberos.py	2007-05-21 18:01:59 UTC (rev 1541)
+++ CalendarServer/trunk/twistedcaldav/test/test_kerberos.py	2007-05-21 18:23:56 UTC (rev 1542)
@@ -34,18 +34,25 @@
         authkerb.BasicKerberosCredentials("test", "test", "http/example.com at EXAMPLE.COM", "EXAMPLE.COM")
 
     def test_BasicKerberosCredentialFactory(self):
-        factory = authkerb.BasicKerberosCredentialFactory("http/example.com at EXAMPLE.COM", "EXAMPLE.COM")
+        factory = authkerb.BasicKerberosCredentialFactory(principal="http/server.example.com at EXAMPLE.COM")
 
         challenge = factory.getChallenge("peer")
         expected_challenge = {'realm': "EXAMPLE.COM"}
         self.assertTrue(challenge == expected_challenge,
                         msg="BasicKerberosCredentialFactory challenge %s != %s" % (challenge, expected_challenge))
 
+    def test_BasicKerberosCredentialFactoryInvalidPrincipal(self):
+        self.assertRaises(
+            ValueError,
+            authkerb.BasicKerberosCredentialFactory,
+            principal="http/server.example.com/EXAMPLE.COM"
+        )
+
     def test_NegotiateCredentials(self):
         authkerb.NegotiateCredentials("test")
 
     def test_NegotiateCredentialFactory(self):
-        factory = authkerb.NegotiateCredentialFactory("http/example.com at EXAMPLE.COM", "EXAMPLE.COM")
+        factory = authkerb.NegotiateCredentialFactory(principal="http/server.example.com at EXAMPLE.COM")
 
         challenge = factory.getChallenge("peer")
         expected_challenge = {}
@@ -61,3 +68,10 @@
             self.fail(msg="NegotiateCredentialFactory decode failed with exception: %s" % (ex,))
         else:
             self.fail(msg="NegotiateCredentialFactory decode did not fail")
+
+    def test_NegotiateCredentialFactoryInvalidPrincipal(self):
+        self.assertRaises(
+            ValueError,
+            authkerb.NegotiateCredentialFactory,
+            principal="http/server.example.com/EXAMPLE.COM"
+        )

Modified: CalendarServer/trunk/twistedcaldav/test/test_tap.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_tap.py	2007-05-21 18:01:59 UTC (rev 1541)
+++ CalendarServer/trunk/twistedcaldav/test/test_tap.py	2007-05-21 18:23:56 UTC (rev 1542)
@@ -413,6 +413,7 @@
         """
         self.config['Authentication']['Digest']['Enabled'] = True
         self.config['Authentication']['Kerberos']['Enabled'] = True
+        self.config['Authentication']['Kerberos']['ServicePrincipal'] = 'http/hello at bob'
         self.config['Authentication']['Basic']['Enabled'] = True
 
         self.writeConfig()
@@ -432,23 +433,18 @@
         self.assertEquals(len(expectedSchemes),
                           len(authWrapper.credentialFactories))
 
-    def test_servicePrincipalNoRealm(self):
+    def test_servicePrincipalNone(self):
         """
-        Test that the Kerberos Realm defaults to the ServerHostName when
-        the principal is not in the form of proto/host at realm
+        Test that the Kerberos principal look is attempted if the principal is empty.
         """
-        self.config['Authentication']['Kerberos']['ServicePrincipal'] = 'http/hello'
+        self.config['Authentication']['Kerberos']['ServicePrincipal'] = ''
         self.config['Authentication']['Kerberos']['Enabled'] = True
         self.writeConfig()
-        site = self.getSite()
+        self.assertRaises(
+            ValueError,
+            self.getSite)
 
-        authWrapper = site.resource.resource
-
-        ncf = authWrapper.credentialFactories['negotiate']
-        self.assertEquals(ncf.service, 'http/hello')
-        self.assertEquals(ncf.realm, 'localhost')
-
-    def test_servicePrincipalWithRealm(self):
+    def test_servicePrincipal(self):
         """
         Test that the kerberos realm is the realm portion of a principal
         in the form proto/host at realm
@@ -461,7 +457,7 @@
         authWrapper = site.resource.resource
 
         ncf = authWrapper.credentialFactories['negotiate']
-        self.assertEquals(ncf.service, 'http/hello at bob')
+        self.assertEquals(ncf.service, 'http at bob')
         self.assertEquals(ncf.realm, 'bob')
 
     def test_AuthWrapperPartialEnabled(self):

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070521/3b7bec12/attachment.html


More information about the calendarserver-changes mailing list