Twisted tiene soporte SSH: http://www.devshed.com/c/a/Python/SSH-with-Twisted/
El paquete twisted.conch añade soporte SSH en Twisted. Este capítulo muestra cómo puede usar los módulos en twisted.conch para construir servidores y clientes SSH.
Configuración de un servidor SSH personalizada
La línea de comandos es una interfaz increíblemente eficiente para ciertas tareas. Los administradores de sistemas adoran la capacidad de administrar aplicaciones escribiendo comandos sin tener que hacer clic a través de una interfaz gráfica de usuario. Un shell SSH es aún mejor, ya que es accesible desde cualquier lugar en Internet.
Puede usar twisted.conch para crear un servidor SSH que proporcione acceso a un shell personalizado con los comandos que defina. Este shell incluso admitirá algunas características adicionales, como el historial de comandos, para que pueda desplazarse por los comandos que ya ha escrito.
¿Cómo puedo hacer eso? Escriba una subclase de twisted.conch.recvline.HistoricRecvLine que implemente su protocolo de shell. HistoricRecvLine es similar a twisted.protocols.basic.LineReceiver, pero con características de nivel superior para controlar la terminal.
Escriba una subclase de twisted.conch.recvline.HistoricRecvLine que implemente su protocolo de shell. HistoricRecvLine es similar a twisted.protocols.basic.LineReceiver, pero con características de nivel superior para controlar la terminal.
Para hacer que su caparazón esté disponible a través de SSH, debe implementar algunas clases diferentes que twisted.conch necesita para construir un servidor SSH. En primer lugar, necesita las clases de autenticación twisted.cred: un portal, verificadores de credenciales y un reino que devuelve avatares. Utilice twisted.conch.avatar.ConchUser como la clase base para su avatar. Su clase de avatar también debería implementar twisted.conch.interfaces.ISession, que incluye un método de openShell en el que crea un protocolo para administrar la sesión interactiva del usuario. Finalmente, cree un objeto twisted.conch.ssh.factory.SSHFactory y establezca su atributo de portal en una instancia de su portal.
El ejemplo 10-1 muestra un servidor SSH personalizado que autentica a los usuarios por su nombre de usuario y contraseña. Le da a cada usuario un shell que proporciona varios comandos.
Ejemplo 10-1. sshserver.py
from twisted.cred import portal, checkers, credentials
from twisted.conch import error, avatar, recvline, interfaces as conchinterfaces
from twisted.conch.ssh import factory, userauth, connection, keys, session, common from twisted.conch.insults import insults from twisted.application import service, internet
from zope.interface import implements
import os
class SSHDemoProtocol(recvline.HistoricRecvLine):
def __init__(self, user):
self.user = user
def connectionMade(self) :
recvline.HistoricRecvLine.connectionMade(self)
self.terminal.write("Welcome to my test SSH server.")
self.terminal.nextLine()
self.do_help()
self.showPrompt()
def showPrompt(self):
self.terminal.write("$ ")
def getCommandFunc(self, cmd):
return getattr(self, ‘do_’ + cmd, None)
def lineReceived(self, line):
line = line.strip()
if line:
cmdAndArgs = line.split()
cmd = cmdAndArgs[0]
args = cmdAndArgs[1:]
func = self.getCommandFunc(cmd)
if func:
try:
func(*args)
except Exception, e:
self.terminal.write("Error: %s" % e)
self.terminal.nextLine()
else:
self.terminal.write("No such command.")
self.terminal.nextLine()
self.showPrompt()
def do_help(self, cmd=”):
"Get help on a command. Usage: help command"
if cmd:
func = self.getCommandFunc(cmd)
if func:
self.terminal.write(func.__doc__)
self.terminal.nextLine()
return
publicMethods = filter(
lambda funcname: funcname.startswith(‘do_’), dir(self))
commands = [cmd.replace(‘do_’, ”, 1) for cmd in publicMethods]
self.terminal.write("Commands: " + " ".join(commands))
self.terminal.nextLine()
def do_echo(self, *args):
"Echo a string. Usage: echo my line of text"
self.terminal.write(" ".join(args))
self.terminal.nextLine()
def do_whoami(self):
"Prints your user name. Usage: whoami"
self.terminal.write(self.user.username)
self.terminal.nextLine()
def do_quit(self):
"Ends your session. Usage: quit"
self.terminal.write("Thanks for playing!")
self.terminal.nextLine()
self.terminal.loseConnection()
def do_clear(self):
"Clears the screen. Usage: clear"
self.terminal.reset()
class SSHDemoAvatar(avatar.ConchUser):
implements(conchinterfaces.ISession)
def __init__(self, username):
avatar.ConchUser.__init__(self)
self.username = username
self.channelLookup.update({‘session’:session.SSHSession})
def openShell(self, protocol):
serverProtocol = insults.ServerProtocol(SSHDemoProtocol, self)
serverProtocol.makeConnection(protocol)
protocol.makeConnection(session.wrapProtocol(serverProtocol))
def getPty(self, terminal, windowSize, attrs):
return None
def execCommand(self, protocol, cmd):
raise NotImplementedError
def closed(self):
pass
class SSHDemoRealm:
implements(portal.IRealm)
def requestAvatar(self, avatarId, mind, *interfaces):
if conchinterfaces.IConchUser in interfaces:
return interfaces[0], SSHDemoAvatar(avatarId), lambda: None
else:
raise Exception, "No supported interfaces found."
def getRSAKeys():
if not (os.path.exists(‘public.key’) and os.path.exists(‘private.key’)):
# generate a RSA keypair
print "Generating RSA keypair…"
from Crypto.PublicKey import RSA
KEY_LENGTH = 1024
rsaKey = RSA.generate(KEY_LENGTH, common.entropy.get_bytes)
publicKeyString = keys.makePublicKeyString(rsaKey)
privateKeyString = keys.makePrivateKeyString(rsaKey)
# save keys for next time
file(‘public.key’, ‘w+b’).write(publicKeyString)
file(‘private.key’, ‘w+b’).write(privateKeyString)
print "done."
else:
publicKeyString = file(‘public.key’).read()
privateKeyString = file(‘private.key’).read()
return publicKeyString, privateKeyString
if __name__ == "__main__":
sshFactory = factory.SSHFactory()
sshFactory.portal = portal.Portal(SSHDemoRealm())
users = {‘admin’: ‘aaa’, ‘guest’: ‘bbb’}
sshFactory.portal.registerChecker(
checkers.InMemoryUsernamePasswordDatabaseDontUse(**users))
pubKeyString, privKeyString =
getRSAKeys()
sshFactory.publicKeys = {
‘ssh-rsa’: keys.getPublicKeyString(data=pubKeyString)}
sshFactory.privateKeys = {
‘ssh-rsa’: keys.getPrivateKeyObject(data=privKeyString)}
from twisted.internet import reactor
reactor.listenTCP(2222, sshFactory)
reactor.run()
{mospagebreak title=Setting Up a Custom SSH Server continued}
sshserver.py se ejecutará un servidor SSH en el puerto 2222.Conectarse a este servidor con un cliente SSH utilizando el nombre de usuario y contraseña de administrador AAA, y pruebe a escribir algunos comandos:
$ ssh [email protected] -p 2222
[email protected]’s password: aaa
>>> Welcome to my test SSH server.
Commands: clear echo help quit whoami
$ whoami
admin
$ help echo
Echo a string. Usage: echo my line of text
$ echo hello SSH world!
hello SSH world!
$ quit
Connection to localhost closed.
Advertencias dado el requisito multiplataforma: "[pexpect] debería funcionar en cualquier plataforma que admita el módulo Python estándar". lista de plataformas de módulos pty: linux. Además: "Pexpect actualmente no funciona en el Python de Windows estándar (consulte el requisito pty); sin embargo, parece funcionar bien con Cygwin". – jtniehof
Gracias por las respuestas. Logré obtener paramiko para conectarme, sin embargo, aún no lo he probado en múltiples plataformas. Definitivamente voy a tener estas otras opciones en mente. – Takkun
Me parece que pxssh se ha integrado en pexpect que se encuentra aquí: https://github.com/pexpect/pexpect – AlanObject