diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cab60f5..f09da2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,8 @@ ### New Features * Added internationalization of UI. Translations of OctoPrint are being crowd sourced via [Transifex](https://www.transifex.com/projects/p/octoprint/). - The following translations are already available with more in the works: - - Dutch (nl) - - German (de) - - French (fr) - - Hebrew (he) - - Norwegian (no) - - Romanian (ro) + Language Packs for both the core application as well as installed plugins can be uploaded through a new management + dialog in Settings > Appearance > Language Packs. * New file list: Pagination is gone, no more (mobile incompatible) pop overs, instead scrollable and with instant search * You can now define a folder (default: `~/.octoprint/watched`) to be watched for newly added GCODE (or -- if slicing @@ -139,10 +134,11 @@ * [#435](https://github.com/foosel/OctoPrint/issues/435) - Always interpret negative duration (e.g. for print time left) as 0 -* [#633](https://github.com/foosel/OctoPrint/issues/633) - Correctly interpret temperature lines from multi extruder - setups under Smoothieware +* [#516](https://github.com/foosel/OctoPrint/issues/516) - Also require API key even if ACL is disabled. * [#556](https://github.com/foosel/OctoPrint/issues/556) - Allow login of the same user from multiple browsers without side effects +* [#633](https://github.com/foosel/OctoPrint/issues/633) - Correctly interpret temperature lines from multi extruder + setups under Smoothieware * [#680](https://github.com/foosel/OctoPrint/issues/680) - Don't accidentally include a newline from the MIME headers in the parsed multipart data from file uploads * [#709](https://github.com/foosel/OctoPrint/issues/709) - Properly initialize time estimation for SD card transfers too diff --git a/src/octoprint/server/util/flask.py b/src/octoprint/server/util/flask.py index 3c7624e6..8881f6e9 100644 --- a/src/octoprint/server/util/flask.py +++ b/src/octoprint/server/util/flask.py @@ -276,7 +276,7 @@ def redirect_to_tornado(request, target, code=302): return flask.redirect(redirectUrl, code=code) -def restricted_access(func, api_enabled=True): +def restricted_access(func): """ If you decorate a view with this, it will ensure that first setup has been done for OctoPrint's Access Control plus that any conditions of the @@ -288,11 +288,12 @@ def restricted_access(func, api_enabled=True): that it's user database has been customized from default), the decorator will cause a HTTP 403 status code to be returned by the decorated resource. - If an API key is provided and it matches a known key, the user will be logged in and - the view will be called directly. If the provided key doesn't match any known key, - a HTTP 403 status code will be returned by the decorated resource. + If the API key matches the UI API key, the result of calling login_required for the + view will be returned (browser session mode). - Otherwise the result of calling login_required will be returned. + Otherwise the API key will be attempted to be resolved to a user. If that is + successful the user will be logged in and the view will be called directly. + Otherwise a HTTP 401 status code will be returned. """ @functools.wraps(func) def decorated_view(*args, **kwargs): @@ -300,19 +301,24 @@ def restricted_access(func, api_enabled=True): if settings().getBoolean(["server", "firstRun"]) and (octoprint.server.userManager is None or not octoprint.server.userManager.hasBeenCustomized()): return flask.make_response("OctoPrint isn't setup yet", 403) - # if API is globally enabled, enabled for this request and an api key is provided that is not the current UI API key, try to use that apikey = octoprint.server.util.get_api_key(flask.request) - if settings().get(["api", "enabled"]) and api_enabled and apikey is not None and apikey != octoprint.server.UI_API_KEY: - user = octoprint.server.util.get_user_for_apikey(apikey) + if apikey == octoprint.server.UI_API_KEY: + # UI API key => call regular login_required decorator, we are using browser sessions here + return flask.ext.login.login_required(func)(*args, **kwargs) - if user is None: - return flask.make_response("Invalid API key", 401) - if flask.ext.login.login_user(user, remember=False): - flask.ext.principal.identity_changed.send(flask.current_app._get_current_object(), identity=flask.ext.principal.Identity(user.get_id())) - return func(*args, **kwargs) + # try to determine user for key + user = octoprint.server.util.get_user_for_apikey(apikey) + if user is None: + # no user or no key => go away + return flask.make_response("Invalid API key", 401) + + if not flask.ext.login.login_user(user, remember=False): + # user for API key could not be logged in => go away + return flask.make_response("Invalid API key", 401) + + flask.ext.principal.identity_changed.send(flask.current_app._get_current_object(), identity=flask.ext.principal.Identity(user.get_id())) + return func(*args, **kwargs) - # call regular login_required decorator - return flask.ext.login.login_required(func)(*args, **kwargs) return decorated_view