From b96d1b51e06fe2518aa6055dcd25e1ba12c75fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 17 Dec 2015 13:08:45 +0100 Subject: [PATCH] Disabled ACL is now tracked through enabled flag on UserManager That allows us to properly enable and disable it at runtime (during first run). --- src/octoprint/server/__init__.py | 22 ++++++++++--------- src/octoprint/server/api/__init__.py | 6 +++-- src/octoprint/server/api/users.py | 20 ++++++++--------- src/octoprint/server/util/__init__.py | 2 +- src/octoprint/server/util/flask.py | 2 +- src/octoprint/server/views.py | 6 ++--- src/octoprint/static/js/app/dataupdater.js | 5 +---- src/octoprint/static/js/app/helpers.js | 4 ++++ src/octoprint/static/js/app/main.js | 3 +++ .../static/js/app/viewmodels/firstrun.js | 2 +- src/octoprint/users.py | 15 +++++++++++++ 11 files changed, 55 insertions(+), 32 deletions(-) diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index 0af327b6..97d22064 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -101,7 +101,7 @@ def load_user(id): else: sessionid = None - if settings().getBoolean(["accessControl", "enabled"]) and userManager is not None: + if userManager.enabled: if sessionid: return userManager.findUser(userid=id, session=sessionid) else: @@ -291,13 +291,15 @@ class Server(): events.DebugEventListener() # setup access control - if s.getBoolean(["accessControl", "enabled"]): - userManagerName = s.get(["accessControl", "userManager"]) - try: - clazz = octoprint.util.get_class(userManagerName) - userManager = clazz() - except AttributeError, e: - self._logger.exception("Could not instantiate user manager %s, will run with accessControl disabled!" % userManagerName) + userManagerName = s.get(["accessControl", "userManager"]) + try: + clazz = octoprint.util.get_class(userManagerName) + userManager = clazz() + except AttributeError, e: + self._logger.exception("Could not instantiate user manager {}, falling back to FilebasedUserManager!".format(userManagerName)) + userManager = octoprint.users.FilebasedUserManager() + finally: + userManager.enabled = s.getBoolean(["accessControl", "enabled"]) app.wsgi_app = util.ReverseProxied( app.wsgi_app, @@ -321,7 +323,7 @@ class Server(): loginManager = LoginManager() loginManager.session_protection = "strong" loginManager.user_callback = load_user - if userManager is None: + if not userManager.enabled: loginManager.anonymous_user = users.DummyUser principals.identity_loaders.appendleft(users.dummy_identity_loader) loginManager.init_app(app) @@ -535,7 +537,7 @@ class Server(): if "l10n" in request.values: return Locale.negotiate([request.values["l10n"]], LANGUAGES) - if hasattr(g, "identity") and g.identity and userManager is not None: + if hasattr(g, "identity") and g.identity and userManager.enabled: userid = g.identity.id try: user_language = userManager.getUserSetting(userid, ("interface", "language")) diff --git a/src/octoprint/server/api/__init__.py b/src/octoprint/server/api/__init__.py index 961441fa..c7749361 100644 --- a/src/octoprint/server/api/__init__.py +++ b/src/octoprint/server/api/__init__.py @@ -111,6 +111,7 @@ def firstRunSetup(): "pass2" in request.values.keys() and request.values["pass1"] == request.values["pass2"]: # configure access control s().setBoolean(["accessControl", "enabled"], True) + octoprint.server.userManager.enable() octoprint.server.userManager.addUser(request.values["user"], request.values["pass1"], True, ["user", "admin"]) s().setBoolean(["server", "firstRun"], False) elif "ac" in request.values.keys() and not request.values["ac"] in valid_boolean_trues: @@ -120,6 +121,7 @@ def firstRunSetup(): octoprint.server.loginManager.anonymous_user = octoprint.users.DummyUser octoprint.server.principals.identity_loaders.appendleft(octoprint.users.dummy_identity_loader) + octoprint.server.userManager.disable() s().save() return NO_CONTENT @@ -181,7 +183,7 @@ def performSystemAction(): @api.route("/login", methods=["POST"]) def login(): - if octoprint.server.userManager is not None and "user" in request.values.keys() and "pass" in request.values.keys(): + if octoprint.server.userManager.enabled and "user" in request.values.keys() and "pass" in request.values.keys(): username = request.values["user"] password = request.values["pass"] @@ -196,7 +198,7 @@ def login(): user = octoprint.server.userManager.findUser(username) if user is not None: if octoprint.server.userManager.checkPassword(username, password): - if octoprint.server.userManager is not None: + if octoprint.server.userManager.enabled: user = octoprint.server.userManager.login_user(user) session["usersession.id"] = user.get_session() g.user = user diff --git a/src/octoprint/server/api/users.py b/src/octoprint/server/api/users.py index 19472d95..c423bcf8 100644 --- a/src/octoprint/server/api/users.py +++ b/src/octoprint/server/api/users.py @@ -23,7 +23,7 @@ from octoprint.server.util.flask import restricted_access @restricted_access @admin_permission.require(403) def getUsers(): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) return jsonify({"users": userManager.getAllUsers()}) @@ -33,7 +33,7 @@ def getUsers(): @restricted_access @admin_permission.require(403) def addUser(): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if not "application/json" in request.headers["Content-Type"]: @@ -62,7 +62,7 @@ def addUser(): @api.route("/users/", methods=["GET"]) @restricted_access def getUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is not None and not current_user.is_anonymous() and (current_user.get_name() == username or current_user.is_admin()): @@ -79,7 +79,7 @@ def getUser(username): @restricted_access @admin_permission.require(403) def updateUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) user = userManager.findUser(username) @@ -110,7 +110,7 @@ def updateUser(username): @restricted_access @admin_permission.require(http_exception=403) def removeUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) try: @@ -123,7 +123,7 @@ def removeUser(username): @api.route("/users//password", methods=["PUT"]) @restricted_access def changePasswordForUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is not None and not current_user.is_anonymous() and (current_user.get_name() == username or current_user.is_admin()): @@ -151,7 +151,7 @@ def changePasswordForUser(username): @api.route("/users//settings", methods=["GET"]) @restricted_access def getSettingsForUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is None or current_user.is_anonymous() or (current_user.get_name() != username and not current_user.is_admin()): @@ -165,7 +165,7 @@ def getSettingsForUser(username): @api.route("/users//settings", methods=["PATCH"]) @restricted_access def changeSettingsForUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is None or current_user.is_anonymous() or (current_user.get_name() != username and not current_user.is_admin()): @@ -185,7 +185,7 @@ def changeSettingsForUser(username): @api.route("/users//apikey", methods=["DELETE"]) @restricted_access def deleteApikeyForUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is not None and not current_user.is_anonymous() and (current_user.get_name() == username or current_user.is_admin()): @@ -201,7 +201,7 @@ def deleteApikeyForUser(username): @api.route("/users//apikey", methods=["POST"]) @restricted_access def generateApikeyForUser(username): - if userManager is None: + if not userManager.enabled: return jsonify(SUCCESS) if current_user is not None and not current_user.is_anonymous() and (current_user.get_name() == username or current_user.is_admin()): diff --git a/src/octoprint/server/util/__init__.py b/src/octoprint/server/util/__init__.py index 20640e64..4ac355d2 100644 --- a/src/octoprint/server/util/__init__.py +++ b/src/octoprint/server/util/__init__.py @@ -120,7 +120,7 @@ def get_user_for_apikey(apikey): if apikey == settings().get(["api", "key"]) or octoprint.server.appSessionManager.validate(apikey): # master key or an app session key was used return ApiUser() - elif octoprint.server.userManager is not None: + elif octoprint.server.userManager.enabled: # user key might have been used return octoprint.server.userManager.findUser(apikey=apikey) return None diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index b17690f6..8a566a6f 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -222,7 +222,7 @@ def fix_webassets_filtertool(): #~~ passive login helper def passive_login(): - if octoprint.server.userManager is not None: + if octoprint.server.userManager.enabled: user = octoprint.server.userManager.login_user(flask.ext.login.current_user) else: user = flask.ext.login.current_user diff --git a/src/octoprint/server/views.py b/src/octoprint/server/views.py index f3461eba..83fdcdde 100644 --- a/src/octoprint/server/views.py +++ b/src/octoprint/server/views.py @@ -44,7 +44,7 @@ def index(): enable_gcodeviewer = settings().getBoolean(["gcodeViewer", "enabled"]) enable_timelapse = (settings().get(["webcam", "snapshot"]) and settings().get(["webcam", "ffmpeg"])) enable_systemmenu = settings().get(["system"]) is not None and settings().get(["system", "actions"]) is not None - enable_accesscontrol = userManager is not None + enable_accesscontrol = userManager.enabled preferred_stylesheet = settings().get(["devel", "stylesheet"]) locales = dict((l.language, dict(language=l.language, display=l.display_name, english=l.english_name)) for l in LOCALES) @@ -281,11 +281,11 @@ def index(): #~~ prepare full set of template vars for rendering - first_run = settings().getBoolean(["server", "firstRun"]) and (userManager is None or not userManager.hasBeenCustomized()) + first_run = settings().getBoolean(["server", "firstRun"]) and userManager.enabled and not userManager.hasBeenCustomized() render_kwargs = dict( webcamStream=settings().get(["webcam", "stream"]), enableTemperatureGraph=settings().get(["feature", "temperatureGraph"]), - enableAccessControl=userManager is not None, + enableAccessControl=userManager.enabled, enableSdSupport=settings().get(["feature", "sdSupport"]), firstRun=first_run, debug=debug, diff --git a/src/octoprint/static/js/app/dataupdater.js b/src/octoprint/static/js/app/dataupdater.js index 4caf44ac..4e867f1e 100644 --- a/src/octoprint/static/js/app/dataupdater.js +++ b/src/octoprint/static/js/app/dataupdater.js @@ -11,9 +11,6 @@ function DataUpdater(allViewModels) { self._pluginHash = undefined; - self.reloadOverlay = $("#reloadui_overlay"); - $("#reloadui_overlay_reload").click(function() { location.reload(); }); - self.connect = function() { var options = {}; if (SOCKJS_DEBUG) { @@ -142,7 +139,7 @@ function DataUpdater(allViewModels) { } if (oldVersion != VERSION || (oldPluginHash != undefined && oldPluginHash != self._pluginHash)) { - self.reloadOverlay.show(); + showReloadOverlay(); } break; diff --git a/src/octoprint/static/js/app/helpers.js b/src/octoprint/static/js/app/helpers.js index 181229fb..40924fe0 100644 --- a/src/octoprint/static/js/app/helpers.js +++ b/src/octoprint/static/js/app/helpers.js @@ -476,6 +476,10 @@ function showConfirmationDialog(message, onacknowledge) { confirmationDialog.modal("show"); } +function showReloadOverlay() { + $("#reloadui_overlay").show(); +} + function commentableLinesToArray(lines) { return splitTextToArray(lines, "\n", true, function(item) {return !_.startsWith(item, "#")}); } diff --git a/src/octoprint/static/js/app/main.js b/src/octoprint/static/js/app/main.js index 02930e08..bdf2c89a 100644 --- a/src/octoprint/static/js/app/main.js +++ b/src/octoprint/static/js/app/main.js @@ -490,6 +490,9 @@ $(function() { e.preventDefault(); }); + // reload overlay + $("#reloadui_overlay_reload").click(function() { location.reload(); }); + //~~ Starting up the app _.each(allViewModels, function(viewModel) { diff --git a/src/octoprint/static/js/app/viewmodels/firstrun.js b/src/octoprint/static/js/app/viewmodels/firstrun.js index 9e5552dd..6aeb2bd8 100644 --- a/src/octoprint/static/js/app/viewmodels/firstrun.js +++ b/src/octoprint/static/js/app/viewmodels/firstrun.js @@ -46,7 +46,7 @@ $(function() { }; self._sendData(data, function() { // if the user indeed disables access control, we'll need to reload the page for this to take effect - //location.reload(true); // TODO: clear cache doesn't work properly, needs a better way, same issue with reloading plugins + showReloadOverlay(); }); }); $("#confirmation_dialog").modal("show"); diff --git a/src/octoprint/users.py b/src/octoprint/users.py index d4890a64..b6425dd7 100644 --- a/src/octoprint/users.py +++ b/src/octoprint/users.py @@ -26,6 +26,21 @@ class UserManager(object): self._logger = logging.getLogger(__name__) self._session_users_by_session = dict() self._session_users_by_userid = dict() + self._enabled = True + + @property + def enabled(self): + return self._enabled + + @enabled.setter + def enabled(self, value): + self._enabled = value + + def enable(self): + self._enabled = True + + def disable(self): + self._enabled = False def login_user(self, user): self._cleanup_sessions()