def user(ctx): """ User management. Note that this currently only supports managing user accounts stored in the configured user manager, not any user managers added through plugins and the "octoprint.users.factory" hook. """ try: logging.basicConfig( level=logging.DEBUG if get_ctx_obj_option(ctx, "verbosity", 0) > 0 else logging.WARN) settings = init_settings(get_ctx_obj_option(ctx, "basedir", None), get_ctx_obj_option(ctx, "configfile", None)) name = settings.get(["accessControl", "userManager"]) try: clazz = get_class(name) manager = clazz(settings=settings) except Exception: click.echo( "Could not instantiate user manager {}, falling back to FilebasedUserManager!" .format(name), err=True) manager = FilebasedUserManager(settings=settings) finally: manager.enabled = settings.getBoolean(["accessControl", "enabled"]) ctx.obj.user_manager = manager except Exception: click.echo("Could not instantiate user manager", err=True) return
def checkPassword(self, username, password): try: connection = self.getLDAPClient() username = self.escapeLDAP(username) dn = self.findLDAPUser(username) if dn is None: return False connection.bind_s(dn, password) connection.unbind_s() user = FilebasedUserManager.findUser(self, username) if not user: self._logger.debug("Add new user") self.addUser(username, str(uuid.uuid4()), True) return True except ldap.INVALID_CREDENTIALS: self._logger.error("LDAP : Your username or password is incorrect.") return FilebasedUserManager.checkPassword(self, username, password) except ldap.LDAPError, e: if type(e.message) == dict: for (k, v) in e.message.iteritems(): self._logger.error("%s: %sn" % (k, v)) else: self._logger.error(e.message) return False
def __init__(self, components, settings): OAuthbasedUserManager.logger.info("Initializing OAuthbasedUserManager") self._components = components self._settings = settings # Get data from config file self.oauth2 = self._settings.get(["plugins", "oauth2"]) self.path_for_token = self.oauth2["token_path"] self.path_user_info = self.oauth2["user_info_path"] self.username_key = self.oauth2["username_key"] self.access_token_query_key = self.oauth2["access_token_query_key"] try: self.token_headers = self.oauth2["token_headers"] except KeyError: self.token_headers = None # Init FilebasedUserManager, other methods are needed for OctoPrint FilebasedUserManager.__init__(self)
def __init__(self): FilebasedUserManager.__init__(self) self.url = (settings().get(['accessControl', 'fabman', 'url']) or self.FABMAN_API_URL).rstrip('/') self.fabman_enabled = settings().getBoolean( ['accessControl', 'fabman', 'enabled']) or False self.local_enabled = settings().getBoolean( ['accessControl', 'fabman', 'allowLocalUsers']) or False self.fabman_account = settings().getInt( ['accessControl', 'fabman', 'accountId']) self.restrict_access = settings().getBoolean( ['accessControl', 'fabman', 'restrictAccess']) or False self.resource_set = set( settings().get(['accessControl', 'fabman', 'resourceIds']) or []) # { username: (id, cookie) } self.fabman_users = {}
def __init__(self): if settings().get(["accessControl", "userManager" ]) == 'octoprint_authldap.LDAPUserManager': if settings().get(["plugins", "authldap", "ldap_uri"]) is not None\ and settings().get(["plugins", "authldap", "ldap_bind_user"]) is not None \ and settings().get(["plugins", "authldap", "ldap_bind_password"]) is not None \ and settings().get(["plugins", "authldap", "ldap_search_base"]) is not None \ and settings().get(["plugins", "authldap", "ldap_query"]) is not None: connection = ldap.initialize(settings().get( ["plugins", "authldap", "ldap_uri"])) connection.set_option(ldap.OPT_REFERRALS, 0) if settings().get(["plugins", "authldap", "ldap_method"]) == 'SECURE': ldap_verifypeer = settings().get( ["plugins", "authldap", "ldap_tls_reqcert"]) verifypeer = ldap.OPT_X_TLS_HARD if ldap_verifypeer == 'NEVER': verifypeer = ldap.OPT_X_TLS_NEVER elif ldap_verifypeer == 'ALLOW': verifypeer = ldap.OPT_X_TLS_ALLOW elif ldap_verifypeer == 'TRY': verifypeer = ldap.OPT_X_TLS_TRY elif ldap_verifypeer == 'DEMAND': verifypeer = ldap.OPT_X_TLS_DEMAND # elif ldap_verifypeer == 'HARD': # verifypeer = ldap.OPT_X_TLS_HARD connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, verifypeer) try: connection.start_tls_s() except: pass try: connection.simple_bind_s( settings().get( ["plugins", "authldap", "ldap_bind_user"]), settings().get( ["plugins", "authldap", "ldap_bind_password"])) connection.unbind_s() FilebasedUserManager.__init__(self) return except: pass
def checkPassword(self, username, password): if self.local_enabled: user = super(FabmanUserManager, self).findUser(username) if user is not None and not isinstance(user, FabmanUser): return FilebasedUserManager.checkPassword( self, username, password) if not self.fabman_enabled: return False return self._fabman_auth(username, password)
def findUser(self, userid=None, apikey=None, session=None): """ Find user using FilebasedUserManager, else set temporary user. This is because of implementation of server/api. """ user = FilebasedUserManager.findUser(self, userid, apikey, session) if user is not None: return user # making temporary user because of implementation of api # and we need to pass our code from OAuth to login_user # api login could be found in server/api/__init__.py user = User(userid, "", 1, ["user"]) return user
def findUser(self, userid=None, apikey=None, session=None): local_user = FilebasedUserManager.findUser(self, userid, apikey, session) #If user not exists in local database, search it on LDAP if userid and not local_user: if(self.findLDAPUser(userid)): #Return a fake user instance return User(userid, str(uuid.uuid4()), True, ["user"]) else: return None else : self._logger.debug("Local user found") return local_user
def findUser(self, userid=None, apikey=None, session=None): local_user = FilebasedUserManager.findUser(self, userid, apikey, session) #If user not exists in local database, search it on LDAP if userid and not local_user: if (self.findLDAPUser(userid)): # Return a fake user instance return User( userid, str(uuid.uuid4()), settings().getBoolean( ["plugins", "authldap", "auto_activate"]), self.getRoles()) else: return None else: self._logger.debug("Local user found") return local_user
def login_user(self, user): """ This method logs in the user into OctoPrint using authorization OAuth2. Users user.get_id() should be dict containing redirect_uri and code. It is obtained by view model in static/js folder. Method gets specified data from config yaml - client_id and client_secret, then start OAuth2Session from requests_oauthlib library. Using the library method fetch the access token using method get_token. After that, user is added into users.yaml config file. """ self._cleanup_sessions() if user is None: return if isinstance(user, LocalProxy): user = user._get_current_object() return user if not isinstance(user, User): return None if not isinstance(user, SessionUser): # from get_id we get for each user his redirect uri and code try: redirect_uri = user.get_id()['redirect_uri'] code = user.get_id()['code'] except KeyError: OAuthbasedUserManager.logger.error( "Code or redirect_uri not found") return None client_id = self.oauth2[redirect_uri]["client_id"] client_secret = self.oauth2[redirect_uri]["client_secret"] oauth2_session = OAuth2Session(client_id, redirect_uri=redirect_uri) access_token = self.get_token(oauth2_session, code, client_id, client_secret) if access_token is None: return None username = self.get_username(oauth2_session) if username is None: OAuthbasedUserManager.logger.error("Username none") return None user = FilebasedUserManager.findUser(self, username) if user is None: self.addUser(username, "", True, ["user"]) user = self.findUser(username) if not isinstance(user, SessionUser): user = SessionUser(user) self._session_users_by_session[user.session] = user user_id = user.get_id() if user_id not in self._sessionids_by_userid: self._sessionids_by_userid[user_id] = set() self._sessionids_by_userid[user_id].add(user.session) return user
def changeUserPassword(self, username, password): #Changing password of LDAP users is not allowed if FilebasedUserManager.findUser(self, username) is not None: return FilebasedUserManager.changeUserPassword(self, username, password)
class LDAPUserManager(FilebasedUserManager, octoprint.plugin.SettingsPlugin, octoprint.plugin.TemplatePlugin): # Login phase : # - findUser called, if it return a user # - checkPassword called, if it return True # - login_user called with User returned by previous findUser _localUserManager = FilebasedUserManager() def __init__(self): if settings().get(["accessControl", "userManager" ]) == 'octoprint_authldap.LDAPUserManager': if settings().get(["plugins", "authldap", "ldap_uri"]) is not None\ and settings().get(["plugins", "authldap", "ldap_bind_user"]) is not None \ and settings().get(["plugins", "authldap", "ldap_bind_password"]) is not None \ and settings().get(["plugins", "authldap", "ldap_search_base"]) is not None \ and settings().get(["plugins", "authldap", "ldap_query"]) is not None: connection = ldap.initialize(settings().get( ["plugins", "authldap", "ldap_uri"])) connection.set_option(ldap.OPT_REFERRALS, 0) if settings().get(["plugins", "authldap", "ldap_method"]) == 'SECURE': ldap_verifypeer = settings().get( ["plugins", "authldap", "ldap_tls_reqcert"]) verifypeer = ldap.OPT_X_TLS_HARD if ldap_verifypeer == 'NEVER': verifypeer = ldap.OPT_X_TLS_NEVER elif ldap_verifypeer == 'ALLOW': verifypeer = ldap.OPT_X_TLS_ALLOW elif ldap_verifypeer == 'TRY': verifypeer = ldap.OPT_X_TLS_TRY elif ldap_verifypeer == 'DEMAND': verifypeer = ldap.OPT_X_TLS_DEMAND # elif ldap_verifypeer == 'HARD': # verifypeer = ldap.OPT_X_TLS_HARD connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, verifypeer) try: connection.start_tls_s() except: pass try: connection.simple_bind_s( settings().get( ["plugins", "authldap", "ldap_bind_user"]), settings().get( ["plugins", "authldap", "ldap_bind_password"])) connection.unbind_s() FilebasedUserManager.__init__(self) return except: pass #settings().remove(["accessControl", "userManager"]) #settings().remove(["plugins", "authldap", "active"]) #settings().save() #os.system('kill $PPID') def findUser(self, userid=None, apikey=None, session=None): user = UserManager.findUser(self, userid=userid, session=session) if user is not None: self._logger.debug("User already logged in.") return user elif apikey is not None: self._logger.debug("User logs in via API Key.") return self._localUserManager.findUser(apikey=apikey, session=session) elif userid is not None: self._logger.debug("User not yet logged in: %s" % userid) local_user = self._localUserManager.findUser(userid=userid, session=session) if local_user is not None: self._logger.debug("User found locally") return local_user elif self.findLDAPUser(userid): self._logger.debug("User found in LDAP") password = ''.join( [random.choice(string.lowercase) for i in range(10)]) if settings().get(["plugins", "authldap", "roles"]) is not None: roles = [ x.strip() for x in settings().get( ["plugins", "authldap", "roles"]).split(',') ] self._localUserManager.addUser(userid, password, active=settings().getBoolean([ "plugins", "authldap", "auto_activate" ]), roles=roles) return self._localUserManager.findUser(userid=userid, session=session) else: return None else: return None def findLDAPUser(self, userid): userid = self.escapeLDAP(userid) self._logger.debug("Searching User in ldap: %s" % userid) connection = self.getLDAPClient() try: self._logger.debug( "Binding LDAP with User: %s" % settings().get(["plugins", "authldap", "ldap_bind_user"])) connection.simple_bind_s( settings().get(["plugins", "authldap", "ldap_bind_user"]), settings().get(["plugins", "authldap", "ldap_bind_password"])) query = settings().get(["plugins", "authldap", "ldap_query"]).format(uid=userid) self._logger.debug( "Searching for \"uid=%s\" under \"%s\" " % (query, settings().get( ["plugins", "authldap", "ldap_search_base"]))) result = connection.search_s( settings().get(["plugins", "authldap", "ldap_search_base"]), ldap.SCOPE_SUBTREE, query) connection.unbind_s() self._logger.debug("Search finished.") if result is None or len(result) == 0: self._logger.debug("No User Found in LDAP") return None # Get the DN of first user found dn, data = result[0] self._logger.debug("User Found %s" % dn) return dn except ldap.SERVER_DOWN: self._logger.debug("LDAP Server unreachable!") return None def checkPassword(self, username, password): self._logger.debug("Checking Password") if self.findLDAPUser(username) is not None: self._logger.debug("User is a LDAP User") try: connection = self.getLDAPClient() username = self.escapeLDAP(username) dn = self.findLDAPUser(username) connection.simple_bind_s(dn, password) connection.unbind_s() return True except ldap.INVALID_CREDENTIALS: self._logger.error("Username or password is incorrect.") else: self._logger.debug("User is a local user") return self._localUserManager.checkPassword(username, password) def changeUserPassword(self, username, password): # Changing password of LDAP users is not allowed if self.findLDAPUser(username) is None: return self._localUserManager.changeUserPassword( username, password) else: self._logger.error("User is not allowed to change the Password.") def getLDAPClient(self): self._logger.debug("Creating LDAP Client") ldap_server = settings().get(["plugins", "authldap", "ldap_uri"]) self._logger.debug("LDAP URL %s" % ldap_server) if not ldap_server: settings().remove(["accessControl", "userManager"]) self._logger.debug( "UserManager: %s" % settings().get(["accessControl", "userManager"])) raise Exception("LDAP conf error, server is missing") connection = ldap.initialize(ldap_server) connection.set_option(ldap.OPT_REFERRALS, 0) self._logger.debug("LDAP initialized") if settings().get(["plugins", "authldap", "ldap_method"]) == 'SECURE': self._logger.debug("LDAP is using TLS, setting ldap options...") ldap_verifypeer = settings().get( ["plugins", "authldap", "ldap_tls_reqcert"]) verifypeer = ldap.OPT_X_TLS_HARD if ldap_verifypeer == 'NEVER': verifypeer = ldap.OPT_X_TLS_NEVER elif ldap_verifypeer == 'ALLOW': verifypeer = ldap.OPT_X_TLS_ALLOW elif ldap_verifypeer == 'TRY': verifypeer = ldap.OPT_X_TLS_TRY elif ldap_verifypeer == 'DEMAND': verifypeer = ldap.OPT_X_TLS_DEMAND # elif ldap_verifypeer == 'HARD': # verifypeer = ldap.OPT_X_TLS_HARD connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, verifypeer) try: connection.start_tls_s() self._logger.error("TLS connection established.") except: self._logger.error("Error initializing tls connection") pass self._logger.error("Finished creating connection") return connection def escapeLDAP(self, str): reservedStrings = [ '+', '=', '\\', '\r', '\n', '#', ',', '>', '<', '"', ';' ] for ch in reservedStrings: if ch in str: str = str.replace(ch, '\\' + ch) return str # Softwareupdate hook def get_update_information(self): return dict(authldap=dict( displayName="AuthLDAP", displayVersion=self._plugin_version, # version check: github repository type="github_release", user="******", repo="OctoPrint-LDAP", current=self._plugin_version, # update method: pip pip=("https://github.com" "/bveina/OctoPrint-LDAP/archive/{target_version}.zip"))) # UserManager hook def ldap_user_factory(components, settings, *args, **kwargs): return LDAPUserManager() # SettingsPlugin def get_settings_defaults(self): return dict(active=False, ldap_uri=None, ldap_search_base=None, ldap_query=None, ldap_method=None, auto_activate=False, roles=None, ldap_tls_reqcert=None, ldap_bind_user=None, ldap_bind_password=None) def on_settings_save(self, data): old_flag = self._settings.get_boolean(["active"]) octoprint.plugin.SettingsPlugin.on_settings_save(self, data) new_flag = self._settings.get_boolean(["active"]) if new_flag != old_flag: if new_flag: self._logger.warning("Warning! Activating LDAP Plugin") settings().set(["accessControl", "userManager"], 'octoprint_authldap.LDAPUserManager') settings().save() else: if settings().get(["accessControl", "userManager" ]) == 'octoprint_authldap.LDAPUserManager': self._logger.warning("Deactivating LDAP Plugin") settings().remove(["accessControl", "userManager"]) settings().save() # TemplatePlugin def get_template_configs(self): return [dict(type="settings", custom_bindings=False)]