diff --git a/README.md b/README.md index 9423e7f..0521626 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ If installing on Windows, you will need to find the proper pre-built binary of p You can install this via the OctoPrint plugin manager GUI using this URL: ``` -https://github.com/battis/OctoPrint-LDAP/archive/master.zip +https://github.com/gillg/OctoPrint-LDAP/archive/refs/heads/master.zip ``` The plugin may also be installed within the oprint venv using the command diff --git a/octoprint_auth_ldap/group_manager.py b/octoprint_auth_ldap/group_manager.py index b65a8f0..2e328d6 100644 --- a/octoprint_auth_ldap/group_manager.py +++ b/octoprint_auth_ldap/group_manager.py @@ -151,6 +151,7 @@ def _load(self): try: with io.open(self._groupfile, 'rt', encoding='utf-8') as f: data = yaml.safe_load(f) + version = data.pop("_version", 1) if "groups" not in data: groups = data diff --git a/octoprint_auth_ldap/user.py b/octoprint_auth_ldap/user.py index a4a8942..facdff0 100644 --- a/octoprint_auth_ldap/user.py +++ b/octoprint_auth_ldap/user.py @@ -11,6 +11,7 @@ class LDAPUser(User): def __init__( self, username, + passwordHash=None, active=True, permissions=None, groups=None, @@ -21,7 +22,7 @@ def __init__( User.__init__( self, username=username, - passwordHash=None, + passwordHash=passwordHash, active=active, permissions=permissions, groups=groups, diff --git a/octoprint_auth_ldap/user_manager.py b/octoprint_auth_ldap/user_manager.py index 0045870..caf35c9 100644 --- a/octoprint_auth_ldap/user_manager.py +++ b/octoprint_auth_ldap/user_manager.py @@ -5,6 +5,7 @@ import os import yaml +from passlib import pwd from ldap.filter import filter_format from octoprint.access.users import FilebasedUserManager, User, UserAlreadyExists from octoprint.util import atomic_write @@ -27,7 +28,7 @@ def __init__(self, plugin, ldap, **kwargs): def group_manager(self): return self._group_manager - def find_user(self, userid=None, apikey=None, session=None): + def find_user(self, userid=None, apikey=None, session=None, fresh=False): self.logger.debug("Search for userid=%s, apiKey=%s, session=%s" % (userid, apikey, session)) user = FilebasedUserManager.find_user(self, userid=userid, apikey=apikey, session=session) user, userid = self._find_user_with_transformation(apikey, session, user, userid) @@ -80,7 +81,7 @@ def _find_user_with_transformation(self, apikey, session, user, userid): def add_user(self, username, - password=None, + password=pwd.genword(entropy=52, length=20), active=False, permissions=None, groups=None, @@ -112,6 +113,7 @@ def add_user(self, self._users[username] = LDAPUser( username=username, + passwordHash=LDAPUserManager.create_password_hash(password, settings=self._settings), active=active, permissions=permissions, groups=groups, @@ -133,6 +135,9 @@ def check_password(self, username, password): client = self.ldap.get_client(user.distinguished_name, password) authenticated = client is not None self.logger.debug("%s was %sauthenticated" % (user.get_name(), "" if authenticated else "not ")) + if authenticated: + user._passwordHash = LDAPUserManager.create_password_hash(password, settings=self._settings) + self._save(force=True) return authenticated else: self.logger.debug("%s is inactive or no longer a member of required groups" % user.get_id()) @@ -158,6 +163,8 @@ def _load(self): self._customized = True with io.open(self._userfile, 'rt', encoding='utf-8') as f: data = yaml.safe_load(f) + version = data.pop("_version", 1) + for name, attributes in data.items(): permissions = self._to_permissions(*attributes.get("permissions", [])) groups = attributes.get("groups", { @@ -181,6 +188,7 @@ def _load(self): self.logger.debug("Loading %s as %s" % (name, LDAPUser.__name__)) self._users[name] = LDAPUser( username=name, + passwordHash=attributes["password"], active=attributes["active"], permissions=permissions, groups=groups, @@ -228,7 +236,7 @@ def _save(self, force=False): # password field has to exist because of how FilebasedUserManager processes # data, but an empty password hash cannot match any entered password (as # whatever the user enters will be hashed... even an empty password. - "password": None, + "password": user._passwordHash, "active": user._active, "groups": self._from_groups(*user._groups),