summaryrefslogtreecommitdiffstats
path: root/py-bin/jabberman.py
diff options
context:
space:
mode:
Diffstat (limited to 'py-bin/jabberman.py')
-rw-r--r--py-bin/jabberman.py392
1 files changed, 392 insertions, 0 deletions
diff --git a/py-bin/jabberman.py b/py-bin/jabberman.py
new file mode 100644
index 0000000..11e3bdf
--- /dev/null
+++ b/py-bin/jabberman.py
@@ -0,0 +1,392 @@
+#jabber manager
+
+import shelve, atexit, sha, hmac, random, os, time, re
+import config
+from ejabberdctl import EJabberdCtl
+
+class JabberUser:
+ def __init__(self, user_id):
+ self.user, self.domain = user_id.split("@")
+ self.accounts = []
+
+ def get_user_id(self):
+ return self.user + "@" + self.domain
+
+ def get_default_jabber_id(self):
+ return self.user + "@jabber." + self.domain
+
+ def is_active(self):
+ return hasattr(self, "password_hash")
+
+ def check_password(self, password):
+ if not self.is_active():
+ return False
+ return self.password_hash == self.__hash_password(password)
+
+ def set_password(self, password):
+ self.password_hash = self.__hash_password(password)
+
+ def __hash_password(self, password):
+ return sha.new(password).hexdigest()
+
+ @staticmethod
+ def generate_token():
+ data = str(random.getrandbits(256)) + str(time.time()*1000) + str(os.getpid())
+ return "+" + hmac.new(config.the_secret, data, sha).hexdigest()
+
+ def set_token(self, token):
+ self.token = token
+
+ def validate_token(self, token):
+ if token[1:] == self.token[1:]:
+ if self.__is_token_expired():
+ return (False, "Benutzerkonto bereits aktiviert.")
+ return (True, self)
+ else:
+ return (False, "Zugriff verweigert.")
+
+ def __is_token_expired(self):
+ return self.token[0] != "+"
+
+ def expire_token(self):
+ self.token = "-" + self.token[1:]
+
+ def add_account(self, jabber_id):
+ self.accounts.append(jabber_id)
+
+ def has_account(self, jabber_id):
+ return jabber_id in self.accounts
+
+ def get_account_list(self):
+ return list(self.accounts)
+
+ def get_extra_account_list(self):
+ default_acc = self.get_default_jabber_id()
+ return filter(lambda acc: acc != default_acc, self.accounts)
+
+ def remove_account(self, jabber_id):
+ self.accounts.remove(jabber_id)
+
+class JabberAccount:
+ def __init__(self, jabber_id):
+ self.user, self.server = jabber_id.split("@")
+
+ def get_jabber_id(self):
+ return self.user + "@" + self.server
+
+class JabberDB:
+ def __init__(self):
+ self.db = shelve.open(config.jabberdb_path, 'c')
+ atexit.register(self.db.close)
+
+ def login_user(self, user_id, password):
+ user = self.__load_user(user_id)
+ if user and user.check_password(password):
+ return user
+ return None
+
+ def generate_token(self, user_id):
+ if self.__load_user(user_id):
+ return (False, "Benutzer existiert bereits!")
+
+ return (True, JabberUser.generate_token())
+
+ def prepare_user(self, user_id, token):
+ if self.__load_user(user_id):
+ return (False, "Benutzer existiert bereits!")
+
+ user = JabberUser(user_id)
+ user.set_token(token)
+ self.__store_user(user)
+
+ return (True, "Benutzer registriert, Aktivierung noch ausstehend.")
+
+ def validate_token(self, user_id, token):
+ user = self.__load_user(user_id)
+ if not user:
+ return (False, "Zugriff verweigert.")
+
+ return user.validate_token(token)
+
+ def activate_user(self, user_id, password, token):
+ user = self.__load_user(user_id)
+ if not user:
+ return (False, "Zugriff verweigert.")
+
+ ok, status = user.validate_token(token)
+ if not ok:
+ return (False, status)
+
+ user.expire_token()
+ user.set_password(password)
+ self.__store_user(user)
+
+ return (True, user)
+
+ def add_account(self, user_id, jabber_id, check_only = False):
+ user = self.__load_user(user_id)
+ if not user:
+ return (False, "Zugriff verweigert.")
+
+ account = self.__load_account(jabber_id)
+ if account:
+ return (False, "Sorry, Jabber Benutzerkonto %s bereits vergeben." % jabber_id)
+
+ if check_only:
+ return (True, "Jabber kann hinzugefuegt werden.")
+
+ account = JabberAccount(jabber_id)
+ self.__store_account(account)
+ user.add_account(jabber_id)
+ self.__store_user(user)
+
+ return (True, "Jabber Konto hinzugefuegt.")
+
+ def remove_account(self, user_id, jabber_id, check_only = False):
+ user = self.__load_user(user_id)
+ if (not user) or (not user.has_account(jabber_id)):
+ return (False, "Zugriff verweigert.")
+
+ if check_only:
+ return (True, "Jabber darf geloescht werden.")
+
+ self.__delete_account(jabber_id)
+ user.remove_account(jabber_id)
+ self.__store_user(user)
+
+ return (True, "Jabber Konto geloescht.")
+
+ def change_password(self, user_id, password):
+ user = self.__load_user(user_id)
+ if not user:
+ return (False, "Zugriff verweigert.")
+
+ user.set_password(password)
+ self.__store_user(user)
+ return (True, "Passwort geaendert.")
+
+ def __load_user(self, user_id):
+ return self.db.get("#usr#" + user_id)
+
+ def __store_user(self, user):
+ self.db["#usr#" + user.get_user_id()] = user
+
+ def __load_account(self, jabber_id):
+ return self.db.get("#acc#" + jabber_id)
+
+ def __store_account(self, account):
+ self.db["#acc#" + account.get_jabber_id()] = account
+
+ def __delete_account(self, jabber_id):
+ del(self.db["#acc#" + jabber_id])
+
+
+class JabberManager:
+ def __init__(self, session):
+ self.jadb = JabberDB()
+ self.session = session
+ self.current_user, self.authenticated = None, False
+ self.ejctl = EJabberdCtl()
+
+ def get_user(self):
+ return self.current_user
+
+ def authenticate(self):
+ if self.authenticated == True:
+ return True
+ if (not "uid" in self.session) or (not "pass" in self.session):
+ return (False, "Nicht angemeldet.")
+ ok, status_or_user = self.login(
+ self.session["uid"], self.session["pass"])
+ return (ok, status_or_user)
+
+ def login(self, user_id, password):
+ ok, status = self.check_user_id(user_id)
+ if not ok:
+ return (False, status)
+
+ self.current_user = self.jadb.login_user(user_id, password)
+ if self.current_user:
+ self.__set_session(user_id, password = password)
+ else:
+ self.__clear_session()
+ return (False, "Benutzername oder Passwort falsch.")
+
+ self.authenticated = True
+ return (True, self.current_user)
+
+ def logout(self):
+ self.current_user, self.authenticated = None, False
+ self.__clear_session()
+
+ def generate_token(self, user_id):
+ ok, status = self.check_user_id(user_id)
+ if not ok:
+ return (False, status)
+
+ return self.jadb.generate_token(user_id)
+
+ def prepare_user(self, user_id, token):
+ ok, status = self.check_user_id(user_id)
+ if not ok:
+ return (False, status)
+
+ return self.jadb.prepare_user(user_id, token)
+
+ def validate_token(self, user_id, token):
+ if user_id == "":
+ try:
+ user_id, token = self.session["uid"], self.session["tok"]
+ except Exception:
+ return (False, "Zugriff verweigert.")
+
+ ok, status = self.check_user_id(user_id)
+ if not ok:
+ return (False, "Zugriff verweigert.")
+
+ ok, status_or_user = self.jadb.validate_token(user_id, token)
+ if ok:
+ self.current_user = status_or_user
+ self.__set_session(user_id, token = token)
+ return (ok, status_or_user)
+
+ def activate_user(self, password):
+ try:
+ user_id, token = self.session["uid"], self.session["tok"]
+ except Exception:
+ return (False, "Zugriff verweigert.")
+ ok, status = self.check_user_id(user_id)
+ if not ok:
+ return (False, "Zugriff verweigert.")
+
+ ok, status_or_user = self.jadb.activate_user(user_id, password, token)
+ if ok:
+ self.current_user, self.authenticated = status_or_user, True
+ self.__set_session(user_id, password = password)
+ else:
+ self.__clear_session()
+ return (False, status_or_user)
+
+ ok, status = self.add_account(self.current_user.get_default_jabber_id())
+ if not ok:
+ #todo: handle this smarter somehow
+ return (False, status)
+
+ return (True, status)
+
+ def change_password(self, password):
+ if not self.authenticated:
+ return (False, "Zugriff verweigert.")
+
+ user_id = self.current_user.get_user_id()
+ ok, status = self.jadb.change_password(user_id, password)
+ if ok:
+ self.__set_session(user_id, password = password)
+ else:
+ self.__clear_session()
+ return (False, status)
+
+ for jabber_id in self.current_user.get_account_list():
+ acc = JabberAccount(jabber_id)
+ if not self.ejctl.change_password(acc.user, acc.server, password):
+ msg = "Konnte Jaber Passwort fuer %s nicht setzen." % acc.get_jabber_id()
+ return (False, msg)
+
+ return (True, "Passwort erfolgreich geaendert.")
+
+ def is_acceptable_password(self, password, password2):
+ if password != password2:
+ return (False, "Passwoerter nicht identisch.")
+ if len(password) < config.min_password_length:
+ return (False, "Passwort ist zu kurz.")
+ if not re.match(config.password_re, password):
+ return (False, "Passwort enthaelt unerlaubte Zeichen.")
+ return (True, "Passwort OK.")
+
+ def add_account(self, jabber_id):
+ if not self.authenticated:
+ return (False, "Zugriff verweigert.")
+
+ ok, status = JabberManager.check_jabber_id(jabber_id)
+ if not ok:
+ return (False, status)
+
+ acc = JabberAccount(jabber_id)
+ try:
+ password = self.session["pass"]
+ except Exception:
+ return (False, "Zugriff verweigert.")
+
+ user_id = self.current_user.get_user_id()
+ ok, status = self.jadb.add_account(user_id, jabber_id, check_only = True)
+ if not ok:
+ return (False, status)
+
+ if not self.ejctl.create_account(acc.user, acc.server, password):
+ return (False, "Konnte Konto %s nicht erstellen." % acc.get_jabber_id())
+
+ user_id = self.current_user.get_user_id()
+ return self.jadb.add_account(user_id, jabber_id)
+
+ def remove_account(self, jabber_id):
+ if not self.authenticated:
+ return (False, "Zugriff verweigert.")
+
+ ok, status = JabberManager.check_jabber_id(jabber_id)
+ if not ok:
+ return (False, "Zugriff verweigert.")
+
+ user_id = self.current_user.get_user_id()
+ if jabber_id == self.current_user.get_default_jabber_id():
+ return (False, "Hauptkonto darf nicht geloescht werden!")
+
+ ok, status = self.jadb.remove_account(user_id, jabber_id, check_only = True)
+ if not ok:
+ return (False, status)
+
+ acc = JabberAccount(jabber_id)
+ if not self.ejctl.remove_account(acc.user, acc.server):
+ return (False, "Konnte Konto %s nicht loeschen." % acc.get_jabber_id())
+
+ return self.jadb.remove_account(user_id, jabber_id)
+
+ def __set_session(self, user_id, password = None, token = None):
+ self.__clear_session()
+ self.session["uid"] = user_id
+ if password:
+ self.session["pass"] = password
+ if token:
+ self.session["tok"] = token
+
+ def __clear_session(self):
+ if self.session.get("uid"):
+ del(self.session["uid"])
+ if self.session.get("pass"):
+ del(self.session["pass"])
+ if self.session.get("token"):
+ del(self.session["tok"])
+
+ @staticmethod
+ def __check_account_form(acc_type, domains, account):
+ try:
+ user, domain = account.split("@")
+ except ValueError:
+ status = "Ungueltige %s Adresse. Erwartete Form: user@domain." % acc_type
+ return (False, status)
+
+ if not re.match(config.user_re, user):
+ return (False, "Benutzername %s nicht erlaubt." % user)
+ if domain not in domains:
+ return (False, "Domain %s nicht erlaubt." % domain)
+ return (True, "%s Adresse akzeptiert." % acc_type)
+
+ @staticmethod
+ def check_user_id(user_id):
+ return JabberManager.__check_account_form("E-Mail", config.mail_domains, user_id)
+
+ @staticmethod
+ def check_jabber_id(jabber_id):
+ domains = map(lambda d: "jabber." + d, config.mail_domains) + config.extra_domains
+ return JabberManager.__check_account_form("Jabber", domains, jabber_id)
+
+