diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index 632b5190..b5cc70ac 100644 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -264,6 +264,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members # ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members # ENABLE_AUTH_PATHFINDER = Enable Alliance Pathfinder suppor in auth for auth'd members +# ENABLE_AUTH_XENFORO = Enable XenForo forums support in the auth for auth'd members ######################### ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False') ENABLE_AUTH_JABBER = 'True' == os.environ.get('AA_ENABLE_AUTH_JABBER', 'False') @@ -276,6 +277,7 @@ ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') ENABLE_AUTH_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_AUTH_PATHFINDER', 'False') +ENABLE_AUTH_XENFORO = 'True' == os.environ.get('AA_ENABLE_AUTH_XENFORO', 'False') ##################### # Blue service Setup @@ -291,6 +293,7 @@ ENABLE_AUTH_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_AUTH_PATHFINDER', ' # ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues # ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues # ENABLE_BLUE_PATHFINDER = Enable Pathfinder support in the auth for blues +# ENABLE_BLUE_XENFORO = Enable XenForo forum support in the auth for blue ##################### BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False') @@ -304,6 +307,7 @@ ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') ENABLE_BLUE_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_BLUE_PATHFINDER', 'False') +ENABLE_BLUE_XENFORO = 'True' == os.environ.get('AA_ENABLE_BLUE_XENFORO', 'False') ######################### # Corp Configuration @@ -374,6 +378,14 @@ IPBOARD_ENDPOINT = os.environ.get('AA_IPBOARD_ENDPOINT', 'yourdomain.com/interfa IPBOARD_APIKEY = os.environ.get('AA_IPBOARD_APIKEY', 'somekeyhere') IPBOARD_APIMODULE = 'aa' +######################## +# XenForo Configuration +######################## +XENFORO_ENDPOINT = os.environ.get('AA_XENFORO_ENDPOINT', 'yourdomain.com/api.php') +XENFORO_DEFAULT_GROUP = os.environ.get('AA_XENFORO_DEFAULT_GROUP', 0) +XENFORO_APIKEY = os.environ.get('AA_XENFORO_APIKEY', 'yourapikey') +##################### + ###################### # Jabber Configuration ###################### diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index cb21e06a..def77686 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -123,6 +123,15 @@ urlpatterns = patterns('', name='auth_reset_ipboard_password'), url(r'^set_ipboard_password/$', 'services.views.set_ipboard_password', name='auth_set_ipboard_password'), + # XenForo service control + url(r'^activate_xenforo/$', 'services.views.activate_xenforo_forum', + name='auth_activate_xenforo'), + url(r'^deactivate_xenforo/$', 'services.views.deactivate_xenforo_forum', + name='auth_deactivate_xenforo'), + url(r'^reset_xenforo_password/$', 'services.views.reset_xenforo_password', + name='auth_reset_xenforo_password'), + url(r'^set_xenforo_password/$', 'services.views.set_xenforo_password', name='auth_set_xenforo_password'), + # Teamspeak3 service control url(r'^activate_teamspeak3/$', 'services.views.activate_teamspeak3', name='auth_activate_teamspeak3'), diff --git a/authentication/managers.py b/authentication/managers.py index 84f867bf..1ab279b0 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -90,6 +90,18 @@ class AuthServicesInfoManager: else: logger.error("Failed to update user %s ipboard info: user does not exist." % user) + @staticmethod + def update_user_xenforo_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s xenforo info: uername %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.xenforo_username = username + authserviceinfo.xenforo_password = password + authserviceinfo.save(update_fields=['xenforo_username', 'xenforo_password']) + logger.info("Updated user %s xenforo info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s xenforo info: user does not exist." % user) + @staticmethod def update_user_teamspeak3_info(uid, perm_key, user): if User.objects.filter(username=user.username).exists(): diff --git a/authentication/models.py b/authentication/models.py index 11b51097..aaed9119 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -5,6 +5,8 @@ from django.contrib.auth.models import User class AuthServicesInfo(models.Model): ipboard_username = models.CharField(max_length=254, blank=True, default="") ipboard_password = models.CharField(max_length=254, blank=True, default="") + xenforo_username = models.CharField(max_length=254, blank=True, default="") + xenforo_password = models.CharField(max_length=254, blank=True, default="") forum_username = models.CharField(max_length=254, blank=True, default="") forum_password = models.CharField(max_length=254, blank=True, default="") jabber_username = models.CharField(max_length=254, blank=True, default="") diff --git a/celerytask/tasks.py b/celerytask/tasks.py index b4b19324..c4128331 100644 --- a/celerytask/tasks.py +++ b/celerytask/tasks.py @@ -9,6 +9,7 @@ from services.managers.openfire_manager import OpenfireManager from services.managers.mumble_manager import MumbleManager from services.managers.phpbb3_manager import Phpbb3Manager from services.managers.ipboard_manager import IPBoardManager +from services.managers.xenforo_manager import XenForoManager from services.managers.teamspeak3_manager import Teamspeak3Manager from services.managers.discord_manager import DiscordManager, DiscordAPIManager from services.managers.discourse_manager import DiscourseManager diff --git a/services/managers/xenforo_manager.py b/services/managers/xenforo_manager.py new file mode 100644 index 00000000..18050201 --- /dev/null +++ b/services/managers/xenforo_manager.py @@ -0,0 +1,137 @@ +import os +import requests +import json + +from django.conf import settings + +import logging + +logger = logging.getLogger(__name__) + +class XenForoManager: + def __init__(self): + if not settings.XENFORO_ENDPOINT: + logger.debug("Could not find XenForo endpoint") + if not settings.XENFORO_APIKEY: + logger.debug("XenForo API Key not found") + pass + + @staticmethod + def __sanitize_username(username): + sanitized = username.replace(" ", "_") + return sanitized + + @staticmethod + def __generate_password(): + return os.urandom(8).encode('hex') + + @staticmethod + def exec_http_request(http_params): + default_params = { + 'hash': settings.XENFORO_APIKEY + } + http_params.update(default_params) + r = requests.get(settings.XENFORO_ENDPOINT, params=http_params) + return r + + @staticmethod + def add_user(username, email): + + sanitized = XenForoManager.__sanitize_username(username) + password = XenForoManager.__generate_password(); + + data = { + 'action': 'register', + 'username': sanitized, + 'password': password, + 'email': email, + 'group': settings.XENFORO_DEFAULT_GROUP, + 'visible': '1', + 'user_state': 'valid' + } + + r = XenForoManager.exec_http_request(data) + + # check if the user already exist but was disabled + if r.status_code != 200: + if json.loads(r.text)['error'] == 7: + data = XenForoManager.reactivate_user(sanitized) + return data + + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + } + } + data.update(response) + return data + + @staticmethod + def reset_password(username): + + password = XenForoManager.__generate_password(); + + data = { + 'action': 'editUser', + 'user': username, + 'password': password + } + + r = XenForoManager.exec_http_request(data) + + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + } + } + data.update(response) + return data + + @staticmethod + def disable_user(username): + data = { + 'action': 'editUser', + 'user': username, + 'remove_groups': settings.XENFORO_DEFAULT_GROUP + } + r = XenForoManager.exec_http_request(data) + return r + + @staticmethod + def reactivate_user(username): + data = { + 'action': 'editUser', + 'user': username, + 'add_groups': settings.XENFORO_DEFAULT_GROUP, + 'password': XenForoManager.__generate_password() + } + r = XenForoManager.exec_http_request(data) + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + }, + 'username': username + } + data.update(response) + return data + + @staticmethod + def update_user_password(username, raw_password): + data = { + 'action': 'editUser', + 'user': username, + 'password': raw_password + } + r = XenForoManager.exec_http_request(data) + response = { + 'response': { + 'message': r.text, + 'status_code': r.status_code + }, + 'username': username + } + data.update(response) + return data \ No newline at end of file diff --git a/services/views.py b/services/views.py index 1fa5e797..2ff4854e 100755 --- a/services/views.py +++ b/services/views.py @@ -12,6 +12,7 @@ from managers.openfire_manager import OpenfireManager from managers.phpbb3_manager import Phpbb3Manager from managers.mumble_manager import MumbleManager from managers.ipboard_manager import IPBoardManager +from managers.xenforo_manager import XenForoManager from managers.teamspeak3_manager import Teamspeak3Manager from managers.discord_manager import DiscordManager from managers.discourse_manager import DiscourseManager @@ -178,6 +179,79 @@ def reset_forum_password(request): logger.error("Unsuccessful attempt to reset forum password for user %s" % request.user) return HttpResponseRedirect("/dashboard") +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_xenforo_forum(request): + logger.debug("activate_xenforo_forum called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + character = EveManager.get_character_by_id(authinfo.main_char_id) + logger.debug("Adding XenForo user for user %s with main character %s" % (request.user, character)) + result = XenForoManager.add_user(character.character_name, request.user.email) + # Based on XenAPI's response codes + if result['response']['status_code'] == 200: + logger.info("Updated authserviceinfo for user %s with XenForo credentials. Updating groups." % request.user) + AuthServicesInfoManager.update_user_xenforo_info(result['username'], result['password'], request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate xenforo for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_xenforo_forum(request): + logger.debug("deactivate_xenforo_forum called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = XenForoManager.disable_user(authinfo.xenforo_username) + if result.status_code == 200: + AuthServicesInfoManager.update_user_xenforo_info("", "", request.user) + logger.info("Succesfully deactivated XenForo for user %s" % request.user) + return HttpResponseRedirect("/services/") + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def reset_xenforo_password(request): + logger.debug("reset_xenforo_password called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + character = EveManager.get_character_by_id(authinfo.main_char_id) + result = XenForoManager.reset_password(authinfo.xenforo_username) + # Based on XenAPI's response codes + if result['response']['status_code'] == 200: + AuthServicesInfoManager.update_user_xenforo_info(authinfo.xenforo_username, result['password'], request.user) + logger.info("Succesfully reset XenForo password for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to reset XenForo password for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def set_xenforo_password(request): + logger.debug("set_xenforo_password called by user %s" % request.user) + error = None + if request.method == 'POST': + logger.debug("Received POST request with form.") + form = ServicePasswordForm(request.POST) + logger.debug("Form is valid: %s" % form.is_valid()) + if form.is_valid(): + password = form.cleaned_data['password'] + logger.debug("Form contains password of length %s" % len(password)) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = XenForoManager.update_user_password(authinfo.xenforo_username, password) + if result['response']['status_code'] == 200: + AuthServicesInfoManager.update_user_xenforo_info(authinfo.xenforo_username, result['password'], request.user) + logger.info("Succesfully reset XenForo password for user %s" % request.user) + return HttpResponseRedirect("/services/") + else: + logger.error("Failed to install custom XenForo password for user %s" % request.user) + error = "Failed to install custom password." + else: + error = "Invalid password provided" + else: + logger.debug("Request is not type POST - providing empty form.") + form = ServicePasswordForm() + + logger.debug("Rendering form for user %s" % request.user) + context = {'form': form, 'service': 'Forum'} + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) @login_required @user_passes_test(service_blue_alliance_test) diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index a98bedd8..d6b26a04 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -105,6 +105,35 @@ {% endif %} + {% if ENABLE_BLUE_XENFORO %} +