Implements create() and authenticate() on DefaultGuest object; migrates DefaultAccount.authenticate_guest().
This commit is contained in:
parent
f943b3e179
commit
d78cd56279
2 changed files with 108 additions and 102 deletions
|
|
@ -414,82 +414,6 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||||
objs.append(klass(**validator.get('OPTIONS', {})))
|
objs.append(klass(**validator.get('OPTIONS', {})))
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def authenticate_guest(cls, **kwargs):
|
|
||||||
"""
|
|
||||||
Gets or creates a Guest account object.
|
|
||||||
|
|
||||||
Kwargs:
|
|
||||||
ip (str, optional): IP address of requestor; used for ban checking,
|
|
||||||
throttling and logging
|
|
||||||
|
|
||||||
"""
|
|
||||||
errors = []
|
|
||||||
account = None
|
|
||||||
username = None
|
|
||||||
ip = kwargs.get('ip', '').strip()
|
|
||||||
|
|
||||||
# check if guests are enabled.
|
|
||||||
if not settings.GUEST_ENABLED:
|
|
||||||
errors.append('Guest accounts are not enabled on this server.')
|
|
||||||
return None, errors
|
|
||||||
|
|
||||||
# See if authentication is currently being throttled
|
|
||||||
if ip and LOGIN_THROTTLE.check(ip):
|
|
||||||
errors.append('Too many login failures; please try again in a few minutes.')
|
|
||||||
|
|
||||||
# With throttle active, do not log continued hits-- it is a
|
|
||||||
# waste of storage and can be abused to make your logs harder to
|
|
||||||
# read and/or fill up your disk.
|
|
||||||
return None, errors
|
|
||||||
|
|
||||||
# check if IP banned
|
|
||||||
if ip and cls.is_banned(ip=ip):
|
|
||||||
errors.append("|rYou have been banned and cannot continue from here." \
|
|
||||||
"\nIf you feel this ban is in error, please email an admin.|x")
|
|
||||||
logger.log_sec('Authentication Denied (Banned): %s (IP: %s).' % ('guest', ip))
|
|
||||||
LOGIN_THROTTLE.update(ip, 'Too many sightings of banned IP.')
|
|
||||||
return None, errors
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Find an available guest name.
|
|
||||||
for name in settings.GUEST_LIST:
|
|
||||||
if not AccountDB.objects.filter(username__iexact=name).count():
|
|
||||||
username = name
|
|
||||||
break
|
|
||||||
if not username:
|
|
||||||
errors.append("All guest accounts are in use. Please try again later.")
|
|
||||||
if ip: LOGIN_THROTTLE.update(ip, 'Too many requests for Guest access.')
|
|
||||||
return None, errors
|
|
||||||
else:
|
|
||||||
# build a new account with the found guest username
|
|
||||||
password = "%016x" % getrandbits(64)
|
|
||||||
home = ObjectDB.objects.get_id(settings.GUEST_HOME)
|
|
||||||
permissions = settings.PERMISSION_GUEST_DEFAULT
|
|
||||||
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
|
|
||||||
account_typeclass = settings.BASE_GUEST_TYPECLASS
|
|
||||||
account, errs = cls.create(
|
|
||||||
guest=True,
|
|
||||||
username=username,
|
|
||||||
password=password,
|
|
||||||
permissions=permissions,
|
|
||||||
account_typeclass=account_typeclass,
|
|
||||||
character_typeclass=character_typeclass,
|
|
||||||
ip=ip,
|
|
||||||
)
|
|
||||||
errors.extend(errs)
|
|
||||||
return account, errors
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
# We are in the middle between logged in and -not, so we have
|
|
||||||
# to handle tracebacks ourselves at this point. If we don't,
|
|
||||||
# we won't see any errors at all.
|
|
||||||
errors.append("An error occurred. Please e-mail an admin if the problem persists.")
|
|
||||||
logger.log_trace()
|
|
||||||
return None, errors
|
|
||||||
|
|
||||||
return account, errors
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def authenticate(cls, username, password, ip='', **kwargs):
|
def authenticate(cls, username, password, ip='', **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -700,7 +624,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||||
guest (bool, optional): Whether or not this is to be a Guest account
|
guest (bool, optional): Whether or not this is to be a Guest account
|
||||||
|
|
||||||
permissions (str, optional): Default permissions for the Account
|
permissions (str, optional): Default permissions for the Account
|
||||||
account_typeclass (str, optional): Typeclass to use for new Account
|
typeclass (str, optional): Typeclass to use for new Account
|
||||||
character_typeclass (str, optional): Typeclass to use for new char
|
character_typeclass (str, optional): Typeclass to use for new char
|
||||||
when applicable.
|
when applicable.
|
||||||
|
|
||||||
|
|
@ -719,8 +643,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||||
guest = kwargs.get('guest', False)
|
guest = kwargs.get('guest', False)
|
||||||
|
|
||||||
permissions = kwargs.get('permissions', settings.PERMISSION_ACCOUNT_DEFAULT)
|
permissions = kwargs.get('permissions', settings.PERMISSION_ACCOUNT_DEFAULT)
|
||||||
account_typeclass = kwargs.get('account_typeclass', settings.BASE_ACCOUNT_TYPECLASS)
|
typeclass = kwargs.get('typeclass', settings.BASE_ACCOUNT_TYPECLASS)
|
||||||
character_typeclass = kwargs.get('character_typeclass', settings.BASE_CHARACTER_TYPECLASS)
|
|
||||||
|
|
||||||
ip = kwargs.get('ip', '')
|
ip = kwargs.get('ip', '')
|
||||||
if ip and CREATION_THROTTLE.check(ip):
|
if ip and CREATION_THROTTLE.check(ip):
|
||||||
|
|
@ -759,7 +682,7 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||||
# everything's ok. Create the new account account.
|
# everything's ok. Create the new account account.
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
account = create.create_account(username, email, password, permissions=permissions, typeclass=account_typeclass)
|
account = create.create_account(username, email, password, permissions=permissions, typeclass=typeclass)
|
||||||
logger.log_sec('Account Created: %s (IP: %s).' % (account, ip))
|
logger.log_sec('Account Created: %s (IP: %s).' % (account, ip))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -784,10 +707,15 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
|
||||||
|
|
||||||
if account and settings.MULTISESSION_MODE < 2:
|
if account and settings.MULTISESSION_MODE < 2:
|
||||||
# Load the appropriate Character class
|
# Load the appropriate Character class
|
||||||
Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS)
|
character_typeclass = kwargs.get('character_typeclass', settings.BASE_CHARACTER_TYPECLASS)
|
||||||
|
character_home = kwargs.get('home')
|
||||||
|
Character = class_from_module(character_typeclass)
|
||||||
|
|
||||||
# Create the character
|
# Create the character
|
||||||
character, errs = Character.create(account.key, account, ip=ip)
|
character, errs = Character.create(
|
||||||
|
account.key, account, ip=ip, typeclass=character_typeclass,
|
||||||
|
permissions=permissions, home=character_home
|
||||||
|
)
|
||||||
errors.extend(errs)
|
errors.extend(errs)
|
||||||
|
|
||||||
if character:
|
if character:
|
||||||
|
|
@ -1454,6 +1382,78 @@ class DefaultGuest(DefaultAccount):
|
||||||
their characters are deleted after disconnection.
|
their characters are deleted after disconnection.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, **kwargs):
|
||||||
|
"""
|
||||||
|
Forwards request to cls.authenticate(); returns a DefaultGuest object
|
||||||
|
if one is available for use.
|
||||||
|
"""
|
||||||
|
return cls.authenticate(**kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def authenticate(cls, **kwargs):
|
||||||
|
"""
|
||||||
|
Gets or creates a Guest account object.
|
||||||
|
|
||||||
|
Kwargs:
|
||||||
|
ip (str, optional): IP address of requestor; used for ban checking,
|
||||||
|
throttling and logging
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
account (Object): Guest account object, if available
|
||||||
|
errors (list): List of error messages accrued during this request.
|
||||||
|
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
account = None
|
||||||
|
username = None
|
||||||
|
ip = kwargs.get('ip', '').strip()
|
||||||
|
|
||||||
|
# check if guests are enabled.
|
||||||
|
if not settings.GUEST_ENABLED:
|
||||||
|
errors.append('Guest accounts are not enabled on this server.')
|
||||||
|
return None, errors
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Find an available guest name.
|
||||||
|
for name in settings.GUEST_LIST:
|
||||||
|
if not AccountDB.objects.filter(username__iexact=name).count():
|
||||||
|
username = name
|
||||||
|
break
|
||||||
|
if not username:
|
||||||
|
errors.append("All guest accounts are in use. Please try again later.")
|
||||||
|
if ip: LOGIN_THROTTLE.update(ip, 'Too many requests for Guest access.')
|
||||||
|
return None, errors
|
||||||
|
else:
|
||||||
|
# build a new account with the found guest username
|
||||||
|
password = "%016x" % getrandbits(64)
|
||||||
|
home = settings.GUEST_HOME
|
||||||
|
permissions = settings.PERMISSION_GUEST_DEFAULT
|
||||||
|
typeclass = settings.BASE_GUEST_TYPECLASS
|
||||||
|
|
||||||
|
# Call parent class creator
|
||||||
|
account, errs = super(DefaultGuest, cls).create(
|
||||||
|
guest=True,
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
permissions=permissions,
|
||||||
|
typeclass=typeclass,
|
||||||
|
home=home,
|
||||||
|
ip=ip,
|
||||||
|
)
|
||||||
|
errors.extend(errs)
|
||||||
|
return account, errors
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# We are in the middle between logged in and -not, so we have
|
||||||
|
# to handle tracebacks ourselves at this point. If we don't,
|
||||||
|
# we won't see any errors at all.
|
||||||
|
errors.append("An error occurred. Please e-mail an admin if the problem persists.")
|
||||||
|
logger.log_trace()
|
||||||
|
return None, errors
|
||||||
|
|
||||||
|
return account, errors
|
||||||
|
|
||||||
def at_post_login(self, session=None, **kwargs):
|
def at_post_login(self, session=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
In theory, guests only have one character regardless of which
|
In theory, guests only have one character regardless of which
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,9 @@ from unittest import TestCase
|
||||||
|
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from evennia.accounts.accounts import AccountSessionHandler
|
from evennia.accounts.accounts import AccountSessionHandler
|
||||||
from evennia.accounts.accounts import DefaultAccount
|
from evennia.accounts.accounts import DefaultAccount, DefaultGuest
|
||||||
from evennia.server.session import Session
|
from evennia.server.session import Session
|
||||||
|
from evennia.utils.test_resources import EvenniaTest
|
||||||
from evennia.utils import create
|
from evennia.utils import create
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
@ -60,8 +61,30 @@ class TestAccountSessionHandler(TestCase):
|
||||||
"Check count method"
|
"Check count method"
|
||||||
self.assertEqual(self.handler.count(), len(self.handler.get()))
|
self.assertEqual(self.handler.count(), len(self.handler.get()))
|
||||||
|
|
||||||
|
class TestDefaultGuest(EvenniaTest):
|
||||||
|
"Check DefaultGuest class"
|
||||||
|
|
||||||
class TestDefaultAccount(TestCase):
|
ip = '212.216.134.22'
|
||||||
|
|
||||||
|
def test_authenticate(self):
|
||||||
|
# Guest account should not be permitted
|
||||||
|
account, errors = DefaultGuest.authenticate(ip=self.ip)
|
||||||
|
self.assertFalse(account, 'Guest account was created despite being disabled.')
|
||||||
|
|
||||||
|
settings.GUEST_ENABLED = True
|
||||||
|
settings.GUEST_LIST = ['bruce_wayne']
|
||||||
|
|
||||||
|
# Create a guest account
|
||||||
|
account, errors = DefaultGuest.authenticate(ip=self.ip)
|
||||||
|
self.assertTrue(account, 'Guest account should have been created.')
|
||||||
|
|
||||||
|
# Create a second guest account
|
||||||
|
account, errors = DefaultGuest.authenticate(ip=self.ip)
|
||||||
|
self.assertFalse(account, 'Two guest accounts were created with a single entry on the guest list!')
|
||||||
|
|
||||||
|
settings.GUEST_ENABLED = False
|
||||||
|
|
||||||
|
class TestDefaultAccount(EvenniaTest):
|
||||||
"Check DefaultAccount class"
|
"Check DefaultAccount class"
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
@ -92,23 +115,6 @@ class TestDefaultAccount(TestCase):
|
||||||
account, errors = DefaultAccount.create(username='Ziggy', password='starman11')
|
account, errors = DefaultAccount.create(username='Ziggy', password='starman11')
|
||||||
self.assertFalse(account, 'Duplicate account name should not have been allowed.')
|
self.assertFalse(account, 'Duplicate account name should not have been allowed.')
|
||||||
|
|
||||||
# Guest account should not be permitted
|
|
||||||
account, errors = DefaultAccount.authenticate_guest()
|
|
||||||
self.assertFalse(account, 'Guest account was created despite being disabled.')
|
|
||||||
|
|
||||||
settings.GUEST_ENABLED = True
|
|
||||||
settings.GUEST_LIST = ['bruce_wayne']
|
|
||||||
|
|
||||||
# Create a guest account
|
|
||||||
account, errors = DefaultAccount.authenticate_guest()
|
|
||||||
self.assertTrue(account, 'Guest account should have been created.')
|
|
||||||
|
|
||||||
# Create a second guest account
|
|
||||||
account, errors = DefaultAccount.authenticate_guest()
|
|
||||||
self.assertFalse(account, 'Two guest accounts were created despite a single entry on the guest list!')
|
|
||||||
|
|
||||||
settings.GUEST_ENABLED = False
|
|
||||||
|
|
||||||
def test_throttle(self):
|
def test_throttle(self):
|
||||||
"Confirm throttle activates on too many failures."
|
"Confirm throttle activates on too many failures."
|
||||||
for x in xrange(20):
|
for x in xrange(20):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue