2013-03-17 21:28:08 +00:00
|
|
|
# coding=utf-8
|
|
|
|
__author__ = "Gina Häußge <osd@foosel.net>"
|
|
|
|
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
|
|
|
|
|
|
|
from flask.ext.login import UserMixin
|
2013-04-14 13:04:39 +00:00
|
|
|
from flask.ext.principal import Identity
|
2013-03-17 21:28:08 +00:00
|
|
|
import hashlib
|
|
|
|
import os
|
|
|
|
import yaml
|
2013-05-30 20:16:01 +00:00
|
|
|
import requests
|
2013-03-17 21:28:08 +00:00
|
|
|
|
|
|
|
from octoprint.settings import settings
|
|
|
|
|
2013-03-18 21:27:23 +00:00
|
|
|
class UserManager(object):
|
|
|
|
valid_roles = ["user", "admin"]
|
2013-03-17 21:28:08 +00:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def createPasswordHash(password):
|
|
|
|
return hashlib.sha512(password + "mvBUTvwzBzD3yPwvnJ4E4tXNf3CGJvvW").hexdigest()
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def addUser(self, username, password, active, roles):
|
2013-03-17 21:28:08 +00:00
|
|
|
pass
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def changeUserActivation(self, username, active):
|
2013-03-17 21:28:08 +00:00
|
|
|
pass
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def changeUserRoles(self, username, roles):
|
2013-03-17 21:28:08 +00:00
|
|
|
pass
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def addRolesToUser(self, username, roles):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def removeRolesFromUser(self, username, roles):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def changeUserPassword(self, username, password):
|
2013-03-17 21:28:08 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def removeUser(self, username):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def findUser(self, username=None):
|
|
|
|
return None
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def getAllUsers(self):
|
|
|
|
return []
|
|
|
|
|
2013-05-30 20:16:01 +00:00
|
|
|
|
|
|
|
class HackerspaceUserManager(UserManager):
|
|
|
|
"""A user manager for the Warsaw Hackerspace, uses interal apis."""
|
|
|
|
def __init__(self):
|
2013-05-30 21:01:04 +00:00
|
|
|
super(HackerspaceUserManager, self).__init__()
|
2013-05-30 20:16:01 +00:00
|
|
|
self.group = settings().get(["accessControl", "group"])
|
|
|
|
|
2013-05-30 21:01:04 +00:00
|
|
|
def createPasswordHash(self, password):
|
|
|
|
return password
|
|
|
|
|
2013-05-30 20:16:01 +00:00
|
|
|
def findUser(self, username=None):
|
2013-05-30 21:01:04 +00:00
|
|
|
if username == "dummy":
|
|
|
|
return DummyUser()
|
|
|
|
print "finduser: {}".format(username)
|
2013-05-30 20:16:01 +00:00
|
|
|
if requests.get("https://capacifier.hackerspace.pl/{}/{}".format(self.group, username)).status_code == 200:
|
|
|
|
return HackerspaceUser(username)
|
2013-05-30 21:01:04 +00:00
|
|
|
else:
|
2013-05-30 20:16:01 +00:00
|
|
|
return None
|
|
|
|
|
2013-03-17 21:28:08 +00:00
|
|
|
##~~ FilebasedUserManager, takes available users from users.yaml file
|
|
|
|
|
|
|
|
class FilebasedUserManager(UserManager):
|
2013-03-18 21:27:23 +00:00
|
|
|
def __init__(self):
|
2013-03-17 21:28:08 +00:00
|
|
|
UserManager.__init__(self)
|
|
|
|
|
2013-03-18 21:27:23 +00:00
|
|
|
userfile = settings().get(["accessControl", "userfile"])
|
2013-03-17 21:28:08 +00:00
|
|
|
if userfile is None:
|
|
|
|
userfile = os.path.join(settings().settings_dir, "users.yaml")
|
|
|
|
self._userfile = userfile
|
2013-04-12 21:08:14 +00:00
|
|
|
self._users = {}
|
2013-03-17 21:28:08 +00:00
|
|
|
self._dirty = False
|
|
|
|
|
|
|
|
self._load()
|
|
|
|
|
|
|
|
def _load(self):
|
|
|
|
if os.path.exists(self._userfile) and os.path.isfile(self._userfile):
|
|
|
|
with open(self._userfile, "r") as f:
|
|
|
|
data = yaml.safe_load(f)
|
|
|
|
for name in data.keys():
|
|
|
|
attributes = data[name]
|
2013-04-12 21:08:14 +00:00
|
|
|
self._users[name] = User(name, attributes["password"], attributes["active"], attributes["roles"])
|
2013-04-13 19:40:28 +00:00
|
|
|
else:
|
|
|
|
self._users["admin"] = User("admin", "7557160613d5258f883014a7c3c0428de53040fc152b1791f1cc04a62b428c0c2a9c46ed330cdce9689353ab7a5352ba2b2ceb459b96e9c8ed7d0cb0b2c0c076", True, ["user", "admin"])
|
2013-03-17 21:28:08 +00:00
|
|
|
|
|
|
|
def _save(self, force=False):
|
|
|
|
if not self._dirty and not force:
|
|
|
|
return
|
|
|
|
|
|
|
|
data = {}
|
|
|
|
for name in self._users.keys():
|
|
|
|
user = self._users[name]
|
|
|
|
data[name] = {
|
2013-04-12 21:08:14 +00:00
|
|
|
"password": user._passwordHash,
|
|
|
|
"active": user._active,
|
|
|
|
"roles": user._roles
|
2013-03-17 21:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
with open(self._userfile, "wb") as f:
|
|
|
|
yaml.safe_dump(data, f, default_flow_style=False, indent=" ", allow_unicode=True)
|
|
|
|
self._dirty = False
|
|
|
|
self._load()
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def addUser(self, username, password, active=False, roles=["user"]):
|
2013-03-17 21:28:08 +00:00
|
|
|
if username in self._users.keys():
|
|
|
|
raise UserAlreadyExists(username)
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
self._users[username] = User(username, UserManager.createPasswordHash(password), active, roles)
|
2013-03-17 21:28:08 +00:00
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def changeUserActivation(self, username, active):
|
2013-03-17 21:28:08 +00:00
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
if self._users[username]._active != active:
|
|
|
|
self._users[username]._active = active
|
2013-03-17 21:28:08 +00:00
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def changeUserRoles(self, username, roles):
|
2013-03-17 21:28:08 +00:00
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
|
|
|
user = self._users[username]
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
removedRoles = set(user._roles) - set(roles)
|
|
|
|
self.removeRolesFromUser(username, removedRoles)
|
|
|
|
|
|
|
|
addedRoles = set(roles) - set(user._roles)
|
|
|
|
self.addRolesToUser(username, addedRoles)
|
|
|
|
|
|
|
|
def addRolesToUser(self, username, roles):
|
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
|
|
|
user = self._users[username]
|
|
|
|
for role in roles:
|
|
|
|
if not role in user._roles:
|
|
|
|
user._roles.append(role)
|
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
|
|
|
def removeRolesFromUser(self, username, roles):
|
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
|
|
|
user = self._users[username]
|
|
|
|
for role in roles:
|
|
|
|
if role in user._roles:
|
|
|
|
user._roles.remove(role)
|
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
|
|
|
def changeUserPassword(self, username, password):
|
2013-03-17 21:28:08 +00:00
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
|
|
|
passwordHash = UserManager.createPasswordHash(password)
|
|
|
|
user = self._users[username]
|
2013-04-12 21:08:14 +00:00
|
|
|
if user._passwordHash != passwordHash:
|
|
|
|
user._passwordHash = passwordHash
|
2013-03-17 21:28:08 +00:00
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
|
|
|
def removeUser(self, username):
|
|
|
|
if not username in self._users.keys():
|
|
|
|
raise UnknownUser(username)
|
|
|
|
|
|
|
|
del self._users[username]
|
|
|
|
self._dirty = True
|
|
|
|
self._save()
|
|
|
|
|
|
|
|
def findUser(self, username=None):
|
|
|
|
if username is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
if username not in self._users.keys():
|
|
|
|
return None
|
|
|
|
|
|
|
|
return self._users[username]
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def getAllUsers(self):
|
|
|
|
return map(lambda x: x.asDict(), self._users.values())
|
|
|
|
|
2013-03-17 21:28:08 +00:00
|
|
|
##~~ Exceptions
|
|
|
|
|
|
|
|
class UserAlreadyExists(Exception):
|
|
|
|
def __init__(self, username):
|
|
|
|
Exception.__init__(self, "User %s already exists" % username)
|
|
|
|
|
|
|
|
class UnknownUser(Exception):
|
|
|
|
def __init__(self, username):
|
|
|
|
Exception.__init__(self, "Unknown user: %s" % username)
|
|
|
|
|
|
|
|
class UnknownRole(Exception):
|
|
|
|
def _init_(self, role):
|
|
|
|
Exception.__init__(self, "Unknown role: %s" % role)
|
|
|
|
|
|
|
|
##~~ User object
|
|
|
|
|
|
|
|
class User(UserMixin):
|
|
|
|
def __init__(self, username, passwordHash, active, roles):
|
2013-03-19 22:06:48 +00:00
|
|
|
self._username = username
|
|
|
|
self._passwordHash = passwordHash
|
|
|
|
self._active = active
|
|
|
|
self._roles = roles
|
|
|
|
|
2013-04-12 21:08:14 +00:00
|
|
|
def asDict(self):
|
|
|
|
return {
|
|
|
|
"name": self._username,
|
|
|
|
"active": self.is_active(),
|
2013-04-13 19:40:28 +00:00
|
|
|
"admin": self.is_admin(),
|
|
|
|
"user": self.is_user()
|
2013-04-12 21:08:14 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 22:06:48 +00:00
|
|
|
def check_password(self, passwordHash):
|
|
|
|
return self._passwordHash == passwordHash
|
2013-03-17 21:28:08 +00:00
|
|
|
|
|
|
|
def get_id(self):
|
2013-03-19 22:06:48 +00:00
|
|
|
return self._username
|
|
|
|
|
|
|
|
def get_name(self):
|
|
|
|
return self._username
|
2013-03-17 21:28:08 +00:00
|
|
|
|
|
|
|
def is_active(self):
|
2013-03-19 22:06:48 +00:00
|
|
|
return self._active
|
|
|
|
|
|
|
|
def is_user(self):
|
|
|
|
return "user" in self._roles
|
|
|
|
|
|
|
|
def is_admin(self):
|
|
|
|
return "admin" in self._roles
|
2013-03-18 21:27:23 +00:00
|
|
|
|
2013-05-30 20:16:01 +00:00
|
|
|
class HackerspaceUser(User):
|
|
|
|
def __init__(self, username):
|
|
|
|
self._username = username
|
|
|
|
self._active = True
|
|
|
|
self._roles = ["user"]
|
|
|
|
if requests.get("https://capacifier.hackerspace.pl/staff/{}".format(username)).status_code == 200:
|
|
|
|
self._roles.append("admin")
|
|
|
|
|
|
|
|
def check_password(self, password):
|
|
|
|
data = {
|
|
|
|
"login": self._username,
|
|
|
|
"password": password,
|
|
|
|
}
|
2013-05-30 21:01:04 +00:00
|
|
|
return requests.post("https://auth.hackerspace.pl/", data, verify=False).status_code == 200
|
2013-05-30 20:16:01 +00:00
|
|
|
|
|
|
|
|
2013-03-18 21:27:23 +00:00
|
|
|
##~~ DummyUser object to use when accessControl is disabled
|
|
|
|
|
2013-03-19 22:06:48 +00:00
|
|
|
class DummyUser(User):
|
2013-03-18 21:27:23 +00:00
|
|
|
def __init__(self):
|
2013-03-19 22:06:48 +00:00
|
|
|
User.__init__(self, "dummy", "", True, UserManager.valid_roles)
|
2013-03-18 21:27:23 +00:00
|
|
|
|
2013-03-19 22:06:48 +00:00
|
|
|
def check_password(self, passwordHash):
|
2013-04-14 13:04:39 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
class DummyIdentity(Identity):
|
|
|
|
def __init__(self):
|
|
|
|
Identity.__init__(self, "dummy")
|
|
|
|
|
|
|
|
def dummy_identity_loader():
|
2013-04-14 13:33:11 +00:00
|
|
|
return DummyIdentity()
|