From 72a3d7cf2c3a56b67e25af4e9f36249834376e16 Mon Sep 17 00:00:00 2001 From: helmutm Date: Sat, 18 Feb 2006 15:53:34 +0000 Subject: [PATCH] Clean-up and improvements on twisted.manhole git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1086 fd906abe-77d9-0310-91a1-e0d9ade77398 --- twisted/manhole.py | 93 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 22 deletions(-) diff --git a/twisted/manhole.py b/twisted/manhole.py index fe6e08e..0f7b62d 100644 --- a/twisted/manhole.py +++ b/twisted/manhole.py @@ -1,14 +1,37 @@ """ +A simple twisted manhole that allows you to access a running Zope 3 +instance via a python command line without having to run ZEO. + +You may run it for testing purposes via `python manhole.py` (note that +the twisted library must be reachable via your PYTHONPATH) and log in +from another console window using `ssh -p 5001 admin@localhost`. The +password is defined below in the "reactor.listenTCP()" statement. The +manhole script may be stopped with Ctrl-C. + +Note that this will open up a serious security hole on your computer +as now anybody knowing this password may login to the Python console +and get full access to the system with the permissions of the user +running the manhole script. + +In order to use it with Zope copy the cybertools.twisted-configure.zcml +to the etc/package-includes directory of your Zope instance and restart +Zope. You can then log in with ssh like shown above, using the username +and password of the zope.manager principal defined in your principals.zcml. + +After logging in use the `help` command to get more information. + $Id$ """ -from twisted.internet import reactor, protocol +from twisted.internet import reactor, protocol, defer from twisted.protocols import basic -from twisted.cred import portal, checkers +from twisted.cred import portal, checkers, credentials, error as credError from twisted.conch import manhole, manhole_ssh +from zope.interface import implements try: from zope.app.publication.zopepublication import ZopePublication from zope.app.component.hooks import setSite + from zope.app.security.principalregistry import principalRegistry from zope.app import zapi hasZope = True except: @@ -17,34 +40,60 @@ import time import sys from cStringIO import StringIO + def getManholeFactory(namespace, **passwords): realm = manhole_ssh.TerminalRealm() def getManhole(_): return manhole.Manhole(namespace) realm.chainedProtocolFactory.protocolFactory = getManhole p = portal.Portal(realm) - p.registerChecker( - checkers.InMemoryUsernamePasswordDatabaseDontUse(**passwords)) + checker = (hasZope and ZopeManagerChecker() or + checkers.InMemoryUsernamePasswordDatabaseDontUse(**passwords)) + p.registerChecker(checker) return manhole_ssh.ConchFactory(p) + +class ZopeManagerChecker(object): + + implements(checkers.ICredentialsChecker) + credentialInterfaces = (credentials.IUsernamePassword,) + + def requestAvatarId(self, credentials): + manager = principalRegistry.getPrincipal('zope.manager') + login = credentials.username + password = credentials.password + if login == manager.getLogin() and manager.validate(password): + return defer.succeed(login) + return defer.fail(credError.UnauthorizedLogin( + 'User/password not correct')) + + def printTime(): print 'twisted.manhole running:', time.strftime('%H:%M:%S') reactor.callLater(60, printTime) -def help(): - info = """ - Use dir() to see what variables and functions are available.""" - zopeInfo = """ - In order to get access to local utilities and adapters you should - issue a setSite(root). Don't forget to call setSite() before - finishing your session. - You may use x = zapi.traverse(root, 'path/to/object') to get an - object in your folder hierarchy. Then you may call any method or - access any attribute of this object.""" - print info - if hasZope: - print zopeInfo - print + +class Help(object): + + def __repr__(self): + info = """ + Use dir() to see what variables and functions are available. + """ + zopeInfo = """ + You may use x = zapi.traverse(root, 'path/to/object') to get an + object in your folder hierarchy. Then you may call any method or + access any attribute of this object. + + In order to get access to local utilities and adapters you may + issue a setSite(root). Don't forget to call setSite() before + finishing your session in order to reset this setting. + """ + return info + (hasZope and zopeInfo or '') + + def __call__(self): + print self + +help = Help() def startup(event=None, port=5001): @@ -52,14 +101,14 @@ def startup(event=None, port=5001): printTime() d = globals() if hasZope and event is not None: - conn =event.database.open() - root = conn.root()[ZopePublication.root_name] + connection = event.database.open() + root = connection.root()[ZopePublication.root_name] else: hasZope = False d.update(locals()) namespace = {} - for key in ('__builtins__', 'conn', 'event', 'setSite', 'hasZope', 'zapi', - 'root', '__doc__', 'help'): + for key in ('__builtins__', 'connection', 'event', 'setSite', 'hasZope', + 'zapi', 'root', '__doc__', 'help'): if key in d: namespace[key] = d[key] # TODO: get admin password from somewhere else or use a real checker.