Continued reorganization and streamlining.

This commit is contained in:
Lance Stout
2011-07-01 14:45:55 -07:00
parent 754ac5092a
commit 634f5d691b
19 changed files with 73 additions and 34 deletions

View File

@@ -0,0 +1,10 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.features.feature_mechanisms.mechanisms import feature_mechanisms
from sleekxmpp.features.feature_mechanisms.stanza import *

View File

@@ -0,0 +1,116 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
import logging
from sleekxmpp.stanza import stream
from sleekxmpp.xmlstream import RestartStream
from sleekxmpp.xmlstream.matcher import *
from sleekxmpp.xmlstream.handler import *
from sleekxmpp.plugins.base import base_plugin
log = logging.getLogger(__name__)
class feature_mechanisms(base_plugin):
def plugin_init(self):
self.name = 'SASL Mechanisms'
self.rfc = '6120'
self.description = "SASL Stream Feature"
self.xmpp.register_stanza(stream.sasl.Success)
self.xmpp.register_stanza(stream.sasl.Failure)
self.xmpp.register_stanza(stream.sasl.Auth)
self._mechanism_handlers = {}
self._mechanism_priorities = []
self.xmpp.register_handler(
Callback('SASL Success',
MatchXPath(stream.sasl.Success.tag_name()),
self._handle_success,
instream=True,
once=True))
self.xmpp.register_handler(
Callback('SASL Failure',
MatchXPath(stream.sasl.Failure.tag_name()),
self._handle_fail,
instream=True,
once=True))
self.xmpp.register_feature('mechanisms',
self._handle_sasl_auth,
restart=True,
order=self.config.get('order', 100))
def register_mechanism(self, name, handler, priority=0):
"""
Register a handler for a SASL authentication mechanism.
Arguments:
name -- The name of the mechanism (all caps)
handler -- The function that will perform the
authentication. The function must
return True if it is able to carry
out the authentication, False if
a required condition is not met.
priority -- An integer value indicating the
preferred ordering for the mechanism.
High values will be attempted first.
"""
self._mechanism_handlers[name] = handler
self._mechanism_priorities.append((priority, name))
self._mechanism_priorities.sort(reverse=True)
def remove_mechanism(self, name):
"""
Remove support for a given SASL authentication mechanism.
Arguments:
name -- The name of the mechanism to remove (all caps)
"""
if name in self._mechanism_handlers:
del self._mechanism_handlers[name]
p = self._mechanism_priorities
self._mechanism_priorities = [i for i in p if i[1] != name]
def _handle_sasl_auth(self, features):
"""
Handle authenticating using SASL.
Arguments:
features -- The stream features stanza.
"""
for priority, mech in self._mechanism_priorities:
if mech in features['mechanisms']:
log.debug('Attempt to use SASL %s' % mech)
if self._mechanism_handlers[mech]():
break
else:
log.error("No appropriate login method.")
self.xmpp.event("no_auth", direct=True)
self.xmpp.disconnect()
return True
def _handle_success(self, stanza):
"""SASL authentication succeeded. Restart the stream."""
self.xmpp.authenticated = True
self.xmpp.features.append('mechanisms')
raise RestartStream()
def _handle_fail(self, stanza):
"""SASL authentication failed. Disconnect and shutdown."""
log.info("Authentication failed.")
self.xmpp.event("failed_auth", direct=True)
self.xmpp.disconnect()
log.debug("Starting SASL Auth")
return True

View File

@@ -0,0 +1,104 @@
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
This file is part of SleekXMPP.
See the file LICENSE for copying permission.
"""
from sleekxmpp.stanza import StreamFeatures
from sleekxmpp.xmlstream import ElementBase, StanzaBase, ET
from sleekxmpp.xmlstream import register_stanza_plugin
class Mechanisms(ElementBase):
"""
"""
name = 'mechanisms'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = set(('mechanisms', 'required'))
plugin_attrib = name
is_extension = True
def get_required(self):
"""
"""
return True
def get_mechanisms(self):
"""
"""
results = []
mechs = self.findall('{%s}mechanism' % self.namespace)
if mechs:
for mech in mechs:
results.append(mech.text)
return results
def set_mechanisms(self, values):
"""
"""
self.del_mechanisms()
for val in values:
mech = ET.Element('{%s}mechanism' % self.namespace)
mech.text = val
self.append(mech)
def del_mechanisms(self):
"""
"""
mechs = self.findall('{%s}mechanism' % self.namespace)
if mechs:
for mech in mechs:
self.xml.remove(mech)
class Success(StanzaBase):
"""
"""
name = 'success'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = set()
plugin_attrib = name
class Failure(StanzaBase):
"""
"""
name = 'failure'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = set()
plugin_attrib = name
class Auth(StanzaBase):
"""
"""
name = 'auth'
namespace = 'urn:ietf:params:xml:ns:xmpp-sasl'
interfaces = set(('mechanism', 'value'))
plugin_attrib = name
def setup(self, xml):
StanzaBase.setup(self, xml)
self.xml.tag = self.tag_name()
def set_value(self, value):
self.xml.text = value
def get_value(self):
return self.xml.text
def del_value(self):
self.xml.text = ''
register_stanza_plugin(StreamFeatures, Mechanisms)