Last active
August 29, 2015 14:06
-
-
Save giftig/41c69b1bdc5e3bf93257 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Author: Rob Moore <[email protected]>""" | |
import logging | |
import signal | |
import struct | |
import sys | |
from django.contrib.auth.models import check_password | |
from django.contrib.auth.models import User | |
from django.core.management.base import BaseCommand | |
logger = logging.getLogger(__name__) | |
class Command(BaseCommand): | |
help = 'Interface between ejabberd and django; an auth service for XMPP' | |
stopping = False | |
@staticmethod | |
def write_response(success=False): | |
"""Creates and sends a response back to the ejabberd server.""" | |
result = 1 if success else 0 | |
sys.stdout.write(struct.pack('>hh', 2, result)) | |
sys.stdout.flush() | |
@staticmethod | |
def _handle_isuser(username, server): | |
""" | |
Handles the `isuser` ejabberd command, indicating whether or not | |
the requested user exists in the system. | |
""" | |
return Command.write_response( | |
User.objects.filter(username=username).exists() | |
) | |
@staticmethod | |
def _handle_auth(username, server, password): | |
"""Handles authentication of the user""" | |
user = User.objects.filter(username=username) | |
if not user: | |
return Command.write_response(False) | |
user = user[0] | |
result = check_password(password, user.password) | |
return Command.write_response(result) | |
def handle_request(self): | |
"""Read an ejabberd request and respond to it""" | |
try: | |
data_size = struct.unpack('>h', sys.stdin.read(2))[0] | |
data = sys.stdin.read(data_size).split(':') | |
command = input.pop(0) | |
# If anything goes wrong, tell ejabberd it's being dumb; don't crash | |
except: | |
logger.exception('ejabberd gave us a bad request!') | |
return Command.write_response(False) | |
handler = getattr(Command, '_handle_%s' % command, None) | |
# Fail silently; we don't support all commands, but it doesn't mean | |
# ejabberd isn't going to attempt them, possibly frequently | |
if handler is None: | |
return Command.write_response(False) | |
return handler(*data) | |
def handle(self, **options): | |
""" | |
Per ejabberd external auth API specification, keep listening for | |
auth or 'isuser' requests and responding as appropriate using utility | |
methods. | |
""" | |
# If we get a SIGINT, stop after we've dealt with the current command | |
signal.signal(signal.SIGINT, self.stop_gracefully) | |
while not Command.stopping: | |
Command.handle_request() | |
@staticmethod | |
def stop_gracefully(*args): | |
Command.stopping = True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment