[MERGE/RFC] GSSAPI authentication support for FTP

Martin Pool mbp at canonical.com
Wed Jul 2 06:26:26 BST 2008


Martin Pool has voted resubmit.
Status is now: Resubmit
Comment:
=== added file 'bzrlib/transport/ftp/_gssapi.py'
+import base64, ftplib, getpass, socket
+

The coding standard is that the system imports should be before the 
bzrlib
imports.

+class SecureFtp(ftplib.FTP):
+    """Extended version of ftplib.FTP that can authenticate using 
GSSAPI."""

This class name is a bit generic, I would expect SecureFtp means SFTP or
maybe ftp-over-ssl.  Also there should be a blank line after the
docstring.

+    def mic_getline(self):
+        resp = ftplib.FTP.getline(self)
+        if resp[:4] != '631 ':
+            raise AssertionError
+        rc = kerberos.authGSSClientUnwrap(self.vc, 
resp[4:].strip("\r\n"))
+        response = 
base64.b64decode(kerberos.authGSSClientResponse(self.vc))
+        return response
+
+    def gssapi_login(self, user):
+        # Try GSSAPI login first
+        resp = self.sendcmd('AUTH GSSAPI')
+        if resp[:3] == '334':
+            rc, self.vc = kerberos.authGSSClientInit("ftp@%s" % 
self.host)
+            if kerberos.authGSSClientStep(self.vc, "") != 1:
+                while resp[:3] in ('334', '335'):
+                    authdata = kerberos.authGSSClientResponse(self.vc)
+                    resp = self.sendcmd('ADAT ' + authdata)
+                    if resp[:9] in ('235 ADAT=', '335 ADAT='):
+                        rc = kerberos.authGSSClientStep(self.vc, 
resp[9:])
+                        if not ((resp[:3] == '235' and rc == 1) or
+                                (resp[:3] == '335' and rc == 0)):
+                            raise AssertionError
+            info("Authenticated as %s" % 
kerberos.authGSSClientUserName(
+                    self.vc))
+
+            # Monkey patch ftplib
+            self.putcmd = self.mic_putcmd
+            self.getline = self.mic_getline
+            self.sendcmd('USER ' + user)
+            return resp

When you get something unexpected back it would be nice to raise an 
error
that contains e.g. resp so that if a user hits it we have some data to 
go
on - and anyhow the message might help them understand what's going 
wrong.
Perhaps a generic TransportError would be better than AssertionError.

What happens if you get a response other than 334?  I would guess 
there's
one that means 'not supported' which you should ignore but maybe the
others should at least give a warning?


+class SecureFtpTransport(FtpTransport):
+    def _create_connection(self, credentials=None):
+        """Create a new connection with the provided credentials.
+
+        :param credentials: The credentials needed to establish the 
connection.
+
+        :return: The created connection and its associated credentials.
+
+        The credentials are only the password as it may have been 
entered
+        interactively by the user and may be different from the one 
provided
+        in base url at transport creation time.
+        """
+        if credentials is None:
+            user, password = self._user, self._password
+        else:
+            user, password = credentials
+

The docstring seems inconsistent with how `credentials` is actually
used...

Other than that it looks pretty good to me.

--
Martin


For details, see: 
http://bundlebuggy.aaronbentley.com/request/%3C1213308156.6975.30.camel%40ganieda.vernstok.nl%3E



More information about the bazaar mailing list