summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLance Stout <lancestout@gmail.com>2012-09-04 19:42:49 -0700
committerLance Stout <lancestout@gmail.com>2012-09-04 19:42:49 -0700
commita88b9737ffb1b0fc0c1962a501595ff2375e6619 (patch)
treeca01c7dd42ed9861bf72724d6fbbdbb9e35bd200
parent357406d801dabcac70d2794ac4c61c70655e704b (diff)
downloadslixmpp-a88b9737ffb1b0fc0c1962a501595ff2375e6619.tar.gz
slixmpp-a88b9737ffb1b0fc0c1962a501595ff2375e6619.tar.bz2
slixmpp-a88b9737ffb1b0fc0c1962a501595ff2375e6619.tar.xz
slixmpp-a88b9737ffb1b0fc0c1962a501595ff2375e6619.zip
Add support for XEP-0235: OAuth over XMPP
-rwxr-xr-xsetup.py1
-rw-r--r--sleekxmpp/plugins/__init__.py1
-rw-r--r--sleekxmpp/plugins/xep_0235/__init__.py16
-rw-r--r--sleekxmpp/plugins/xep_0235/oauth.py32
-rw-r--r--sleekxmpp/plugins/xep_0235/stanza.py80
5 files changed, 130 insertions, 0 deletions
diff --git a/setup.py b/setup.py
index b3028a14..cfc5b71a 100755
--- a/setup.py
+++ b/setup.py
@@ -97,6 +97,7 @@ packages = [ 'sleekxmpp',
'sleekxmpp/plugins/xep_0221',
'sleekxmpp/plugins/xep_0224',
'sleekxmpp/plugins/xep_0231',
+ 'sleekxmpp/plugins/xep_0235',
'sleekxmpp/plugins/xep_0249',
'sleekxmpp/plugins/xep_0258',
'sleekxmpp/features',
diff --git a/sleekxmpp/plugins/__init__.py b/sleekxmpp/plugins/__init__.py
index e76a4318..d0afc950 100644
--- a/sleekxmpp/plugins/__init__.py
+++ b/sleekxmpp/plugins/__init__.py
@@ -60,6 +60,7 @@ __all__ = [
'xep_0223', # Persistent Storage of Private Data via Pubsub
'xep_0224', # Attention
'xep_0231', # Bits of Binary
+ 'xep_0235', # OAuth Over XMPP
'xep_0242', # XMPP Client Compliance 2009
'xep_0249', # Direct MUC Invitations
'xep_0256', # Last Activity in Presence
diff --git a/sleekxmpp/plugins/xep_0235/__init__.py b/sleekxmpp/plugins/xep_0235/__init__.py
new file mode 100644
index 00000000..29d4408a
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0235/__init__.py
@@ -0,0 +1,16 @@
+"""
+ 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_0235 import stanza
+from sleekxmpp.plugins.xep_0235.stanza import OAuth
+from sleekxmpp.plugins.xep_0235.oauth import XEP_0235
+
+
+register_plugin(XEP_0235)
diff --git a/sleekxmpp/plugins/xep_0235/oauth.py b/sleekxmpp/plugins/xep_0235/oauth.py
new file mode 100644
index 00000000..df0e2ebf
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0235/oauth.py
@@ -0,0 +1,32 @@
+"""
+ 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 Message
+from sleekxmpp.plugins import BasePlugin
+from sleekxmpp.xmlstream import register_stanza_plugin
+from sleekxmpp.plugins.xep_0235 import stanza, OAuth
+
+
+class XEP_0235(BasePlugin):
+
+ name = 'xep_0235'
+ description = 'XEP-0235: OAuth Over XMPP'
+ dependencies = set(['xep_0030'])
+ stanza = stanza
+
+ def plugin_init(self):
+ register_stanza_plugin(Message, OAuth)
+
+ def session_bind(self, jid):
+ self.xmpp['xep_0030'].add_feature('urn:xmpp:oauth:0')
+
+ def plugin_end(self):
+ self.xmpp['xep_0030'].del_feature(feature='urn:xmpp:oauth:0')
diff --git a/sleekxmpp/plugins/xep_0235/stanza.py b/sleekxmpp/plugins/xep_0235/stanza.py
new file mode 100644
index 00000000..0050d583
--- /dev/null
+++ b/sleekxmpp/plugins/xep_0235/stanza.py
@@ -0,0 +1,80 @@
+"""
+ 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 hmac
+import hashlib
+import urllib
+import base64
+
+from sleekxmpp.xmlstream import ET, ElementBase, JID
+
+
+class OAuth(ElementBase):
+
+ name = 'oauth'
+ namespace = 'urn:xmpp:oauth:0'
+ plugin_attrib = 'oauth'
+ interfaces = set(['oauth_consumer_key', 'oauth_nonce', 'oauth_signature',
+ 'oauth_signature_method', 'oauth_timestamp',
+ 'oauth_token', 'oauth_version'])
+ sub_interfaces = interfaces
+
+ def generate_signature(self, stanza, sfrom, sto, consumer_secret,
+ token_secret, method='HMAC-SHA1'):
+ self['oauth_signature_method'] = method
+
+ request = urllib.quote('%s&%s' % (sfrom, sto), '')
+ parameters = urllib.quote('&'.join([
+ 'oauth_consumer_key=%s' % self['oauth_consumer_key'],
+ 'oauth_nonce=%s' % self['oauth_nonce'],
+ 'oauth_signature_method=%s' % self['oauth_signature_method'],
+ 'oauth_timestamp=%s' % self['oauth_timestamp'],
+ 'oauth_token=%s' % self['oauth_token'],
+ 'oauth_version=%s' % self['oauth_version']
+ ]), '')
+
+ sigbase = '%s&%s&%s' % (stanza, request, parameters)
+
+ consumer_secret = urllib.quote(consumer_secret, '')
+ token_secret = urllib.quote(token_secret, '')
+ key = '%s&%s' % (consumer_secret, token_secret)
+
+ if method == 'HMAC-SHA1':
+ sig = base64.b64encode(hmac.new(key, sigbase, hashlib.sha1).digest())
+ elif method == 'PLAINTEXT':
+ sig = key
+
+ self['oauth_signature'] = sig
+ return sig
+
+ def verify_signature(self, stanza, sfrom, sto, consumer_secret,
+ token_secret):
+ method = self['oauth_signature_method']
+
+ request = urllib.quote('%s&%s' % (sfrom, sto), '')
+ parameters = urllib.quote('&'.join([
+ 'oauth_consumer_key=%s' % self['oauth_consumer_key'],
+ 'oauth_nonce=%s' % self['oauth_nonce'],
+ 'oauth_signature_method=%s' % self['oauth_signature_method'],
+ 'oauth_timestamp=%s' % self['oauth_timestamp'],
+ 'oauth_token=%s' % self['oauth_token'],
+ 'oauth_version=%s' % self['oauth_version']
+ ]), '')
+
+ sigbase = '%s&%s&%s' % (stanza, request, parameters)
+
+ consumer_secret = urllib.quote(consumer_secret, '')
+ token_secret = urllib.quote(token_secret, '')
+ key = '%s&%s' % (consumer_secret, token_secret)
+
+ if method == 'HMAC-SHA1':
+ sig = base64.b64encode(hmac.new(key, sigbase, hashlib.sha1).digest())
+ elif method == 'PLAINTEXT':
+ sig = key
+
+ return self['oauth_signature'] == sig