|
@ -0,0 +1,138 @@ |
|
|
|
|
|
import hashlib |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class User: |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, username, password): |
|
|
|
|
|
'''Create a new user object. The password will be encrypted before |
|
|
|
|
|
storing''' |
|
|
|
|
|
self.username = username |
|
|
|
|
|
self.password = self._encrypt_pw(password) |
|
|
|
|
|
self.is_logged_in = False |
|
|
|
|
|
|
|
|
|
|
|
def _encrypt_pw(self, password): |
|
|
|
|
|
'''Encrypt the password with the username and return the sha digest.''' |
|
|
|
|
|
hash_string = self.username + password |
|
|
|
|
|
hash_string = hash_string.encode("utf8") |
|
|
|
|
|
return hashlib.sha256(hash_string).hexdigest() |
|
|
|
|
|
|
|
|
|
|
|
def check_password(self, password): |
|
|
|
|
|
'''Return True if the password is valid for this user, |
|
|
|
|
|
False otherwise''' |
|
|
|
|
|
encrypted = self._encrypt_pw(password) |
|
|
|
|
|
return encrypted == self.password |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Authenticator: |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
'''Construct an authenticator to manage users logging in and out. |
|
|
|
|
|
The User objects are stored in a simple dictionary''' |
|
|
|
|
|
self.users = {} |
|
|
|
|
|
|
|
|
|
|
|
def add_user(self, username, password): |
|
|
|
|
|
'''Add a User object with given username & password to the users |
|
|
|
|
|
dictionary after checking if given username & password are valid''' |
|
|
|
|
|
if username in self.users: |
|
|
|
|
|
raise UsernameAlreadyExists(username) |
|
|
|
|
|
if len(password) < 6: |
|
|
|
|
|
raise PasswordTooShort(username) |
|
|
|
|
|
self.users[username] = User(username, password) |
|
|
|
|
|
|
|
|
|
|
|
def login(self, username, password): |
|
|
|
|
|
try: |
|
|
|
|
|
user = self.users[username] |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
raise InvalidUsername(username) |
|
|
|
|
|
if not user.check_password(password): |
|
|
|
|
|
raise InvalidPassword(username, user) |
|
|
|
|
|
user.is_logged_in = True |
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
def is_logged_in(self, username): |
|
|
|
|
|
if username in self.users: |
|
|
|
|
|
return self.users[username].is_logged_in |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
authenticator = Authenticator() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Authorizor(): |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, authenticator): |
|
|
|
|
|
self.authenticator = authenticator |
|
|
|
|
|
self.permissions = {} |
|
|
|
|
|
|
|
|
|
|
|
def add_permission(self, perm_name): |
|
|
|
|
|
'''Create a new permission that users can be added to''' |
|
|
|
|
|
try: |
|
|
|
|
|
perm_set = self.permissions[perm_name] |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
self.permissions[perm_name] = set() |
|
|
|
|
|
else: |
|
|
|
|
|
raise PermissionError("Permission exists") |
|
|
|
|
|
|
|
|
|
|
|
def permit_user(self, perm_name, username): |
|
|
|
|
|
'''Grant the given permission to the given user''' |
|
|
|
|
|
try: |
|
|
|
|
|
perm_set = self.permissions[perm_name] |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
raise PermissionError("Permission does not exist") |
|
|
|
|
|
else: |
|
|
|
|
|
if username not in self.authenticator.users: |
|
|
|
|
|
raise InvalidUsername(username) |
|
|
|
|
|
perm_set.add(username) |
|
|
|
|
|
|
|
|
|
|
|
def check_permission(self, perm_name, username): |
|
|
|
|
|
if not self.authenticator.is_logged_in(username): |
|
|
|
|
|
raise NotLoggedInError(username) |
|
|
|
|
|
try: |
|
|
|
|
|
perm_set = self.permissions[perm_name] |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
raise PermissionError("Permission does not exist") |
|
|
|
|
|
if username not in perm_set: |
|
|
|
|
|
raise NotPermittedError(username) |
|
|
|
|
|
else: |
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
authorizor = Authorizor(authenticator) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Exception classes |
|
|
|
|
|
|
|
|
|
|
|
class AuthException(Exception): |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, username, user = None): |
|
|
|
|
|
super().__init__(username, user) |
|
|
|
|
|
self.username = username |
|
|
|
|
|
self.user = user |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UsernameAlreadyExists(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PasswordTooShort(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidUsername(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InvalidPassword(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NotLoggedInError(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class NotPermittedError(AuthException): |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PermissionError(Exception): |
|
|
|
|
|
pass |