1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 portal-related functionality inspired by twisted.cred.portal
24 """
25
26 from twisted.spread import flavors
27 from twisted.internet import defer
28 from twisted.cred import error
29 from twisted.cred.portal import Portal
30 from twisted.python import failure, reflect
31 from twisted.python.components import registerAdapter
32
33 from flumotion.common import keycards, log, interfaces
34 from flumotion.twisted.pb import _FPortalRoot
35
37 """
38 I am a portal for an FPB server using a bouncer to decide on FPB client
39 access.
40 """
41
42 logCategory = "BouncerPortal"
43
45 """
46 Create a BouncerPortal to a L{twisted.cred.portal.IRealm}.
47
48 @param realm: an implementor of L{twisted.cred.portal.IRealm}
49 @param bouncer: a bouncer to use for authentication
50 @type bouncer: L{flumotion.component.bouncers.bouncer.Bouncer}
51 """
52 self.realm = realm
53 self.bouncer = bouncer
54 self._adminCounter = 0
55
57 """
58 Return the Keycard interfaces supported by this portal's bouncer.
59
60 @rtype: L{defer.Deferred} firing list of str
61 """
62 if not self.bouncer:
63 self.error('No bouncer configured, no logins possible')
64 list = [reflect.qual(k) for k in self.bouncer.keycardClasses]
65 return defer.succeed(list)
66
67 - def login(self, keycard, mind, *ifaces):
68 """
69 Log in the keycard to the portal using the bouncer.
70
71 @param keycard: the keycard used to login
72 @type keycard: L{flumotion.common.keycards.Keycard}
73 @param mind: a reference to the client-side requester
74 @type mind: L{twisted.spread.pb.RemoteReference}
75 @param ifaces: a list of interfaces for the perspective that the
76 mind wishes to attach to
77
78 @returns: a deferred, which will fire a tuple of
79 (interface, avatarAspect, logout) or None.
80 """
81 self.debug("_login(keycard=%r, mind=%r, ifaces=%r)" % (
82 keycard, mind, ifaces))
83 if not self.bouncer:
84 self.warning("no bouncer, refusing login")
85 return defer.succeed(None)
86 else:
87 d = defer.maybeDeferred(self.bouncer.authenticate, keycard)
88
89 d.addCallback(self._authenticateCallback, mind, *ifaces)
90 return d
91
93
94 if not result:
95
96 f = failure.Failure(error.UnauthorizedLogin())
97 self.info("unauthorized login for interfaces %r", ifaces)
98 return f
99
100 keycard = result
101 if not keycard.state == keycards.AUTHENTICATED:
102
103 self.log('returning keycard for further authentication')
104 return keycard
105
106
107
108 self.debug('authenticated login of %r into realm %r', keycard,
109 self.realm)
110
111 if interfaces.IAdminMedium in ifaces:
112
113 keycard.avatarId = "admin-%06x" % self._adminCounter
114 self._adminCounter += 1
115
116 self.log('calling %r.requestAvatar(keycard=%r, mind=%r, ifaces=%r)',
117 self.realm, keycard, mind, ifaces)
118
119 return self.realm.requestAvatar(keycard.avatarId, keycard, mind, *ifaces)
120 registerAdapter(_FPortalRoot, BouncerPortal, flavors.IPBRoot)
121