[Twisted-Python] Telnet server using Twisted and AuthenticatingTelnetProtocol

filoufake-python at yahoo.fr filoufake-python at yahoo.fr
Thu Aug 20 01:07:24 MDT 2009


Hello,

I have created a telnet server in python.

Maybe you wonder why to create a telnet server while Windows has one?
Because the windows telnet server does not allow to interract with the
desktop. If you try to start a GUI app, it will start and run but will
not be displayed on the server desktop.

My telnet server will allow to start a GUI application interracting with the windows desktop of the server.
Ex. : typing "notepad" in the telnet console will pop up the notepad on the Windows desktop of the server.

At the time this server works but has no authentication feature implemented.

I would like to implement the authentication using AuthenticatingTelnetProtocol and credential.
I found the "cred.py" example on the twistedmatrix website (in the example section) and looked fine as starting point.

I quite well understand this expample.

I modified the code as follow but always got the same error message when a connectiion is attempted.
I have been trying since two weeks but I cannot get it work.

Is there a problem with "AuthenticatingTelnetProtocol"

The error message:
************************************************************
D:\workspace\twisted>telnet_cred.py
2009-08-20 08:57:11+0200 [-] Log opened.
2009-08-20 08:57:11+0200 [-] __main__.ServerFactory starting on 4738
2009-08-20 08:57:11+0200 [-] Starting factory <__main__.ServerFactory instance at 0x00D79C60>
2009-08-20 08:57:15+0200 [__main__.ServerFactory] DEBUG: buildProtocol - addr IPv4Address(TCP, '127.0.0.1', 4978)
2009-08-20 08:57:15+0200 [__main__.ServerFactory] Unhandled Error
        Traceback (most recent call last):
          File "C:\Python25\lib\site-packages\twisted\python\log.py", line 69, in callWithContext
            return context.call({ILogContext: newCtx}, func, *args, **kw)
          File "C:\Python25\lib\site-packages\twisted\python\context.py", line 59, in callWithContext
            return self.currentContext().callWithContext(ctx, func, *args, **kw)
          File "C:\Python25\lib\site-packages\twisted\python\context.py", line 37, in callWithContext
            return func(*args,**kw)
          File "C:\Python25\lib\site-packages\twisted\internet\selectreactor.py", line 146, in _doReadOrWrite
            why = getattr(selectable, method)()
        --- <exception caught here> ---
          File "C:\Python25\lib\site-packages\twisted\internet\tcp.py", line 932, in doRead
            protocol = self.factory.buildProtocol(self._buildAddr(addr))
          File "D:\workspace\twisted\telnet_cred.py", line 130, in buildProtocol
            p = protocol.ServerFactory.buildProtocol(self, addr)
          File "C:\Python25\lib\site-packages\twisted\internet\protocol.py", line 98, in buildProtocol
            p = self.protocol()
        exceptions.TypeError: __init__() takes exactly 2 arguments (1 given)
************************************************************

The modified code:
************************************************************

# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# See LICENSE for details.



import sys
from zope.interface import implements, Interface

from twisted.protocols import basic
from twisted.internet import protocol
from twisted.python import log

from twisted.cred import error
from twisted.cred import portal
from twisted.cred import checkers
from twisted.cred import credentials

from twisted.conch.telnet import AuthenticatingTelnetProtocol, ITelnetProtocol, TelnetProtocol

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

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

class AnonymousUser:
    implements(IProtocolUser)
    
    def getPrivileges(self):
        return [1, 2, 3]

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

class RegularUser:
    implements(IProtocolUser)
    
    def getPrivileges(self):
        return [1, 2, 3, 5, 6]

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

class Administrator:
    implements(IProtocolUser)
    
    def getPrivileges(self):
        return range(50)

    def logout(self):
        print "Cleaning up administrator resources"

class Protocol(basic.LineReceiver):
    user = None
    portal = None
    avatar = None
    logout = None

    def connectionMade(self):
        self.sendLine("Login with USER <name> followed by PASS <password> or ANON")
        self.sendLine("Check privileges with PRIVS")

    def connectionLost(self, reason):
        if self.logout:
            self.logout()
            self.avatar = None
            self.logout = None
    
    def lineReceived(self, line):
        f = getattr(self, 'cmd_' + line.upper().split()[0])
        if f:
            try:
                f(*line.split()[1:])
            except TypeError:
                self.sendLine("Wrong number of arguments.")
            except:
                self.sendLine("Server error (probably your fault)")

    def cmd_ANON(self):
        if self.portal:
            self.portal.login(credentials.Anonymous(), None, IProtocolUser
                ).addCallbacks(self._cbLogin, self._ebLogin
                )
        else:
            self.sendLine("DENIED")
    
    def cmd_USER(self, name):
        self.user = name
        self.sendLine("Alright.  Now PASS?")
    
    def cmd_PASS(self, password):
        if not self.user:
            self.sendLine("USER required before PASS")
        else:
            if self.portal:
                self.portal.login(
                    credentials.UsernamePassword(self.user, password),
                    None,
                    IProtocolUser
                ).addCallbacks(self._cbLogin, self._ebLogin
                )
            else:
                self.sendLine("DENIED")

    def cmd_PRIVS(self):
        self.sendLine("You have the following privileges: ")
        self.sendLine(" ".join(map(str, self.avatar.getPrivileges())))

    def _cbLogin(self, (interface, avatar, logout)):
        assert interface is IProtocolUser
        self.avatar = avatar
        self.logout = logout
        self.sendLine("Login successful.  Available commands: PRIVS")
    
    def _ebLogin(self, failure):
        failure.trap(error.UnauthorizedLogin)
        self.sendLine("Login denied!  Go away.")

class ServerFactory(protocol.ServerFactory):
##    protocol = Protocol
    protocol = AuthenticatingTelnetProtocol
    
    def __init__(self, portal):
        self.portal = portal
    
    def buildProtocol(self, addr):
        print "DEBUG: buildProtocol - addr", addr
        p = protocol.ServerFactory.buildProtocol(self, addr)
        print "DEBUG2: buildProtocol - addr", addr
        p.portal = self.portal
        return p

class Realm:
    implements(portal.IRealm)

    def requestAvatar(self, avatarId, mind, *interfaces):
        if IProtocolUser in interfaces:
            if avatarId == checkers.ANONYMOUS:
                av = AnonymousUser()
            elif avatarId.isupper():
                # Capitalized usernames are administrators.
                av = Administrator()
            else:
                av = RegularUser()
            return IProtocolUser, av, av.logout
        elif ITelnetProtocol in interfaces:
            print "BEGUG: aaaa"
            if avatarId.isupper():
                av = TelnetProtocol()
            return ITelnetProtocol, av, None
        raise NotImplementedError("Only IProtocolUser interface is supported by this realm")

def main():
    r = Realm()
    p = portal.Portal(r)
    c = checkers.InMemoryUsernamePasswordDatabaseDontUse()
    c.addUser("auser", "thepass")
    c.addUser("SECONDUSER", "secret")
    p.registerChecker(c)
    p.registerChecker(checkers.AllowAnonymousAccess())
    
    f = ServerFactory(p)
    
    log.startLogging(sys.stdout)

    from twisted.internet import reactor
    reactor.listenTCP(4738, f)
    reactor.run()

if __name__ == '__main__':
    main()

************************************************************

If someone could help me.

Philippe


      
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20090820/37542693/attachment.html>


More information about the Twisted-Python mailing list