[Twisted-Python] FTP server with credentials

Mayne, Peter peter.mayne at hp.com
Wed Oct 12 19:50:28 EDT 2005


I'm trying to write a simple FTP server that a client can connect and
authenticate to, then upload a file, which the server buffers in memory
and processes, and then returns a status result to the client depending
on the result of the processing. (Twisted 2.0.1, Python 2.4.1, Windws XP
SP2)

So far I've done this:

<code>
import sys
from twisted.cred import checkers, portal
from twisted.internet import reactor, protocol
from twisted.protocols import ftp
from twisted.python import components, log

class IProtocolUser(components.Interface):
    def getPrivileges(self):
        """Return a list of privileges this user has."""

    def logout(self):
        """Cleanup per-login resources allocated to this avatar"""

class RegularUser:
    __implements__ = (IProtocolUser,)

    def getPrivileges(self):
        return [1, 2, 3, 5, 6]

    def logout(self):
        print "Cleaning up regular user resources"

class Realm:
    __implements__ = portal.IRealm

    def requestAvatar(self, avatarId, mind, *interfaces):
        if ftp.IFTPShell in interfaces:
            av = RegularUser()
            return ftp.IFTPShell, av, av.logout
        else:
            raise NotImplementedError("Only IFTPShell interface is
supported by this realm")

class MyFtpServer(ftp.FTP):
    '''My custom FTP server.'''

    def __init__(self, *args, **kw):
        super(ftp.FTP, self).__init__(*args, **kw)
        self.blockingCommands.remove('PORT')
        print 'Removed PORT to allow non-PASV'

    def dataReceived(self, data):
        'As soon as any data is received, send it to stdout for
debugging.'
        sys.stdout.write('\n  **[%s]\n' % data)
        self.transport.write(data)

def main():
    r = Realm()
    p = portal.Portal(r)
    c = checkers.InMemoryUsernamePasswordDatabaseDontUse()
    c.addUser("u", "p")
    p.registerChecker(c)
    p.registerChecker(checkers.AllowAnonymousAccess())

    #log.startLogging(sys.stdout)

    factory = ftp.FTPFactory(MyFtpServer())
    factory.portal = p
    reactor.listenTCP(2121, factory)
    reactor.run()

if __name__ == '__main__':
    main()
</code>

I can connect and authenticate (using the Windows comman line FTP client
running on the same system), but when I "put myfile.txt" on the client,
the server produces the following:

<output>
C:\>mockftp.py
Removed PORT to allow non-PASV
C:\opt\Python24\lib\site-packages\twisted\protocols\ftp.py:625:
DeprecationWarni
ng: IPv4Address.__getitem__ is deprecated.  Use attributes instead.
  phost = self.transport.getPeer()[1]
Traceback (most recent call last):
Failure: exceptions.IndexError: tuple index out of range
Traceback (most recent call last):
  File
"C:\opt\Python24\lib\site-packages\twisted\internet\selectreactor.py",
li
ne 133, in doSelect
    _logrun(selectable, _drdw, selectable, method, dict)
  File "C:\opt\Python24\Lib\site-packages\twisted\python\log.py", line
56, in ca
llWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "C:\opt\Python24\Lib\site-packages\twisted\python\log.py", line
41, in ca
llWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "C:\opt\Python24\Lib\site-packages\twisted\python\context.py",
line 31, i
n callWithContext
    return func(*args,**kw)
--- <exception caught here> ---
  File
"C:\opt\Python24\lib\site-packages\twisted\internet\selectreactor.py",
li
ne 139, in _doReadOrWrite
    why = getattr(selectable, method)()
  File "C:\opt\Python24\Lib\site-packages\twisted\internet\tcp.py", line
351, in
 doRead
    return self.protocol.dataReceived(data)
  File "C:\opt\Python24\Lib\site-packages\twisted\protocols\basic.py",
line 221,
 in dataReceived
    why = self.lineReceived(line)
  File "C:\opt\Python24\lib\site-packages\twisted\protocols\ftp.py",
line 550, i
n lineReceived
    self.processCommand(*cmdAndArgs)
  File "C:\opt\Python24\lib\site-packages\twisted\protocols\ftp.py",
line 608, i
n processCommand
    return method(*args)
  File "C:\opt\Python24\lib\site-packages\twisted\protocols\ftp.py",
line 940, i
n ftp_PORT
    self._createDTP()
  File "C:\opt\Python24\lib\site-packages\twisted\protocols\ftp.py",
line 632, i
n _createDTP
    self.dtpPort = reactor.connectTCP(self.dtpHostPort[1],
self.dtpHostPort[2])
exceptions.IndexError: tuple index out of range
Cleaning up regular user resources
</output>

At this point I'm lost. What am I doing wrong?

Thanks.

PJDM
-- 
Peter Mayne
Technology Consultant
Hewlett-Packard Australia
7-11 Barry Drive, Turner, ACT, 2612




More information about the Twisted-Python mailing list