From e6c95f0a2acfd56ad47f60d9576a0db5458ed118 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Fri, 19 Oct 2012 00:01:02 -0700 Subject: Add support for XEP-0257: Client Certificate Management for SASL EXTERNAL --- setup.py | 1 + sleekxmpp/plugins/__init__.py | 1 + sleekxmpp/plugins/xep_0257/__init__.py | 17 +++++ .../plugins/xep_0257/client_cert_management.py | 65 ++++++++++++++++ sleekxmpp/plugins/xep_0257/stanza.py | 87 ++++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 sleekxmpp/plugins/xep_0257/__init__.py create mode 100644 sleekxmpp/plugins/xep_0257/client_cert_management.py create mode 100644 sleekxmpp/plugins/xep_0257/stanza.py diff --git a/setup.py b/setup.py index 247b3d91..13203611 100755 --- a/setup.py +++ b/setup.py @@ -102,6 +102,7 @@ packages = [ 'sleekxmpp', 'sleekxmpp/plugins/xep_0231', 'sleekxmpp/plugins/xep_0235', 'sleekxmpp/plugins/xep_0249', + 'sleekxmpp/plugins/xep_0257', 'sleekxmpp/plugins/xep_0258', 'sleekxmpp/plugins/xep_0279', 'sleekxmpp/plugins/xep_0280', diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py index 1e6534d0..59d716eb 100644 --- a/sleekxmpp/plugins/__init__.py +++ b/sleekxmpp/plugins/__init__.py @@ -67,6 +67,7 @@ __all__ = [ 'xep_0242', # XMPP Client Compliance 2009 'xep_0249', # Direct MUC Invitations 'xep_0256', # Last Activity in Presence + 'xep_0257', # Client Certificate Management for SASL EXTERNAL 'xep_0258', # Security Labels in XMPP 'xep_0270', # XMPP Compliance Suites 2010 'xep_0279', # Server IP Check diff --git a/sleekxmpp/plugins/xep_0257/__init__.py b/sleekxmpp/plugins/xep_0257/__init__.py new file mode 100644 index 00000000..8c5311fd --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/__init__.py @@ -0,0 +1,17 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.plugins.base import register_plugin + +from sleekxmpp.plugins.xep_0257 import stanza +from sleekxmpp.plugins.xep_0257.stanza import Certs, AppendCert +from sleekxmpp.plugins.xep_0257.stanza import DisableCert, RevokeCert +from sleekxmpp.plugins.xep_0257.client_cert_management import XEP_0257 + + +register_plugin(XEP_0257) diff --git a/sleekxmpp/plugins/xep_0257/client_cert_management.py b/sleekxmpp/plugins/xep_0257/client_cert_management.py new file mode 100644 index 00000000..49317843 --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/client_cert_management.py @@ -0,0 +1,65 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +import logging + +from sleekxmpp import Iq +from sleekxmpp.plugins import BasePlugin +from sleekxmpp.xmlstream import register_stanza_plugin +from sleekxmpp.plugins.xep_0257 import stanza, Certs +from sleekxmpp.plugins.xep_0257 import AppendCert, DisableCert, RevokeCert + + +log = logging.getLogger(__name__) + + +class XEP_0257(BasePlugin): + + name = 'xep_0257' + description = 'XEP-0258: Client Certificate Management for SASL EXTERNAL' + dependencies = set(['xep_0030']) + stanza = stanza + + def plugin_init(self): + register_stanza_plugin(Iq, Certs) + register_stanza_plugin(Iq, AppendCert) + register_stanza_plugin(Iq, DisableCert) + register_stanza_plugin(Iq, RevokeCert) + + def get_certs(self, ifrom=None, block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'get' + iq['from'] = ifrom + iq.enable('sasl_certs') + return iq.send(block=block, timeout=timeout, callback=callback) + + def add_cert(self, name, cert, allow_management=True, ifrom=None, + block=True, timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_append']['name'] = name + iq['sasl_cert_append']['x509cert'] = cert + iq['sasl_cert_append']['cert_management'] = allow_management + return iq.send(block=block, timeout=timeout, callback=callback) + + def disable_cert(self, name, ifrom=None, block=True, + timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_disable']['name'] = name + return iq.send(block=block, timeout=timeout, callback=callback) + + def revoke_cert(self, name, ifrom=None, block=True, + timeout=None, callback=None): + iq = self.xmpp.Iq() + iq['type'] = 'set' + iq['from'] = ifrom + iq['sasl_cert_revoke']['name'] = name + return iq.send(block=block, timeout=timeout, callback=callback) diff --git a/sleekxmpp/plugins/xep_0257/stanza.py b/sleekxmpp/plugins/xep_0257/stanza.py new file mode 100644 index 00000000..17e20136 --- /dev/null +++ b/sleekxmpp/plugins/xep_0257/stanza.py @@ -0,0 +1,87 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permission. +""" + +from sleekxmpp.xmlstream import ElementBase, ET, register_stanza_plugin + + +class Certs(ElementBase): + name = 'query' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_certs' + interfaces = set() + + +class CertItem(ElementBase): + name = 'item' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'item' + plugin_multi_attrib = 'items' + interfaces = set(['name', 'x509cert', 'users']) + sub_interfaces = set(['name', 'x509cert']) + + def get_users(self): + resources = self.xml.findall('{%s}users/{%s}resource' % ( + self.namespace, self.namespace)) + return set([res.text for res in resources]) + + def set_users(self, values): + users = self.xml.find('{%s}users' % self.namespace) + if users is None: + users = ET.Element('{%s}users' % self.namespace) + self.xml.append(users) + for resource in values: + res = ET.Element('{%s}resource' % self.namespace) + res.text = resource + users.append(res) + + def del_users(self): + users = self.xml.find('{%s}users' % self.namespace) + if users is not None: + self.xml.remove(users) + + +class AppendCert(ElementBase): + name = 'append' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_append' + interfaces = set(['name', 'x509cert', 'cert_management']) + sub_interfaces = set(['name', 'x509cert']) + + def get_cert_management(self): + manage = self.xml.find('{%s}no-cert-management' % self.namespace) + return manage is None + + def set_cert_management(self, value): + self.del_cert_management() + if not value: + manage = ET.Element('{%s}no-cert-management' % self.namespace) + self.xml.append(manage) + + def del_cert_management(self): + manage = self.xml.find('{%s}no-cert-management' % self.namespace) + if manage is not None: + self.xml.remove(manage) + + +class DisableCert(ElementBase): + name = 'disable' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_disable' + interfaces = set(['name']) + sub_interfaces = interfaces + + +class RevokeCert(ElementBase): + name = 'revoke' + namespace = 'urn:xmpp:saslcert:1' + plugin_attrib = 'sasl_cert_revoke' + interfaces = set(['name']) + sub_interfaces = interfaces + + +register_stanza_plugin(Certs, CertItem, iterable=True) -- cgit v1.2.3