Commit 9048630d by Nate Hardison

Use ejabberd's MySQL for usernames/passwords

When chat is enabled, sync user accounts with the ejabberd server
by directly writing into its MySQL database. This is ugly in the
sense that ejabberd just does a simple string comparison when
authenticating a password against a username, so we have to send
passwords in the clear in the templates. In a future commit, I'll
implement a password rotation mechanism to make this slightly more
robust: currently, everyone's password is just a dummy string.

To enable this, you'll have to add a 'jabber' key into your
DATABASES dict in the settings, and point at an actual ejabberd's
MySQL instance. The current plan is to just point at one that we've
got set up, since running ejabberd locally (not to mention on
MySQL instead of Mnesia) is non-trivial.
parent 6ce4c005
...@@ -34,6 +34,8 @@ from xmodule.modulestore.django import modulestore ...@@ -34,6 +34,8 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
from xmodule.modulestore.search import path_to_location from xmodule.modulestore.search import path_to_location
from jabber.models import JabberUser
import comment_client import comment_client
log = logging.getLogger("mitx.courseware") log = logging.getLogger("mitx.courseware")
...@@ -242,6 +244,13 @@ def chat_settings(course, user): ...@@ -242,6 +244,13 @@ def chat_settings(course, user):
if domain is None: if domain is None:
raise ImproperlyConfigured("Missing JABBER_DOMAIN in the settings") raise ImproperlyConfigured("Missing JABBER_DOMAIN in the settings")
# username/password from somewhere
jabber_user, created = JabberUser.objects.get_or_create(username=user.username,
defaults={'password' : 'bobobo'})
if created:
log.info("CREATED PASSWORD FOR USER %s\n" % user.username)
return { return {
'domain': domain, 'domain': domain,
...@@ -249,15 +258,10 @@ def chat_settings(course, user): ...@@ -249,15 +258,10 @@ def chat_settings(course, user):
'room': "{ID}_class".format(ID=course.id.replace('/', '-')), 'room': "{ID}_class".format(ID=course.id.replace('/', '-')),
'username': "{USER}@{DOMAIN}".format( 'username': "{USER}@{DOMAIN}".format(
USER=user.username, DOMAIN=domain USER=jabber_user.username, DOMAIN=domain
), ),
# TODO: clearly this needs to be something other than the username 'password': jabber_user.password
# should also be something that's not necessarily tied to a
# particular course
'password': "{USER}@{DOMAIN}".format(
USER=user.username, DOMAIN=domain
),
} }
......
from django.db import models
class JabberUser(models.Model):
class Meta:
app_label = 'jabber'
db_table = 'users'
# This is the primary key for our table, since ejabberd doesn't
# put an ID column on this table. This will match the edX
# username chosen by the user.
username = models.CharField(max_length=255, db_index=True, primary_key=True)
# Yes, this is stored in plaintext. ejabberd only knows how to do
# basic string matching, so we don't hash/salt this or anything.
password = models.TextField(default="")
created_at = models.DateTimeField(auto_now_add=True, null=True, db_index=True)
class JabberRouter(object):
"""
A router to control all database operations on models in the
Jabber application.
"""
def db_for_read(self, model, **hints):
"""
Attempts to read Jabber models go to the Jabber DB.
"""
if model._meta.app_label == 'jabber':
return 'jabber'
return None
def db_for_write(self, model, **hints):
"""
Attempts to write Jabber models go to the Jabber DB.
"""
if model._meta.app_label == 'jabber':
return 'jabber'
return None
def allow_relation(self, obj1, obj2, **hints):
"""
Allow relations if a model in the Jabber app is involved.
"""
if obj1._meta.app_label == 'jabber' or \
obj2._meta.app_label == 'jabber':
return True
return None
def allow_syncdb(self, db, model):
"""
Make sure the Jabber app only appears in the 'jabber'
database.
"""
if db == 'jabber':
return model._meta.app_label == 'jabber'
elif model._meta.app_label == 'jabber':
return False
return None
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment