1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """
23 A bouncer that combines other bouncers.
24 """
25
26 from twisted.internet import defer
27 from twisted.python import util
28
29 from flumotion.common import keycards, watched
30 from flumotion.common import python, messages, errors, documentation
31 from flumotion.common.i18n import N_, gettexter
32 from flumotion.component.bouncers import base, component, combinator
33
34 T_ = gettexter()
35
36
38
39 logCategory = 'multibouncer'
40
41 keycardClasses = (keycards.KeycardHTTPGetArguments,
42 keycards.KeycardGeneric, keycards.KeycardUACPCC,
43 keycards.KeycardUACPP, keycards.KeycardToken)
44
50
64
65
66
67 entries = self.config['plugs'].get(base.BOUNCER_ALGORITHM_SOCKET, [])
68 algorithms = self.plugs.get(base.BOUNCER_ALGORITHM_SOCKET, [])
69
70
71
72 self.check_algorithms(algorithms)
73
74 for entry, algorithm in zip(entries, algorithms):
75
76 name = add_entry(entry, algorithm)
77
78 algorithm.set_keycard_store(self.watchable_keycards)
79
80
81 expire = lambda ids: self.algorithm_expire_keycard_ids(ids, name)
82 algorithm.set_expire_function(expire)
83
84
85
86 if not self.algorithms:
87 return
88
89 self.debug("configured with algorithms %r", self.algorithms.keys())
90
91
92 props = self.config['properties']
93 self.combinator = combinator.AlgorithmCombinator(self.algorithms)
94
95 if 'combination' in props and combinator.pyparsing is None:
96 m = messages.Error(T_(N_(
97 "To use the 'combination' property you need to "
98 "have the 'pyparsing' module installed.\n")),
99 mid='missing-pyparsing')
100 documentation.messageAddPythonInstall(m, 'pyparsing')
101 self.addMessage(m)
102 raise errors.ComponentSetupHandledError()
103
104
105 spec = props.get('combination', ' and '.join(self.algorithms.keys()))
106 self.debug("using combination %s", spec)
107 try:
108 self.combinator.create_combination(spec)
109 except combinator.ParseException, e:
110 m = messages.Error(T_(N_(
111 "Invalid algorithms combination: %s"), str(e)),
112 mid='wrong-combination')
113 self.addMessage(m)
114 raise errors.ComponentSetupHandledError()
115
123
146
147 return d.addCallback(authenticated, keycard)
148
150
151 del self.contexts[keycard.id]
152 del self.watchable_keycards[keycard.id]
153
155
156
157 to_expire = []
158
159 self.debug("algorithm %r requested expiration of keycards %r",
160 name, keycard_ids)
161
162 for keycard_id in keycard_ids:
163
164 context = self.contexts[keycard_id]
165 context[name] = False
166
167
168
169
170 if not self.combinator.synchronous_evaluate(context):
171 self.log("keycard with id %r will be expired", keycard_id)
172 to_expire.append(keycard_id)
173
174 return self.expireKeycardIds(to_expire)
175
176
178 """A multibouncer that has a static list of bouncer algorithm plugs"""
179
180 algorithmClasses = None
181
183 for algorithm in self.algorithms.itervalues():
184 return algorithm
185
190
192 if self.algorithmClasses is None:
193 raise NotImplementedError("Subclass did not choose algorithm")
194
195 def start_algorithm(d, algorithm, name):
196 self.algorithms[name] = algorithm
197 d.addCallback(lambda _: defer.maybeDeferred(algorithm.start, self))
198 d.addCallback(algorithm_started, algorithm, name)
199
200 def algorithm_started(_, algorithm, name):
201 algorithm.set_keycard_store(self.watchable_keycards)
202
203 expire = lambda ids: self.algorithm_expire_keycard_ids(ids, name)
204 algorithm.set_expire_function(expire)
205
206 try:
207 klasses = iter(self.algorithmClasses)
208 except TypeError:
209 klasses = iter((self.algorithmClasses, ))
210
211 d = defer.Deferred()
212 for klass in klasses:
213 name = klass.__name__
214 algorithm = klass({'properties': self.config['properties']})
215 start_algorithm(d, algorithm, name)
216
217 def create_combinator(_):
218 self.combinator = combinator.AlgorithmCombinator(self.algorithms)
219 spec = ' and '.join(self.algorithms.keys())
220 self.combinator.create_combination(spec)
221
222 d.addCallback(create_combinator)
223
224 d.callback(None)
225 return d
226
229
231 d = defer.Deferred()
232 for algorithm in self.algorithms.values():
233 d.addCallback(lambda _: defer.maybeDeferred(algorithm.stop, self))
234
235 d.callback(None)
236 return d
237