Merge branch 'master' of https://github.com/Adarnof/allianceauth into custom_user

# Conflicts:
#	alliance_auth/settings.py.example
#	eveonline/views.py

Fix some tests.
This commit is contained in:
Adarnof
2017-05-27 17:25:15 -04:00
39 changed files with 997 additions and 417 deletions

View File

@@ -376,6 +376,5 @@ class DiscourseManager:
logger.debug("Disabling user %s Discourse access." % user)
d_user = DiscourseManager.__get_user_by_external(user.pk)
DiscourseManager.__logout(d_user['user']['id'])
DiscourseManager.__suspend_user(d_user['user']['username'])
logger.info("Disabled user %s Discourse access." % user)
return True

View File

@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
class Phpbb3Manager:
SQL_ADD_USER = r"INSERT INTO phpbb_users (username, username_clean, " \
r"user_password, user_email, group_id, user_regdate, user_permissions, " \
r"user_sig) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)"
r"user_sig, user_lang) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, 'en')"
SQL_DEL_USER = r"DELETE FROM phpbb_users where username = %s"

View File

@@ -2,9 +2,11 @@ from __future__ import unicode_literals
import random
import string
import requests
import hashlib
from eveonline.managers import EveManager
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.cache import cache
from six import iteritems
@@ -20,7 +22,7 @@ class SeatManager:
RESPONSE_OK = 'ok'
@staticmethod
def __santatize_username(username):
def __sanitize_username(username):
sanatized = username.replace(" ", "_")
return sanatized.lower()
@@ -33,7 +35,7 @@ class SeatManager:
return cls.RESPONSE_OK in response
@staticmethod
def exec_request(endpoint, func, **kwargs):
def exec_request(endpoint, func, raise_for_status=False, **kwargs):
""" Send an https api request """
try:
endpoint = '{0}/api/v1/{1}'.format(settings.SEAT_URL, endpoint)
@@ -43,22 +45,24 @@ class SeatManager:
ret = getattr(requests, func)(endpoint, headers=headers, data=kwargs)
ret.raise_for_status()
return ret.json()
except:
except requests.HTTPError as e:
if raise_for_status:
raise e
logger.exception("Error encountered while performing API request to SeAT with url {}".format(endpoint))
return {}
@classmethod
def add_user(cls, username, email):
""" Add user to service """
sanatized = str(SeatManager.__santatize_username(username))
logger.debug("Adding user to SeAT with username %s" % sanatized)
password = SeatManager.__generate_random_pass()
ret = SeatManager.exec_request('user', 'post', username=sanatized, email=str(email), password=password)
sanitized = str(cls.__sanitize_username(username))
logger.debug("Adding user to SeAT with username %s" % sanitized)
password = cls.__generate_random_pass()
ret = cls.exec_request('user', 'post', username=sanitized, email=str(email), password=password)
logger.debug(ret)
if cls._response_ok(ret):
logger.info("Added SeAT user with username %s" % sanatized)
return sanatized, password
logger.info("Failed to add SeAT user with username %s" % sanatized)
logger.info("Added SeAT user with username %s" % sanitized)
return sanitized, password
logger.info("Failed to add SeAT user with username %s" % sanitized)
return None
@classmethod
@@ -93,7 +97,7 @@ class SeatManager:
@classmethod
def enable_user(cls, username):
""" Enable user """
ret = SeatManager.exec_request('user/{}'.format(username), 'put', active=1)
ret = cls.exec_request('user/{}'.format(username), 'put', active=1)
logger.debug(ret)
if cls._response_ok(ret):
logger.info("Enabled SeAT user with username %s" % username)
@@ -104,13 +108,12 @@ class SeatManager:
@classmethod
def update_user(cls, username, email, password):
""" Edit user info """
logger.debug("Updating SeAT username %s with email %s and password hash starting with %s" % (username, email,
password[0:5]))
ret = SeatManager.exec_request('user/{}'.format(username), 'put', email=email)
logger.debug("Updating SeAT username %s with email %s and password" % (username, email))
ret = cls.exec_request('user/{}'.format(username), 'put', email=email)
logger.debug(ret)
if not cls._response_ok(ret):
logger.warn("Failed to update email for username {}".format(username))
ret = SeatManager.exec_request('user/{}'.format(username), 'put', password=password)
ret = cls.exec_request('user/{}'.format(username), 'put', password=password)
logger.debug(ret)
if not cls._response_ok(ret):
logger.warn("Failed to update password for username {}".format(username))
@@ -118,25 +121,25 @@ class SeatManager:
logger.info("Updated SeAT user with username %s" % username)
return username
@staticmethod
def update_user_password(username, email, plain_password=None):
@classmethod
def update_user_password(cls, username, email, plain_password=None):
logger.debug("Settings new SeAT password for user %s" % username)
if not plain_password:
plain_password = SeatManager.__generate_random_pass()
if SeatManager.update_user(username, email, plain_password):
plain_password = cls.__generate_random_pass()
if cls.update_user(username, email, plain_password):
return plain_password
@staticmethod
def check_user_status(username):
sanatized = str(SeatManager.__santatize_username(username))
logger.debug("Checking SeAT status for user %s" % sanatized)
ret = SeatManager.exec_request('user/{}'.format(sanatized), 'get')
@classmethod
def check_user_status(cls, username):
sanitized = str(cls.__sanitize_username(username))
logger.debug("Checking SeAT status for user %s" % sanitized)
ret = cls.exec_request('user/{}'.format(sanitized), 'get')
logger.debug(ret)
return ret
@staticmethod
def get_all_seat_eveapis():
seat_all_keys = SeatManager.exec_request('key', 'get')
@classmethod
def get_all_seat_eveapis(cls):
seat_all_keys = cls.exec_request('key', 'get')
seat_keys = {}
for key in seat_all_keys:
try:
@@ -145,117 +148,132 @@ class SeatManager:
seat_keys[key["key_id"]] = None
return seat_keys
@classmethod
def synchronize_eveapis(cls, user=None):
# Fetch all of the API keys stored in SeAT already
seat_all_keys = cls.get_all_seat_eveapis()
@staticmethod
def synchronize_eveapis(user=None):
seat_all_keys = SeatManager.get_all_seat_eveapis()
userinfo = None
# retrieve only user-specific api keys if user is specified
if user:
keypars = EveManager.get_api_key_pairs(user)
try:
userinfo = SeatManager.check_user_status(user.seat.username)
except ObjectDoesNotExist:
pass
keypairs = EveManager.get_api_key_pairs(user)
else:
# retrieve all api keys instead
keypars = EveManager.get_all_api_key_pairs()
if keypars:
for keypar in keypars:
if keypar.api_id not in seat_all_keys.keys():
#Add new keys
logger.debug("Adding Api Key with ID %s" % keypar.api_id)
ret = SeatManager.exec_request('key', 'post', key_id=keypar.api_id, v_code=keypar.api_key)
logger.debug(ret)
else:
# remove it from the list so it doesn't get deleted in the last step
seat_all_keys.pop(keypar.api_id)
if not userinfo: # TODO: should the following be done only for new keys?
# Check the key's user status
logger.debug("Retrieving user name from Auth's SeAT users database")
try:
if keypar.user.seat.username:
logger.debug("Retrieving user %s info from SeAT users database" % keypar.user.seat.username)
userinfo = SeatManager.check_user_status(keypar.user.seat.username)
except ObjectDoesNotExist:
pass
if userinfo:
try:
# If the user has activated seat, assign the key to him.
logger.debug("Transferring Api Key with ID %s to user %s with ID %s " % (
keypar.api_id,
keypar.user.seat.username,
userinfo['id']))
ret = SeatManager.exec_request('key/transfer/{}/{}'.format(keypar.api_id, userinfo['id']),
'get')
logger.debug(ret)
except ObjectDoesNotExist:
logger.debug("User does not have SeAT activated, could not assign key to user")
keypairs = EveManager.get_all_api_key_pairs()
if bool(seat_all_keys) and not user and hasattr(settings, 'SEAT_PURGE_DELETED') and settings.SEAT_PURGE_DELETED:
for keypair in keypairs:
# Transfer the key if it isn't already in SeAT
if keypair.api_id not in seat_all_keys.keys():
# Add new keys
logger.debug("Adding Api Key with ID %s" % keypair.api_id)
try:
ret = cls.exec_request('key', 'post',
key_id=keypair.api_id,
v_code=keypair.api_key,
raise_for_status=True)
logger.debug(ret)
except requests.HTTPError as e:
if e.response.status_code == 400:
logger.debug("API key already exists")
else:
logger.exception("API key sync failed")
continue # Skip the rest of the key processing
else:
# remove it from the list so it doesn't get deleted in the last step
seat_all_keys.pop(keypair.api_id)
# Attach API key to the users SeAT account, if possible
try:
userinfo = cache.get_or_set('seat_user_status_' + cls.username_hash(keypair.user.seat.username),
lambda: cls.check_user_status(keypair.user.seat.username),
300) # Cache for 5 minutes
if not bool(userinfo):
# No SeAT account, skip
logger.debug("Could not find users SeAT id, cannot assign key to them")
continue
# If the user has activated seat, assign the key to them
logger.debug("Transferring Api Key with ID %s to user %s with ID %s " % (
keypair.api_id,
keypair.user.seat.username,
userinfo['id']))
ret = cls.exec_request('key/transfer/{}/{}'.format(keypair.api_id, userinfo['id']),
'get')
logger.debug(ret)
except ObjectDoesNotExist:
logger.debug("User does not have SeAT activated, could not assign key to user")
if bool(seat_all_keys) and not user and getattr(settings, 'SEAT_PURGE_DELETED', False):
# remove from SeAT keys that were removed from Auth
for key, key_user in iteritems(seat_all_keys):
# Remove the key only if it is an account or character key
ret = SeatManager.exec_request('key/{}'.format(key), 'get')
ret = cls.exec_request('key/{}'.format(key), 'get')
logger.debug(ret)
try:
if (ret['info']['type'] == "Account") or (ret['info']['type'] == "Character"):
logger.debug("Removing api key %s from SeAT database" % key)
ret = SeatManager.exec_request('key/{}'.format(key), 'delete')
ret = cls.exec_request('key/{}'.format(key), 'delete')
logger.debug(ret)
except KeyError:
pass
@staticmethod
def get_all_roles():
@classmethod
def get_all_roles(cls):
groups = {}
ret = SeatManager.exec_request('role', 'get')
ret = cls.exec_request('role', 'get')
logger.debug(ret)
for group in ret:
groups[group["title"]] = group["id"]
logger.debug("Retrieved role list from SeAT: %s" % str(groups))
return groups
@staticmethod
def add_role(role):
ret = SeatManager.exec_request('role/new', 'post', name=role)
@classmethod
def add_role(cls, role):
ret = cls.exec_request('role/new', 'post', name=role)
logger.debug(ret)
logger.info("Added Seat group %s" % role)
role_info = SeatManager.exec_request('role/detail/{}'.format(role), 'get')
role_info = cls.exec_request('role/detail/{}'.format(role), 'get')
logger.debug(role_info)
return role_info["id"]
@staticmethod
def add_role_to_user(user_id, role_id):
ret = SeatManager.exec_request('role/grant-user-role/{}/{}'.format(user_id, role_id), 'get')
@classmethod
def add_role_to_user(cls, user_id, role_id):
ret = cls.exec_request('role/grant-user-role/{}/{}'.format(user_id, role_id), 'get')
logger.info("Added role %s to user %s" % (role_id, user_id))
return ret
@staticmethod
def revoke_role_from_user(user_id, role_id):
ret = SeatManager.exec_request('role/revoke-user-role/{}/{}'.format(user_id, role_id), 'get')
@classmethod
def revoke_role_from_user(cls, user_id, role_id):
ret = cls.exec_request('role/revoke-user-role/{}/{}'.format(user_id, role_id), 'get')
logger.info("Revoked role %s from user %s" % (role_id, user_id))
return ret
@staticmethod
def update_roles(seat_user, roles):
@classmethod
def update_roles(cls, seat_user, roles):
logger.debug("Updating SeAT user %s with roles %s" % (seat_user, roles))
user_info = SeatManager.check_user_status(seat_user)
user_info = cls.check_user_status(seat_user)
user_roles = {}
if type(user_info["roles"]) is list:
for role in user_info["roles"]:
user_roles[role["title"]] = role["id"]
logger.debug("Got user %s SeAT roles %s" % (seat_user, user_roles))
seat_roles = SeatManager.get_all_roles()
seat_roles = cls.get_all_roles()
addroles = set(roles) - set(user_roles.keys())
remroles = set(user_roles.keys()) - set(roles)
logger.info("Updating SeAT roles for user %s - adding %s, removing %s" % (seat_user, addroles, remroles))
for r in addroles:
if r not in seat_roles:
seat_roles[r] = SeatManager.add_role(r)
seat_roles[r] = cls.add_role(r)
logger.debug("Adding role %s to SeAT user %s" % (r, seat_user))
SeatManager.add_role_to_user(user_info["id"], seat_roles[r])
cls.add_role_to_user(user_info["id"], seat_roles[r])
for r in remroles:
logger.debug("Removing role %s from user %s" % (r, seat_user))
SeatManager.revoke_role_from_user(user_info["id"], seat_roles[r])
cls.revoke_role_from_user(user_info["id"], seat_roles[r])
@staticmethod
def username_hash(username):
m = hashlib.sha1()
m.update(username)
return m.hexdigest()

View File

@@ -1,6 +1,8 @@
from __future__ import unicode_literals
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from .manager import SeatManager
@@ -15,6 +17,7 @@ import logging
logger = logging.getLogger(__name__)
ACCESS_PERM = 'seat.access_seat'
SERVICE_NAME = {'service': 'SeAT'}
@login_required
@@ -38,6 +41,8 @@ def activate_seat(request):
logger.debug("Updated SeatUser for user %s with SeAT credentials. Adding eve-apis..." % request.user)
SeatTasks.update_roles.delay(request.user.pk)
logger.info("Successfully activated SeAT for user %s" % request.user)
messages.add_message(request, messages.SUCCESS, _('Successfully activated your %(service)s account.') %
SERVICE_NAME)
SeatManager.synchronize_eveapis(request.user)
credentials = {
'username': request.user.seat.username,
@@ -45,6 +50,9 @@ def activate_seat(request):
}
return render(request, 'registered/service_credentials.html',
context={'credentials': credentials, 'service': 'SeAT'})
messages.add_message(request, messages.ERROR,
_('Failed to activate your %(service)s account, please contact your administrator.') %
SERVICE_NAME)
logger.error("Unsuccessful attempt to activate seat for user %s" % request.user)
return redirect("auth_services")
@@ -55,10 +63,15 @@ def deactivate_seat(request):
logger.debug("deactivate_seat called by user %s" % request.user)
# false we failed
if SeatTasks.delete_user(request.user):
messages.add_message(request, messages.SUCCESS,
_('Successfully deactivated your %(service)s account.') % SERVICE_NAME)
logger.info("Successfully deactivated SeAT for user %s" % request.user)
return redirect("auth_services")
else:
logging.error("User does not have a SeAT account")
messages.add_message(request, messages.ERROR,
_('Failed to deactivate your %(service)s account, please contact your administrator.') %
SERVICE_NAME)
logger.error("Unsuccessful attempt to activate SeAT for user %s" % request.user)
return redirect("auth_services")
@@ -75,10 +88,15 @@ def reset_seat_password(request):
'username': request.user.seat.username,
'password': result,
}
messages.add_message(request, messages.SUCCESS,
_('Successfully reset your %(service)s password.') % {'service': 'SeAT'})
logger.info("Succesfully reset SeAT password for user %s" % request.user)
return render(request, 'registered/service_credentials.html',
context={'credentials': credentials, 'service': 'SeAT'})
logger.error("Unsuccessful attempt to reset SeAT password for user %s" % request.user)
messages.add_message(request, messages.ERROR,
_('Failed to reset your %(service)s password, please contact your administrator.') %
{'service': 'SeAT'})
return redirect("auth_services")
@@ -97,11 +115,17 @@ def set_seat_password(request):
request.user.email,
plain_password=password)
if result:
messages.add_message(request, messages.SUCCESS,
_('Successfully set your %(service)s password.') % SERVICE_NAME)
logger.info("Succesfully reset SeAT password for user %s" % request.user)
return redirect("auth_services")
else:
messages.add_message(request, messages.ERROR,
_('Failed to set your %(service)s password, please contact your administrator.') %
SERVICE_NAME)
logger.error("Failed to install custom SeAT password for user %s" % request.user)
else:
messages.add_message(request, messages.ERROR, _('Invalid password.'))
logger.error("Invalid SeAT password provided")
else:
logger.debug("Request is not type POST - providing empty form.")