diff --git a/twisted/__init__.py b/twisted/__init__.py index d20a73e..4bc90fb 100644 --- a/twisted/__init__.py +++ b/twisted/__init__.py @@ -2,46 +2,3 @@ $Id$ """ -from twisted.internet import reactor, protocol -from twisted.protocols import basic -from twisted.cred import portal, checkers -from twisted.conch import manhole, manhole_ssh -try: - from zope.app.publication.zopepublication import ZopePublication - from zope.app.component.hooks import setSite - hasZope = True -except: - hasZope = False -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)) - return manhole_ssh.ConchFactory(p) - -def printTime(): - print 'twisted.manhole running:', time.strftime('%H:%M:%S') - reactor.callLater(60, printTime) - -#reactor.callLater(10, stopReactor) -#reactor.listenTCP(5222, EchoServerFactory()) - -def startup(event=None): - printTime() - d = globals() - #d['event'] = event - if hasZope and event is not None: - conn =event.database.open() - root = conn.root()[ZopePublication.root_name] - d.update(locals()) - reactor.listenTCP(5001, getManholeFactory(d, admin='aaa')) - -if __name__ == '__main__': - startup() \ No newline at end of file diff --git a/twisted/configure.zcml b/twisted/configure.zcml index a4f3b8a..5226091 100644 --- a/twisted/configure.zcml +++ b/twisted/configure.zcml @@ -2,10 +2,17 @@ - + diff --git a/twisted/manhole.py b/twisted/manhole.py index 9ce5d92..dc00a18 100644 --- a/twisted/manhole.py +++ b/twisted/manhole.py @@ -15,7 +15,10 @@ 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 +Zope. Open the manhole via the "Manhole Control" Tab of the "Manage process" +menu. + +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. @@ -26,12 +29,15 @@ $Id$ from twisted.internet import reactor, protocol, defer from twisted.protocols import basic from twisted.cred import portal, checkers, credentials, error as credError -from twisted.conch import manhole, manhole_ssh +from twisted.conch import manhole as 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.security import settings + from zope.app.security.interfaces import IAuthentication + from zope.app.securitypolicy.principalrole import principalRoleManager from zope.app import zapi import transaction hasZope = True @@ -41,10 +47,16 @@ import time import sys from cStringIO import StringIO +listener = None +factory = None +printLog = None +port = 5001 + def getManholeFactory(namespace, **passwords): realm = manhole_ssh.TerminalRealm() def getManhole(_): + #return manhole.ColoredManhole(namespace) return manhole.Manhole(namespace) realm.chainedProtocolFactory.protocolFactory = getManhole p = portal.Portal(realm) @@ -60,18 +72,26 @@ class ZopeManagerChecker(object): 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) + # TODO: This should be based on the official Zope API stuff, e.g. via: + #principalRegistry = zapi.getUtility(IAuthentication) + principal = principalRegistry.getPrincipalByLogin(login) + if principal.validate(password): + roles = principalRoleManager.getRolesForPrincipal(principal.id) + for role, setting in roles: + if role == 'zope.Manager' and setting == settings.Allow: + return defer.succeed(login) + return defer.fail(credError.UnauthorizedLogin( + 'Insufficient permissions')) return defer.fail(credError.UnauthorizedLogin( 'User/password not correct')) def printTime(): - print 'twisted.manhole running:', time.strftime('%H:%M:%S') - reactor.callLater(600, printTime) + global printLog + print '***', time.strftime('%H:%M:%S'), '- twisted.manhole open ***' + printLog = reactor.callLater(600, printTime) class Help(object): @@ -101,23 +121,32 @@ class Help(object): help = Help() -def startup(event=None, port=5001): - global hasZope +def open(port=5001, request=None): + global hasZope, factory, listener printTime() d = globals() - if hasZope and event is not None: - connection = event.database.open() + if hasZope and request is not None: + database = request.publication.db + connection = database.open() root = connection.root()[ZopePublication.root_name] else: hasZope = False d.update(locals()) namespace = {} for key in ('__builtins__', 'connection', 'event', 'setSite', 'hasZope', - 'zapi', 'transaction', 'root', '__doc__', 'help'): + 'zapi', 'transaction', 'root', '__doc__', 'help', + 'manholeFactory', 'context'): if key in d: namespace[key] = d[key] # TODO: get admin password from somewhere else or use a real checker. - reactor.listenTCP(port, getManholeFactory(namespace, admin='aaa')) + factory = getManholeFactory(namespace, admin='aaa') + listener = reactor.listenTCP(port, factory) + +def close(): + global listener + listener.stopListening() + listener = None + if __name__ == '__main__': port = 5001 diff --git a/twisted/manhole_control.pt b/twisted/manhole_control.pt new file mode 100644 index 0000000..96f19a9 --- /dev/null +++ b/twisted/manhole_control.pt @@ -0,0 +1,43 @@ + + + ZODB Controller + + +
+ + + +
+
Manhole is open.
+
+
+
Manhole is closed.
+
+ +
+ +
+ Port: + +
+
+ + Open manhole + Close manhole +
+
+
+ +
+
+
+ +
+ + diff --git a/twisted/manhole_control.py b/twisted/manhole_control.py new file mode 100644 index 0000000..3264102 --- /dev/null +++ b/twisted/manhole_control.py @@ -0,0 +1,43 @@ +############################################################################## +# +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# +############################################################################## +""" Manhole Control View + +$Id$ +""" +__docformat__ = 'restructuredtext' + +from cybertools.twisted import manhole + +class ManholeControlView(object): + + def isOpen(self): + return manhole.listener is not None + + def toggleState(self): + if self.isOpen(): + manhole.close() + else: + manhole.open(self.port(), self.request) + + def port(self): + return manhole.port + + def update(self): + if not self.request.get('form_submitted'): + return + port = self.request.get('manhole.port') + if port: + manhole.port = int(port) + if self.request.get('manhole.setting', False): + self.toggleState()