Merge pull request #308 from Adarnof/mumble

Mumble Ice Authenticator
This commit is contained in:
Adarnof
2016-03-23 00:31:18 -04:00
10 changed files with 1734 additions and 199 deletions

View File

@@ -1,6 +1,7 @@
from django.contrib import admin
from .models import AuthTS
from .models import DiscordAuthToken
from .models import MumbleUser
class AuthTSgroupAdmin(admin.ModelAdmin):
fields = ['auth_group','ts_group']
@@ -9,3 +10,5 @@ class AuthTSgroupAdmin(admin.ModelAdmin):
admin.site.register(AuthTS, AuthTSgroupAdmin)
admin.site.register(DiscordAuthToken)
admin.site.register(MumbleUser)

View File

@@ -6,46 +6,13 @@ import django
from django.db import connections
from django.conf import settings
from services.models import MumbleUser
import logging
logger = logging.getLogger(__name__)
class MumbleManager:
SQL_SELECT_USER_MAX_ID = r"SELECT max(user_id)+1 as next_id from murmur_users"
SQL_SELECT_GROUP_MAX_ID = r"SELECT MAX(group_id)+1 FROM murmur_groups"
SQL_CREATE_USER = r"INSERT INTO murmur_users (server_id, user_id, name, pw) VALUES (%s, %s, %s, %s)"
SQL_SELECT_GET_USER_ID_BY_NAME = r"SELECT user_id from murmur_users WHERE name = %s AND server_id = %s"
SQL_CHECK_USER_EXIST = r"SELECT name from murmur_users WHERE name = %s AND server_id = %s"
SQL_DELETE_USER = r"DELETE FROM murmur_users WHERE name = %s AND server_id = %s"
SQL_UPDATE_USER_PASSWORD = r"UPDATE murmur_users SET pw = %s WHERE name = %s AND server_id = %s"
SQL_GET_GROUPS = r"SELECT group_id, name FROM murmur_groups WHERE server_id = %s AND channel_id = 0"
SQL_GET_GROUP_FROM_NAME = r"SELECT group_id, name FROM murmur_groups " \
r"WHERE server_id = %s AND channel_id = 0 AND name = %s"
SQL_GET_USER_GROUPS = r"SELECT murmur_groups.name FROM murmur_groups, murmur_group_members WHERE " \
r"murmur_group_members.group_id = murmur_groups.group_id AND " \
r"murmur_group_members.server_id = murmur_groups.server_id AND " \
r"murmur_group_members.user_id = %s"
SQL_ADD_GROUP = r"INSERT INTO murmur_groups (group_id, server_id, name, channel_id, inherit, inheritable) " \
r"VALUES (%s, %s, %s, 0, 1, 1)"
SQL_ADD_USER_TO_GROUP = r"INSERT INTO murmur_group_members (group_id, server_id, user_id, addit) " \
r"VALUES (%s, %s, %s, 1)"
SQL_DELETE_USER_FROM_GROUP = r"DELETE FROM murmur_group_members WHERE group_id = %s " \
r"AND server_id = %s AND user_id = %s"
def __init__(self):
pass
@staticmethod
def __santatize_username(username):
@@ -69,192 +36,81 @@ class MumbleManager:
def _gen_pwhash(password):
return hashlib.sha1(password).hexdigest()
@staticmethod
def _get_groups():
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_GET_GROUPS, [settings.MUMBLE_SERVER_ID])
rows = dbcursor.fetchall()
out = {}
for row in rows:
out[row[1]] = row[0]
logger.debug("Got mumble groups %s" % out)
return out
@staticmethod
def _get_group(name):
logger.debug("Looking for group name %s in mumble." % name)
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_GET_GROUP_FROM_NAME, [settings.MUMBLE_SERVER_ID, name])
row = dbcursor.fetchone()
if row:
logger.debug("Found group %s in mumble - %s" % (name, row[0]))
return row[0]
@staticmethod
def _get_user_groups(name):
logger.debug("Getting mumble groups for username %s" % name)
dbcursor = connections['mumble'].cursor()
user_id = MumbleManager.get_user_id_by_name(name)
dbcursor.execute(MumbleManager.SQL_GET_USER_GROUPS, [user_id])
out = [row[0] for row in dbcursor.fetchall()]
logger.debug("Got user %s mumble groups %s" % (name, out))
return out
@staticmethod
def _add_group(name):
logger.debug("Adding group %s to mumble server." % name)
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_SELECT_GROUP_MAX_ID)
row = dbcursor.fetchone()
groupid = row[0]
dbcursor.execute(MumbleManager.SQL_ADD_GROUP, [groupid, settings.MUMBLE_SERVER_ID, name])
logger.info("Created group %s on mumble server with id %s" % (name, groupid))
return groupid
@staticmethod
def _add_user_to_group(userid, groupid):
if userid != None:
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_ADD_USER_TO_GROUP, [groupid, settings.MUMBLE_SERVER_ID, userid])
logger.info("Added user id %s to mumble group id %s" % (userid, groupid))
@staticmethod
def _del_user_from_group(userid, groupid):
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_DELETE_USER_FROM_GROUP, [groupid, settings.MUMBLE_SERVER_ID, userid])
logger.info("Removed user id %s from mumble group id %s" % (userid, groupid))
@staticmethod
def get_user_id_by_name(name):
logger.debug("Getting mumble user id for user with name %s" % name)
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_SELECT_GET_USER_ID_BY_NAME, [name, settings.MUMBLE_SERVER_ID])
row = dbcursor.fetchone()
if row:
logger.debug("Got mumble user id %s for name %s" % (row[0], name))
return row[0]
@staticmethod
def create_user(corp_ticker, username):
logger.debug("Creating mumble user with username %s and ticker %s" % (username, corp_ticker))
dbcursor = connections['mumble'].cursor()
username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username(username, corp_ticker))
password = MumbleManager.__generate_random_pass()
pwhash = MumbleManager._gen_pwhash(password)
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (username_clean, pwhash[0:5]))
try:
dbcursor.execute(MumbleManager.SQL_SELECT_USER_MAX_ID)
user_id = dbcursor.fetchone()[0]
dbcursor.execute(MumbleManager.SQL_CREATE_USER,
[settings.MUMBLE_SERVER_ID, user_id, username_clean, pwhash])
logger.info("Added user to mumble with username %s" % username_clean)
if MumbleUser.objects.filter(username=username_clean).exists() is False:
logger.info("Creating mumble user %s" % username_clean)
model = MumbleUser.objects.create(username=username_clean, pwhash=pwhash)
return username_clean, password
else:
logger.warn("Mumble user %s already exists. Updating password")
model = MumbleUser.objects.get(username=username_clean)
model.pwhash = pwhash
model.save()
logger.info("Updated mumble user %s" % username_clean)
return username_clean, password
except django.db.utils.IntegrityError as error:
logger.exception("IntegrityError during mumble create_user occured.")
except:
logger.exception("Unhandled exception occured.")
logger.error("Exception prevented creation of mumble user. Returning blank for username, password.")
return "", ""
@staticmethod
def create_blue_user(corp_ticker, username):
logger.debug("Creating mumble blue user with username %s and ticker %s" % (username, corp_ticker))
dbcursor = connections['mumble'].cursor()
username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username_blue(username,
corp_ticker))
username_clean = MumbleManager.__santatize_username(MumbleManager.__generate_username_blue(username, corp_ticker))
password = MumbleManager.__generate_random_pass()
pwhash = MumbleManager._gen_pwhash(password)
logger.debug("Proceeding with mumble user creation: clean username %s, pwhash starts with %s" % (username_clean, pwhash[0:5]))
try:
dbcursor.execute(MumbleManager.SQL_SELECT_USER_MAX_ID)
user_id = dbcursor.fetchone()[0]
dbcursor.execute(MumbleManager.SQL_CREATE_USER,
[settings.MUMBLE_SERVER_ID, user_id, username_clean, pwhash])
logger.info("Added blue user to mumble with username %s" % username_clean)
if MumbleUser.objects.filter(username=username_clean).exists() is False:
logger.info("Creating mumble user %s" % username_clean)
model = MumbleUser.objects.create(username=username_clean, pwhash=pwhash)
return username_clean, password
else:
logger.warn("Mumble user %s already exists. Updating password")
model = MumbleUser.objects.get(username=username_clean)
model.pwhash = pwhash
model.save()
logger.info("Updated mumble user %s" % username_clean)
return username_clean, password
except:
logger.exception("Unhandled exception occured.")
logger.error("Exception prevented creation of mumble blue user. Returning blank for username, password.")
return "", ""
@staticmethod
def check_user_exist(username):
logger.debug("Checking if username %s exists on mumble." % username)
dbcursor = connections['mumble'].cursor()
dbcursor.execute(MumbleManager.SQL_CHECK_USER_EXIST,
[username, settings.MUMBLE_SERVER_ID])
row = dbcursor.fetchone()
if row and row[0].lower() == username.lower():
logger.debug("Found username %s on mumble." % username)
return True
logger.debug("Unable to find username %s on mumble." % username)
return False
@staticmethod
def delete_user(username):
logger.debug("Deleting user %s from mumble." % username)
dbcursor = connections['mumble'].cursor()
if MumbleManager.check_user_exist(username):
try:
dbcursor.execute(MumbleManager.SQL_DELETE_USER,
[username, settings.MUMBLE_SERVER_ID])
logger.info("Deleted user %s from mumble." % username)
return True
except:
logger.exception("Exception prevented deletion of user %s from mumble." % username)
return False
logger.error("User %s not found on mumble. Unable to delete." % username)
if MumbleUser.objects.filter(username=username).exists():
MumbleUser.objects.filter(username=username).delete()
logger.info("Deleted user %s from mumble" % username)
return True
logger.error("Unable to delete user %s from mumble: MumbleUser model not found" % username)
return False
@staticmethod
def update_user_password(username, password=None):
logger.debug("Updating mumble user %s password." % username)
dbcursor = connections['mumble'].cursor()
if not password:
password = MumbleManager.__generate_random_pass()
pwhash = MumbleManager._gen_pwhash(password)
logger.debug("Proceeding with mumble user %s password update - pwhash starts with %s" % (username, pwhash[0:5]))
if MumbleManager.check_user_exist(username):
try:
dbcursor.execute(MumbleManager.SQL_UPDATE_USER_PASSWORD,
[pwhash, username, settings.MUMBLE_SERVER_ID])
logger.info("Updated mumble user %s password." % username)
return password
except:
logger.exception("Exception prevented updating of mumble user %s password." % username)
return ""
if MumbleUser.objects.filter(username=username).exists():
model = MumbleUser.objects.get(username=username)
model.pwhash = pwhash
model.save()
return password
logger.error("User %s not found on mumble. Unable to update password." % username)
return ""
@staticmethod
def update_groups(username, groups):
logger.debug("Updating mumble user %s groups %s" % (username, groups))
userid = MumbleManager.get_user_id_by_name(username)
mumble_groups = MumbleManager._get_groups()
user_groups = set(MumbleManager._get_user_groups(username))
act_groups = set([g.replace(' ', '-') for g in groups])
addgroups = act_groups - user_groups
remgroups = user_groups - act_groups
logger.info("Updating mumble user %s groups - adding %s, removing %s" % (username, addgroups, remgroups))
for g in addgroups:
if not g in mumble_groups:
mumble_groups[g] = MumbleManager._add_group(g)
try:
logger.debug("Adding mumble user %s to group %s" % (userid, mumble_groups[g]))
MumbleManager._add_user_to_group(userid, mumble_groups[g])
except:
logger.exception("Exception occured while adding mumble user %s with id %s to group %s with id %s" % (username, userid, g, mumble_groups[g]))
for g in remgroups:
try:
logger.debug("Deleting mumble user %s from group %s" % (userid, mumble_groups[g]))
MumbleManager._del_user_from_group(userid, mumble_groups[g])
except:
logger.exception("Exception occured while removing mumble user %s with id %s from group %s with id %s" % (username, userid, g, mumble_groups[g]))
safe_groups = list(set([g.replace(' ', '-') for g in groups]))
groups =''
for g in safe_groups:
groups = groups + g + ','
groups = groups.strip(',')
if MumbleUser.objects.filter(username=username).exists():
logger.info("Updating mumble user %s groups to %s" % (username, safe_groups))
model = MumbleUser.objects.get(username=username)
model.groups = groups
model.save()
else:
logger.error("User %s not found on mumble. Unable to update groups." % username)

View File

@@ -38,3 +38,11 @@ class DiscordAuthToken(models.Model):
def __str__(self):
output = "Discord Token for email %s user %s" % (self.email, self.user)
return output.encode('utf-8')
class MumbleUser(models.Model):
username = models.CharField(max_length=254, unique=True)
pwhash = models.CharField(max_length=40)
groups = models.TextField(blank=True, null=True)
def __str__(self):
return self.username

View File

@@ -6,6 +6,7 @@ from services.models import UserTSgroup
from services.models import AuthTS
from services.models import TSgroup
from services.models import DiscordAuthToken
from services.models import MumbleUser
logger = logging.getLogger(__name__)
@@ -81,6 +82,8 @@ def disable_mumble():
auth.save()
logger.info("Deleting all SyncGroupCache models for mumble")
SyncGroupCache.objects.filter(servicename="mumble").delete()
logger.info("Deleting all MumbleUser models")
MumbleUser.objects.all().delete()
def disable_ipboard():
if settings.ENABLE_AUTH_IPBOARD: