Using Authentication with Perspective Broker

Example 5-8 in Chapter 5 demonstrated Perspective Broker without any authentication in place. In the real world, though, you probably don't want to give just anyone remote access to objects in your application. You usually need to have an authentication layer in place to control who gets in, and what they're allowed to do.

Perspective Broker lets you perform authentication by integrating with twisted.cred. Adding authentication makes Perspective Broker live up to its name: it can provide different perspectives to different users, hiding or exposing objects and methods depending on the user's permissions.

6.4.1. How Do I Do That?

Create a realm that returns pb.Avatar objects. Each avatar should have methods prefixed with perspective_ that the user of that avatar will be allowed to run. Connect the realm to a Portal, add credentials checkers, and pass the Portal to a pb.PBServerFactory. Example 6-4 demonstrates a Perspective Broker server with authentication.

Example 6-4. pbcred.py


from twisted.spread import pb

from twisted.cred import checkers, portal

from zope.interface import implements



class TodoList:

 def _ _init_ _(self):

 self.items = []



 def listItems(self):

 return self.items[:] # return copy of list



 def addItem(self, item):

 self.items.append(item)

 return len(self.items) - 1



 def deleteItem(self, index):

 del(self.items[index])



class UserPerspective(pb.Avatar):

 def _ _init_ _(self, todoList):

 self.todoList = todoList



 def perspective_listItems(self):

 return self.todoList.listItems( )



class AdminPerspective(UserPerspective):

 def _ _init_ _(self, todoList):

 self.todoList = todoList



 def perspective_addItem(self, item):

 return self.todoList.addItem(item)



 def perspective_deleteItem(self, index):

 return self.todoList.deleteItem(index)



class TestRealm(object):

 implements(portal.IRealm)



 def _ _init_ _(self, todoList):

 self.todoList = todoList



 def requestAvatar(self, avatarId, mind, *interfaces):

 if not pb.IPerspective in interfaces:

 raise NotImplementedError, "No supported avatar interface."

 else:

 if avatarId == 'admin':

 avatar = AdminPerspective(self.todoList)

 else:

 avatar = UserPerspective(self.todoList)

 return pb.IPerspective, avatar, lambda: None



if __name__ == "_ _main_ _":

 import sys

 from twisted.internet import reactor

 p = portal.Portal(TestRealm(TodoList( )))

 p.registerChecker(

 checkers.InMemoryUsernamePasswordDatabaseDontUse(

 admin='aaa',

 guest='bbb'))

 reactor.listenTCP(8789, pb.PBServerFactory(p))

 reactor.run( )

To test this server, write a Perspective Broker client that supports authentication. Create a PBClientFactory and call login (instead of geTRootObject) with your user's credentials as the only argument. Example 6-5 is a pb client that uses a username and password for authentication.

Example 6-5. pbcred_client.py


from twisted.spread import pb

from twisted.internet import reactor

from twisted.cred import credentials



class PbAuthTester(object):

 def _ _init_ _(self, credentials):

 self.credentials = credentials

 self.server = None



 def runTests(self):

 self.connect( ).addCallback(

 lambda _: self.listItems( )).addCallback(

 lambda _: self.addItem( )).addErrback(

 self._catchFailure).addCallback(

 lambda _: reactor.stop( ))



 def connect(self):

 factory = pb.PBClientFactory( )

 reactor.connectTCP("localhost", 8789, factory)

 return factory.login(self.credentials).addCallback(self._connected)



 def _connected(self, rootObj):

 self.server = rootObj



 def listItems(self):

 return self.server.callRemote("listItems").addCallback(self._gotList)



 def _gotList(self, list):

 print "%i items in TODO list." % (len(list))



 def addItem(self):

 return self.server.callRemote(

 "addItem", "Buy groceries").addCallback(

 self._addedItem)



 def _addedItem(self, result):

 print "Added 1 item."



 def _catchFailure(self, failure):

 print "Error:", failure.getErrorMessage( )



if __name__ == "_ _main_ _":

 import sys

 username, password = sys.argv[1:3]

 creds = credentials.UsernamePassword(username, password)

 tester = PbAuthTester(creds)

 tester.runTests( )

 reactor.run( )

Run pbcred.py to start the server. pbcred_client.py takes a username and password as arguments. Try it with the name and password admin and aaa. It will list the number of current items on the server, and then add an item:


 $ python pbcred_client.py admin aaa

 Getting item list...

 0 items in list.

 Adding new item...

 Added 1 item.

Then try again using the username guest and password bbb. You'll be able to get the item count, but you'll get an error trying to add an item:


 $ python pbcred_client.py guest bbb

 Getting item list...

 1 items in list.

 Adding new item...

 Error: UserPerspective instance has no attribute 'perspective_addItem'

This is because the guest user does not get the same perspective as admin. The guest user's perspective is read-only, and doesn't include methods for adding or deleting items.

6.4.2. How Does That Work?

The server provides the four standard objects needed for Twisted authentication: avatars, a realm, a portal, and credentials checkers. The TestRealm returns either a UserPerspective avatar or a AdminPerspective avatar, depending on the user's name. The admin user will get an AdminPerspective avatar, which includes the additional methods perspective_addItem and perspective_deleteItem. UserPerspective and AdminPerspective both inherit from pb.Avatar, and provide methods prefixed with perspective_. pb.Avatar objects implement the pb.IPerspective interface; the Perspective Broker server will pass this interface to Portal.login to request a pb.Avatar.

For the sake of simplicity, Example 6-5 uses the InMemoryPasswordDatabaseDontUse credentials checker class, which is included in twisted.cred.checkers for use in test programs only. In production, you'd use a real credentials checker that authenticated usernames and passwords against a file, database, or another service.

To use authentication, the client calls PBClient.login instead of calling PBClient.getRootObject directly. The login function attempts to log in using a set of credentials and then returns a reference to a pb.Avatar object on the server representing that user's perspective.

Getting Started

Building Simple Clients and Servers

Web Clients

Web Servers

Web Services and RPC

Authentication

Mail Clients

Mail Servers

NNTP Clients and Servers

SSH

Services, Processes, and Logging



Twisted Network Programming Essentials
Twisted Network Programming Essentials
ISBN: 0596100329
EAN: 2147483647
Year: 2004
Pages: 107
Authors: Abe Fettig

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net