def complete(self): """ Check to see if SASL negotiation has completed successfully, including a mutual authentication check if the chosen mechanism supports that and mutual authentication was requested via the `mutual_auth` parameter for the `SASLClient` constructor. """ if not self._chosen_mech: raise SASLError("A mechanism has not been chosen yet") return self._chosen_mech.complete
def _fetch_properties(self, *properties): """ Ensure this mechanism has the needed properties. If they haven't been set yet, the registered callback function will be called for each property to retrieve a value. """ needed = [p for p in properties if getattr(self, p, None) is None] if needed and not self.sasl.callback: raise SASLError('The following properties are required, but a ' 'callback has not been set: %s' % ', '.join(needed)) for prop in needed: setattr(self, prop, self.sasl.callback(prop))
def choose_mechanism(self, mechanism_choices, allow_anonymous=True, allow_plaintext=True, allow_active=True, allow_dictionary=True): """ Choose a mechanism from a list of mechanisms based on security scores for mechanisms and required properties of the mechanism. If `allow_anonymous` is ``False``, mechanisms that allow anonymous authentication will not be considered. If `allow_plaintext` is ``False``, mechanisms that transmit sensitive information in plaintext (and are thus susceptible to passive listening attacks) will not be considered. If `allow_active` is ``False``, mechanisms that are susceptible to active non-dictionary attacks (MITM, injection) will not be considered. If `allow_dictionary` is ``False, mechanisms that are susceptible to passive dictionary attacks will not be considered. """ candidates = [ mech_mod.mechanisms[choice] for choice in mechanism_choices if choice in mech_mod.mechanisms ] if not allow_anonymous: candidates = [m for m in candidates if not m.allows_anonymous] if not allow_plaintext: candidates = [m for m in candidates if not m.uses_plaintext] if not allow_active: candidates = [m for m in candidates if m.active_safe] if not allow_dictionary: candidates = [m for m in candidates if m.dictionary_safe] if not candidates: raise SASLError("None of the mechanisms listed meet all " "required properties") # Pick the best mechanism based on its security score mech_class = max(candidates, key=lambda mech: mech.score) self.mechanism = mech_class.name self._chosen_mech = mech_class(self, **self._mech_props)
def wrapped(self, *args, **kwargs): if not self._chosen_mech: raise SASLError("A mechanism has not been chosen yet") return f(self, *args, **kwargs)