Learning by doing: Reading books and trying to understand the (code) examples
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
3.7 KiB

  1. import hashlib
  2. class User:
  3. def __init__(self, username, password):
  4. """Create a new user object. The password will be encrypted before
  5. storing"""
  6. self.username = username
  7. self.password = self._encrypt_pw(password)
  8. self.is_logged_in = False
  9. def _encrypt_pw(self, password):
  10. """Encrypt the password with the username and return the sha digest."""
  11. hash_string = self.username + password
  12. hash_string = hash_string.encode("utf8")
  13. return hashlib.sha256(hash_string).hexdigest()
  14. def check_password(self, password):
  15. """Return True if the password is valid for this user,
  16. False otherwise"""
  17. encrypted = self._encrypt_pw(password)
  18. return encrypted == self.password
  19. class Authenticator:
  20. def __init__(self):
  21. """Construct an authenticator to manage users logging in and out.
  22. The User objects are stored in a simple dictionary"""
  23. self.users = {}
  24. def add_user(self, username, password):
  25. """Add a User object with given username & password to the users
  26. dictionary after checking if given username & password are valid"""
  27. if username in self.users:
  28. raise UsernameAlreadyExists(username)
  29. if len(password) < 6:
  30. raise PasswordTooShort(username)
  31. self.users[username] = User(username, password)
  32. def login(self, username, password):
  33. try:
  34. user = self.users[username]
  35. except KeyError:
  36. raise InvalidUsername(username)
  37. if not user.check_password(password):
  38. raise InvalidPassword(username, user)
  39. user.is_logged_in = True
  40. return True
  41. def is_logged_in(self, username):
  42. if username in self.users:
  43. return self.users[username].is_logged_in
  44. return False
  45. authenticator = Authenticator()
  46. class Authorizor():
  47. def __init__(self, authenticator):
  48. self.authenticator = authenticator
  49. self.permissions = {}
  50. def add_permission(self, perm_name):
  51. """Create a new permission that users can be added to"""
  52. try:
  53. perm_set = self.permissions[perm_name]
  54. except KeyError:
  55. self.permissions[perm_name] = set()
  56. else:
  57. raise PermissionError("Permission exists")
  58. def permit_user(self, perm_name, username):
  59. """Grant the given permission to the given user"""
  60. try:
  61. perm_set = self.permissions[perm_name]
  62. except KeyError:
  63. raise PermissionError("Permission does not exist")
  64. else:
  65. if username not in self.authenticator.users:
  66. raise InvalidUsername(username)
  67. perm_set.add(username)
  68. def check_permission(self, perm_name, username):
  69. if not self.authenticator.is_logged_in(username):
  70. raise NotLoggedInError(username)
  71. try:
  72. perm_set = self.permissions[perm_name]
  73. except KeyError:
  74. raise PermissionError("Permission does not exist")
  75. if username not in perm_set:
  76. raise NotPermittedError(username)
  77. else:
  78. return True
  79. authorizor = Authorizor(authenticator)
  80. # Exception classes
  81. class AuthException(Exception):
  82. def __init__(self, username, user=None):
  83. super().__init__(username, user)
  84. self.username = username
  85. self.user = user
  86. class UsernameAlreadyExists(AuthException):
  87. pass
  88. class PasswordTooShort(AuthException):
  89. pass
  90. class InvalidUsername(AuthException):
  91. pass
  92. class InvalidPassword(AuthException):
  93. pass
  94. class NotLoggedInError(AuthException):
  95. pass
  96. class NotPermittedError(AuthException):
  97. pass
  98. class PermissionError(Exception):
  99. pass