Home arrow Python arrow Page 2 - SSH with Twisted

Setting Up a Custom SSH Server continued - 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.

  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



sshserver.py will run an SSH server on port 2222. Connect to this server with an SSH client using the username admin and password aaa, and try typing some commands:

  $ ssh admin@localhost -p 2222
  admin@localhost's password: aaa

  >>> Welcome to my test SSH server. 
  Commands: clear echo help quit whoami
  $ whoami
  $ help echo
  Echo a string. Usage: echo my line of text
  $ echo hello SSH world!
  hello SSH world!
  $ quit

  Connection to localhost closed.

If you’ve already been using an SSH server on your local machine, you might get an error when you try to connect to the server in this example. You’ll get a message saying something like “Remote host identification has changed” or “Host key verification failed,” and your SSH client will refuse to connect.

The reason you get this error message is that your SSH client is remembering the public key used by your regular localhost SSH server. The server in Example 10-1 has its own key, and when the client sees that the keys are different, it gets suspicious that this new server may be an impostor pretending to be your regular localhost SSH server. To fix this problem, edit your ~/.ssh/known_hosts file (or wherever your SSH client keeps its list of recognized servers) and remove the localhost entry.

How Does That Work?

The SSHDemoProtocol class in Example 10-1 inherits fromtwisted.conch.recvline.HistoricRecvline.HistoricRecvLineis a protocol with built-in features for building command-line shells. It gives your shell features that most people take for granted in a modern shell, including backspacing, the ability to use the arrow keys to move the cursor forwards and backwards on the current line, and a command history that can be accessed using the up and down arrows.twisted.conch.recvlinealso provides a plainRecvLineclass that works the same way, but without the command history.

ThelineReceivedmethod inHistoricRecvLineis called whenever a user enters a line. Example 10-1 shows how you might override this method to parse and execute commands. There are a couple of differences betweenHistoricRecvLineand a regularProtocol, which come from the fact that withHistoricRecvLineyou’re actually manipulating the current contents of a user’s terminal window, rather than just printing out text. To print a line of output, useself.terminal.write; to go to the next line, useself.nextLine.

Thetwisted.conch.avatar.ConchUserclass represents the actions available to an authenticated SSH user. By default,ConchUser doesn’t allow the client to do anything. To make it possible for the user to get a shell, make his avatar implementtwisted.conch.interfaces.ISession. TheSSHDemoAvatarclass in Example 10-1 doesn’t actually implement all ofISession; it only implements enough for the user to get a shell. TheopenShellmethod will be called with atwisted.conch.ssh.session. SSHSessionProcessProtocolobject that represents the encrypted client’s end of the encrypted channel. You have to perform a few steps to connect the client’s protocol to your shell protocol so they can communicate with each other. First, wrap your protocol class in atwisted.conch.insults.insults.ServerProtocolobject. You can pass extra arguments toinsults.ServerProtocol, and it will use them to initialize your protocol object. This sets up your protocol to use a virtual terminal. Then usemakeConnectionto connect the two protocols to each other. The client’s protocol actually expectsmakeConnectionto be called with a an object implementing the lower-leveltwisted.internet.interfaces.ITransportinterface, not aProtocol; thetwisted.conch.session.wrapProtocolfunction wraps aProtocolin a minimalITransportinterface.

The library traditionally used for manipulating a Unix terminal is called curses. So the Twisted developers, never willing to pass up the chance to use a pun in a module name, chose the name insults for this library of classes for terminal programming.

To make a realm for your SSH server, write a class that has arequestAvatar method. The SSH server will callrequestAvatarwith the username asavatarIdandtwisted.conch.interfaces.IAvataras one of the interfaces. Return your subclass oftwisted.conch. avatar.ConchUser.

There’s only one more thing you’ll need to have a complete SSH server: a unique set of public and private keys. Example 10-1 demonstrates how you can use theCrypto.PublicKey.RSAmodule to generate these keys.RSA.generatetakes a key length as the first argument and an entropy-generating function as the second argument; thetwisted.conch.ssh.commonmodule provides theentropy.get_bytesfunction for this purpose.RSA.generatereturns aCrypto.PublicKey.RSA.RSAobjobject. You extract public and private key strings from theRSAobj by passing it to thegetPublicKeyStringandgetPrivateKeyStringfunctions from thetwisted.conch.ssh.keysmodule. Example 10-1 saves its keys to disk after generating them the first time it runs: you need to keep these keys preserved between clients so clients can identify and trust your sever.

Note that you wouldn’t want to callRSA.generateafter your program has entered the Twisted event loop.RSA.generateis a blocking function that can take quite some time to complete.

To run the SSH server, create a twisted.conch.ssh.factory.SSHFactory object. Set itsportalattribute to a portal using your realm, and register a credentials checker that can handletwisted.cred.credentials.IUsernamePasswordcredentials. Set theSSHFactory’spublicKeysattribute to a dictionary that matches encryption algorithms to key string objects. To get the RSA key string object, pass your public key as thedatakeyword tokeys.getPublicKeyString. Then set theprivateKeysattribute to a dictionary that matches protocols to key objects. To get the RSA private key object, pass your private key as thedata keyword tokeys.getPrivateKey. BothgetPublicKeyString andgetPrivateKeycan take a filename keyword instead, to load a key directly from a file. Once theSSHFactoryhas the keys, it’s ready to go. Callreactor.listenTCPto have it start listening on a port and you’ve got an SSH server.

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

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort


- 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: