Home arrow Python arrow Page 5 - SSH with Twisted

Running Commands on a Remote Server - Python

Twisted is a framework for networked applications. In this article, you'll learn how to use the Secure Shell (SSH) with Twisted to accomplish a variety of useful tasks. This article is excerpted from chapter 10 of the book Twisted Network Programming Essentials, written by Abe Fettig (O'Reilly, 2007; ISBN: 0596100329). Copyright © 2007 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

TABLE OF CONTENTS:
  1. SSH with Twisted
  2. Setting Up a Custom SSH Server continued
  3. Using Public Keys for Authentication
  4. Providing an Administrative Python Shell
  5. Running Commands on a Remote Server
By: O'Reilly Media
Rating: starstarstarstarstar / 7
March 06, 2008

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement

This lab demonstrates how to write an SSH client. You can use twisted.conch to communicate with a server using SSH: logging in, executing commands, and
capturing the output.

How Do I Do That?

There are several classes that work together to make up a twisted.conch.ssh SSH client. The transport.SSHClientTransportclass sets up the connection and verifies the identity of the server. Theuserauth.SSHUserAuthClientlogs in using your authentication credentials. Theconnection.SSHConnectionclass takes over once you’ve logged in, and creates one or morechannel.SSHChannelobjects, which you then use to communicate with the server over a secure channel. Example 10-4 shows how you can use these classes to make an SSH client that logs into a server, runs a command, and prints the output.

Example 10-4. sshclient.py

from twisted.conch import error
from twisted.conch.ssh import transport, connection, keys, userauth, channel, common from twisted.internet import defer, protocol, reactor

class ClientCommandTransport(transport.SSHClientTransport):
   
def __init__(self, username, password, command):
        self.username = username
        self.password = password  
        self.command = command

    def verifyHostKey(self, pubKey, fingerprint):
        # in a real app, you should verify that the fingerprint matches
        # the one you expected to get from this server
        return defer.succeed(True)

    def connectionSecure(self):
        self.requestService(
            PasswordAuth(self.username, self.password,
                         ClientConnection(self.command)))

class PasswordAuth(userauth.SSHUserAuthClient):
   
def __init__(self, user, password, connection):
        userauth.SSHUserAuthClient.__init__(self, user, connection)
        self.password = password

    def getPassword(self, prompt=None):
        return defer.succeed(self.password)

class ClientConnection(connection.SSHConnection):
   
def __init__(self, cmd, *args, **kwargs):
        connection.SSHConnection.__init__(self)
        self.command = cmd

    def serviceStarted(self):
        self.openChannel(CommandChannel(self.command, conn=self))

class CommandChannel(channel.SSHChannel):
    name = 'session'

    def __init__(self, command, *args, **kwargs):
        channel.SSHChannel.__init__(self, *args, **kwargs)
        self.command = command

    def channelOpen(self, data):
       
self.conn.sendRequest(
            self, 'exec', common.NS(self.command), wantReply=True).addCallback(
            self._gotResponse)

    def _gotResponse(self, _):
        self.conn.sendEOF(self)

    def dataReceived(self, data):
        print data

    def closed(self):
        reactor.stop()

class ClientCommandFactory(protocol.ClientFactory):
   
def __init__(self, username, password, command):
        self.username = username
        self.password = password
        self.command = command

    def buildProtocol(self, addr):
        protocol = ClientCommandTransport(
            self.username, self.password, self.command)
        return protocol

if __name__ == "__main__":
    import sys, getpass
    server = sys.argv[1]
    command = sys.argv[2]
    username = raw_input("Username: ")
    password = getpass.getpass("Password: ")
    factory = ClientCommandFactory(username, password, command)
    reactor.connectTCP(server, 22, factory)
    reactor.run()

Run sshclient.py with two arguments: a hostname and a command. It will ask for your username and password, log into the server, execute the command, and print the output. For example, you could run the who command to get a list of who’s currently logged in to the server:

  $ python sshclient.py myserver.example.com who
 
Username: abe
 
Password: password

  root     pts/0       Jun 11 21:35 (192.168.0.13)
  phil     pts/2       Jun 22 13:58 (192.168.0.1)
  phil     pts/3       Jun 22 13:58 (192.168.0.1)

How Does That Work?

The ClientCommandTransport in Example 10-4 handles the initial connection to the SSH server. Its verifyHostKey method checks to make sure the server’s public key matches your expectations. Typically, you’d remember each server the first time you connected, and then check on subsequent connections to make sure that another server wasn’t maliciously trying to pass itself off as the server you expected. Here, it just returns a True value without bothering to check the key. The connectionSecure method is called as soon as the initial encrypted connection has been established. This is the appropriate time to send your login credentials, by passing a
userauth.SSHUserAuthClient to self.requestService, along with a connection.SSHConnection object that should manage the connection after authentication succeeds.

ThePasswordAuthinherits fromuserauth.SSHUserAuthClient. It has to implement only a single method,getPassword, which returns the password it will use to log in. If you wanted to use public key authentication, you’d implement the methodsgetPublicKeyandgetPrivateKeyinstead, returning the appropriate key as a string in each case.

TheClientConnectionclass in Example 10-4 will have itsserviceStartedmethod called as soon as the client has successfully logged in. It callsself.openChannelwith aCommandChannel object, which is a subclass ofchannel.SSHChannel. This object is used to work with an authenticated channel to the SSH server. ItschannelOpenmethod is called when the channel is ready. At this point, you can callself.conn.sendRequestto send a command to the server. You have to encode data sent over SSH as a specially formatted network string; to get a string in this format, pass it to thetwisted.conch.common.NSfunction. Set the keyword argumentwantReplytoTrueif you’re interested in getting a response from the command; this setting will causesendRequestto return aDeferredthat will be called back when the command is completed. (If you don’t setwantReplytoTrue,sendRequestwill returnNone.) As data is received from the server, it will be passed todataReceived. Once you’re done using the channel, close it by callingself.conn.sendEOF. Theclosed method will be called to let you know when the channel has been successfully closed.



 
 
>>> More Python Articles          >>> More By O'Reilly Media
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PYTHON ARTICLES

- Python Big Data Company Gets DARPA Funding
- Python 32 Now Available
- Final Alpha for Python 3.2 is Released
- Python 3.1: String Formatting
- Python 3.1: Strings and Quotes
- Python 3.1: Programming Basics and Strings
- Tuples and Other Python Object Types
- The Dictionary Python Object Type
- String and List Python Object Types
- Introducing Python Object Types
- Mobile Programming using PyS60: Advanced UI ...
- Nested Functions in Python
- Python Parameters, Functions and Arguments
- Python Statements and Functions
- Statements and Iterators in Python

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: