1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from zope.interface import implements
17 from twisted.spread import pb
18 from twisted.python import failure, log
19 from twisted.internet import defer
20 from twisted.cred import portal, checkers, credentials, error
21 from twisted.application import service, strports
22
23 debug = False
24
26 """
27 A centralized manager for PB ports and authentication on them.
28
29 Allows various pieces of code to request a (port, username) combo, along
30 with a password and a perspective factory.
31 """
33 service.MultiService.__init__(self)
34 self.dispatchers = {}
35
36 - def register(self, portstr, username, password, pfactory):
37 """
38 Register a perspective factory PFACTORY to be executed when a PB
39 connection arrives on PORTSTR with USERNAME/PASSWORD. Returns a
40 Registration object which can be used to unregister later.
41 """
42
43 if type(portstr) == type(0) or ':' not in portstr:
44 portstr = "tcp:%s" % portstr
45
46 reg = Registration(self, portstr, username)
47
48 if portstr not in self.dispatchers:
49 disp = self.dispatchers[portstr] = Dispatcher(portstr)
50 disp.setServiceParent(self)
51 else:
52 disp = self.dispatchers[portstr]
53
54 disp.register(username, password, pfactory)
55
56 return reg
57
59 disp = self.dispatchers[registration.portstr]
60 disp.unregister(registration.username)
61 registration.username = None
62 if not disp.users:
63 disp = self.dispatchers[registration.portstr]
64 del self.dispatchers[registration.portstr]
65 return disp.disownServiceParent()
66 return defer.succeed(None)
67
68
70 - def __init__(self, pbmanager, portstr, username):
77
79 """
80 Unregister this registration, removing the username from the port, and
81 closing the port if there are no more users left. Returns a Deferred.
82 """
83 return self.pbmanager._unregister(self)
84
85
87 implements(portal.IRealm, checkers.ICredentialsChecker)
88
89 credentialInterfaces = [ credentials.IUsernamePassword,
90 credentials.IUsernameHashedPassword ]
91
93 service.MultiService.__init__(self)
94 self.portstr = portstr
95 self.users = {}
96
97
98 self.portal = portal.Portal(self)
99 self.portal.registerChecker(self)
100 self.serverFactory = pb.PBServerFactory(self.portal)
101 self.serverFactory.unsafeTraceback = True
102 self.serverPort = strports.service(portstr, self.serverFactory)
103 self.serverPort.setServiceParent(self)
104
106
107 return self.serverPort.getHost().port
108
111
114
115 - def register(self, username, password, pfactory):
116 if debug:
117 log.msg("registering username '%s' on pb port %s: %s"
118 % (username, self.portstr, pfactory))
119 if username in self.users:
120 raise KeyError, ("username '%s' is already registered on PB port %s"
121 % (username, self.portstr))
122 self.users[username] = (password, pfactory)
123
125 if debug:
126 log.msg("unregistering username '%s' on pb port %s"
127 % (username, self.portstr))
128 del self.users[username]
129
130
131
133 assert interface == pb.IPerspective
134 if username not in self.users:
135 d = defer.succeed(None)
136 else:
137 _, afactory = self.users.get(username)
138 d = defer.maybeDeferred(afactory, mind, username)
139
140
141 def check(persp):
142 if not persp:
143 raise ValueError("no perspective for '%s'" % username)
144 return persp
145 d.addCallback(check)
146
147
148 def call_attached(persp):
149 d = defer.maybeDeferred(persp.attached, mind)
150 d.addCallback(lambda _ : persp)
151 return d
152 d.addCallback(call_attached)
153
154
155 def done(persp):
156 return (pb.IPerspective, persp, lambda: persp.detached(mind))
157 d.addCallback(done)
158
159 return d
160
161
162
164 if creds.username in self.users:
165 password, _ = self.users[creds.username]
166 d = defer.maybeDeferred(creds.checkPassword, password)
167 def check(matched):
168 if not matched:
169 return failure.Failure(error.UnauthorizedLogin())
170 return creds.username
171 d.addCallback(check)
172 return d
173 else:
174 return defer.fail(error.UnauthorizedLogin())
175