Exemple #1
0
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
Exemple #2
0
    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
Exemple #3
0
    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 = {}
Exemple #5
0
    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)
Exemple #7
0
    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
Exemple #8
0
    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
Exemple #9
0
    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
Exemple #10
0
    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
Exemple #11
0
 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)
Exemple #12
0
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)]