Hello, I have a python script that executes a python code on a remote host using SSH. It was working perfectly with Twisted 2.5. The method of returning private and public has changed in userauth.SSHUserAuthClient (Twisted 8.1).
I was using (Twisted 2.5) ------------------------------------------------ def getPublicKey(self): return keys.getPublicKeyString(self.keyfile+'.pub') def getPrivateKey(self): return defer.succeed(keys.getPrivateKeyObject(self.keyfile)) Now I am using (Twisted 8.1) ---------------------------------------------------- def getPublicKey(self): return keys.Key.fromFile(self.keyfile+'.pub') def getPrivateKey(self): return defer.succeed(keys.Key.fromFile(self.keyfile)) and it doesn't work any more. I have attached the simplified script. Here is the scenario I am using and the exception I got. Any help is greatly appreciated. Scenario ---------------------- I am creating a DSA key using ssh-keygen (in Debian and Ubuntu) with an empty password $ ssh-keygen -t dsa and copy it to my localhost $ ssh-copy-id -i ~/.ssh/id_dsa localhost then run the attached script, which tries to execute a python script remotely using SSH and get the following error Traceback (most recent call last): File "/usr/lib/python2.5/site-packages/twisted/internet/selectreactor.py", line 146, in _doReadOrWrite why = getattr(selectable, method)() File "/usr/lib/python2.5/site-packages/twisted/internet/tcp.py", line 362, in doRead return self.protocol.dataReceived(data) File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/transport.py", line 314, in dataReceived self.dispatchMessage(messageNum, packet[1:]) File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/transport.py", line 336, in dispatchMessage messageNum, payload) --- <exception caught here> --- File "/usr/lib/python2.5/site-packages/twisted/python/log.py", line 51, in callWithLogger return callWithContext({"system": lp}, func, *args, **kw) File "/usr/lib/python2.5/site-packages/twisted/python/log.py", line 36, in callWithContext return context.call({ILogContext: newCtx}, func, *args, **kw) File "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 59, in callWithContext return self.currentContext().callWithContext(ctx, func, *args, **kw) File "/usr/lib/python2.5/site-packages/twisted/python/context.py", line 37, in callWithContext return func(*args,**kw) File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/service.py", line 44, in packetReceived return f(packet) File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/userauth.py", line 262, in ssh_USERAUTH_FAILURE if method not in self.authenticatedWith and self.tryAuth(method): File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/userauth.py", line 234, in tryAuth return f() File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/userauth.py", line 338, in auth_publickey keyType = getNS(publicKey)[0] File "/usr/lib/python2.5/site-packages/twisted/conch/ssh/common.py", line 51, in getNS l, = struct.unpack('!L',s[c:c+4]) exceptions.TypeError: 'Key' object is unsubscriptable Sincerely Saki
# -*- coding: utf-8 -*- ############################################################# # Executes a python code on the remote host using SSH ############################################################# from twisted.conch.ssh import transport, userauth, connection, common, keys, channel from twisted.internet import defer, protocol, reactor from twisted.python import log import sys, os, re class lqSSHException(Exception): def __init__(self, errorcode, message): self.errorcode = errorcode self.message = message def __str__(self): return '%s %s' % (self.errorcode, self.message) class lqSSHClient(protocol.ClientFactory): ''' Executes a remote python code ''' def __init__(self, username, server, keyfile, command): ''' Necessary information to connect ''' self.username = username self.server = server self.keyfile = keyfile self.command = command self._deferer_ = defer.Deferred() self._transport = None def buildProtocol(self, addr): ''' Create the protocol after connection ''' self._transport = lqSSHTransport(self.username, self.keyfile, self.command, self._deferer_) return self._transport def connect(self): reactor.connectTCP(self.server, 22, self) self._deferer_.addCallback(self.disconnectOnSuccess) self._deferer_.addErrback(self.disconnectOnError) return self._deferer_ def disconnect(self): if self._transport is not None: self._transport.loseConnection() def disconnectOnError(self, failure): self.disconnect() raise failure def disconnectOnSuccess(self, result): self.disconnect() return result def clientConnectionFailed(self, connector, reason): ''' When connection failed ''' protocol.ClientFactory.clientConnectionFailed(self, connector, reason) log.err(reason) self._deferer_.errback(reason) class lqSSHTransport(transport.SSHClientTransport): def __init__(self, username, keyfile, command, _deferer_): ''' Necessary info to start SSH connection ''' self.username = username self.keyfile = keyfile self.command = command self._deferer_ = _deferer_ self.timeout = reactor.callLater(30, self.sshTransportTimeout) def verifyHostKey(self, hostKey, fingerprint): ''' Check fingerprint ''' # print 'host key fingerprint: %s' % fingerprint self.timeout.cancel() return defer.succeed(1) def connectionSecure(self): ''' User authentication ''' self.requestService( lqSSHUserAuth(self.username, self.keyfile, self._deferer_, lqSSHConnection(self.command, self._deferer_))) def sshTransportTimeout(self): ''' If the connection times out ''' self.loseConnection() self._deferer_.errback(lqSSHException('408', 'Bağlantı zaman aşımına uğradı')) class lqSSHUserAuth(userauth.SSHUserAuthClient): def __init__(self, username, keyfile, _deferer_, connection): ''' User authentication ''' userauth.SSHUserAuthClient.__init__(self, username, connection) self.keyfile = keyfile self._deferer_ = _deferer_ def getPassword(self): ''' Password auth is not provided, give error ''' self.transport.sendDisconnect(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 'no more auths') self._deferer_.errback(lqSSHException('401', 'Wrong Key / Key authentication failed')) return def getGenericAnswers(self, name, instruction, questions): ''' Keyboard interactive password is not provided, give erro ''' self.transport.sendDisconnect(transport.DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE, 'no more auths') self._deferer_.errback(lqSSHException('401', 'User authentication failed')) return defer.fail(None) def getPublicKey(self): ''' Create the public key ''' if not os.path.exists(self.keyfile) or self.lastPublicKey: return return keys.Key.fromFile(self.keyfile+'.pub') def getPrivateKey(self): ''' Create the private key ''' return defer.succeed(keys.Key.fromFile(self.keyfile)) class lqSSHConnection(connection.SSHConnection): def __init__(self, command, _deferer_, *args, **kwargs): ''' Tracks the SSH connection ''' connection.SSHConnection.__init__(self) self.command = command self._deferer_ = _deferer_ def serviceStarted(self): ''' Runs just after the authentication finished ''' self.openChannel(lqSSHChannel(self.command, self._deferer_, \ 2**16, 2**15, conn=self)) def serviceStopped(self): ''' Runs if the service stopped ''' class lqSSHChannel(channel.SSHChannel): name = 'session' _buffer = '' delimiter = '\n' MAX_LENGTH = 16384 def __init__(self, command, _deferer_, *args, **kwargs): ''' SSH channel parameters ''' channel.SSHChannel.__init__(self, *args, **kwargs) self.command, self.input = command self._deferer_ = _deferer_ self.success = True self.output = '' def openFailed(self, reason): self._deferer_.errback(reason) def channelOpen(self, ignoredData): d = self.conn.sendRequest(self, 'exec', common.NS(self.command), wantReply = True) d.addCallback(self._cbRequest) def _cbRequest(self, ignored): if self.input: self.write(self.input) self.conn.sendEOF(self) def dataReceived(self, data): """ Splits the data to lines """ lines = (self._buffer+data).split(self.delimiter) self._buffer = lines.pop(-1) for line in lines: if len(line) > self.MAX_LENGTH: return self.lineLengthExceeded(line) else: self.lineReceived(line) if len(self._buffer) > self.MAX_LENGTH: return self.lineLengthExceeded(self._buffer) def lineReceived(self, line): code, message = line.strip().split(' ', 1) self.output += line + self.delimiter if code != '200': self.success = False self._deferer_.errback(lqSSHException(code, message)) def lineLengthExceeded(line): self.success = False self._deferer_.errback(lqSSHException('500', 'Very long line')) def extReceived(self, dataType, data): print "500 Extended data:", dataType, data def closed(self): if self.success: self._deferer_.callback(self.output) if __name__ == "__main__": USER = os.getlogin() HOST = 'localhost' KEYFILE = os.path.expanduser('~/.ssh/id_dsa') def done(result): print result reactor.stop() def failed(failure): print >> sys.stderr, failure.getErrorMessage() reactor.stop() remoteCode = "print 'Hello World'" client = lqSSHClient(USER, HOST, KEYFILE, ('python', remoteCode)) d = client.connect() d.addCallback(done) d.addErrback(failed) reactor.run()
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python