Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge branch 'staging/maintenance' into maintenance
  • Loading branch information
foosel committed Feb 26, 2020
2 parents e0b0985 + cf560a4 commit 0c3b0b8
Show file tree
Hide file tree
Showing 41 changed files with 852 additions and 395 deletions.
10 changes: 5 additions & 5 deletions .versioneer-lookup
Expand Up @@ -24,13 +24,13 @@ maintenance 1.4.1 2da7aa358d950b4567aaab8f18d6b5779193e077 pep440-dev
fix/.* 1.4.1 2da7aa358d950b4567aaab8f18d6b5779193e077 pep440-dev
improve/.* 1.4.1 2da7aa358d950b4567aaab8f18d6b5779193e077 pep440-dev

# staging/maintenance is currently the branch for preparation of 1.4.0rc6
# staging/maintenance is currently the branch for preparation of 1.4.0rc7
# so is regressionfix/...
staging/maintenance 1.4.0rc6 73f7c4d8a11a7aea7b0ece474d3bf37ad53c65d4 pep440-dev
regressionfix/.* 1.4.0rc6 73f7c4d8a11a7aea7b0ece474d3bf37ad53c65d4 pep440-dev
staging/maintenance 1.4.0rc7 d99af420acb9d5b18a4f60f9cae8abb458e131d4 pep440-dev
regressionfix/.* 1.4.0rc7 d99af420acb9d5b18a4f60f9cae8abb458e131d4 pep440-dev

# staging/devel is currently inactive (but has the 1.4.0rc6 namespace)
staging/devel 1.4.0rc6 73f7c4d8a11a7aea7b0ece474d3bf37ad53c65d4 pep440-dev
# staging/devel is currently inactive (but has the 1.4.0rc7 namespace)
staging/devel 1.4.0rc7 d99af420acb9d5b18a4f60f9cae8abb458e131d4 pep440-dev

# every other branch is a development branch and thus gets resolved to 1.5.0-dev for now
.* 1.5.0 2da7aa358d950b4567aaab8f18d6b5779193e077 pep440-dev
4 changes: 2 additions & 2 deletions SUPPORTERS.md
Expand Up @@ -23,6 +23,7 @@ thanks to everyone who contributed!
* GadgetAngel
* George Robles
* Greg Holloway
* Hog Duske
* Hugh Blemings
* jean-claude migneault
* Jeff Renfer
Expand Down Expand Up @@ -55,11 +56,10 @@ thanks to everyone who contributed!
* Ronald Griehsler
* Sacha Telgenhof
* sghnsk
* Shawn Lewis
* Simon Hallam
* Stefan Krister
* Sven Mueller
* Trent Shumay
* Ulrich Kempken

and 1746 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel) or via [Github Sponsors](https://github.com/users/foosel/sponsorship)!
and 1764 more wonderful people pledging on the [Patreon campaign](https://patreon.com/foosel) or via [Github Sponsors](https://github.com/users/foosel/sponsorship)!
3 changes: 3 additions & 0 deletions docs/api/push.rst
Expand Up @@ -29,6 +29,9 @@ following message types are currently available for usage by 3rd party clients:

* ``connected``: Initial connection information, sent only right after establishing the socket connection. See
:ref:`the payload data model <sec-api-push-datamodel-connected>`.
* ``reauthRequired``: A reauthentication of the current login session is required. The ``reason`` parameter in the
payload defines whether a full active login is necessary (values ``logout`` and ``removed``) or a simple passive
login will suffice (all other values).
* ``current``: Rate limited general state update, payload contains information about the printer's state, job progress,
accumulated temperature points and log lines since last update. OctoPrint will send these updates when new information
is available, but not more often than twice per second in order to not flood the client with messages (e.g.
Expand Down
35 changes: 0 additions & 35 deletions docs/bundledplugins/forcelogin.rst

This file was deleted.

2 changes: 1 addition & 1 deletion docs/bundledplugins/index.rst
Expand Up @@ -14,8 +14,8 @@ Bundled Plugins
backup.rst
discovery.rst
errortracking.rst
forcelogin.rst
logging.rst
loginui.rst
pluginmanager.rst
printer_safety_check.rst
softwareupdate.rst
66 changes: 66 additions & 0 deletions docs/bundledplugins/loginui.rst
@@ -0,0 +1,66 @@
.. _sec-bundledplugins-loginui:

Login UI
========

The Login UI plugin has been bundled since OctoPrint 1.4.0 and replaces the ForceLogin plugin bundled with prior
versions since 1.3.10.

If anonymous read-only access is disabled in the :ref:`Access Control settings <sec-features-access_control>`
it provides a stand alone login dialog that gets displayed instead of OctoPrint's regular UI.

.. _fig-bundledplugins-loginui:
.. figure:: ../images/bundledplugins-loginui-dialog.png
:align: center
:alt: Login dialog

OctoPrint's login dialog.

The plugin allows theming of the dialog through :ref:`a plugin hook <sec-bundledplugins-loginui-hooks-theming>`.

.. warning::

Since the plugin is absolutely required for the case of anonymous read-only access because in this case the
UI itself could not even fully initialize due to a lack of permissions required to do so, it is hidden in the plugin
manager and cannot be disabled through that.

.. _sec-bundledplugins-loginui-hooks:

Hooks
-----

.. _sec-bundledplugins-loginui-hooks-theming:

octoprint.plugin.loginui.theming
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. py:function:: loginui_theming_hook(*args, **kwargs)
Support theming of the login dialog, just in case the core UI is themed as well. Use to return a list of additional
CSS file URLs to inject into the login dialog HTML.

Example usage by a plugin:

.. code-block:: python
def loginui_theming():
from flask import url_for
return [url_for("plugin.myplugin.static", filename="css/loginui_theme.css")]
__plugin_hooks__ = {
"octoprint.plugin.loginui.theming": loginui_theming
}
Only a list of ready-made URLs to CSS files is supported, neither LESS nor JS. Best use
url_for like in the example above to be prepared for any configured prefix URLs.

:return: A list of additional CSS URLs to inject into the login dialog.
:rtype: A list of strings.

.. _sec-bundledplugins-loginui-sourcecode:

Source Code
-----------

The source of the Anonymous Usage Tracking plugin is bundled with OctoPrint and can be
found in its source repository under ``src/octoprint/plugins/loginui``.
43 changes: 39 additions & 4 deletions docs/features/accesscontrol.rst
Expand Up @@ -3,8 +3,20 @@
Access Control
==============

When Access Control is enabled, anonymous users (not logged in) will only see
the read-only parts of the UI which are the following:
OctoPrint's bundled access control feature allows granular permission control
over which users or user groups are allowed to access which parts of OctoPrint.

The default permissions will deny any kind of access to anonymous (not logged in)
users out of the box.

.. warning::

Please note that OctoPrint does *not* control the webcam and merely embeds it, and
thus also cannot limit access to it. If an anonymous user correctly guesses the
webcam URL, they will thus be able to see it.

If read-only access for anonymous users is enabled, anonymous users will have
read-only access to the following parts of the UI:

* printer state
* available gcode files and stats (upload is disabled)
Expand All @@ -16,8 +28,8 @@ the read-only parts of the UI which are the following:
* any components provided through plugins which are enabled for anonymous
users

Logged in users will get access to everything besides the Settings and System
Commands, which are admin-only.
Logged in users without admin flag will be allowed to access everything besides the
Settings and System Commands, which are admin-only.

If Access Control is disabled, everything is directly accessible. **That also
includes all administrative functionality as well as full control over the
Expand All @@ -39,6 +51,29 @@ internet or other untrusted networks!).
publicly reachable by everyone with an internet connection, even with access
control enabled.

.. _sec-features-access_control-hooks:

Available Extension Hooks
-------------------------

There are two hooks for plugins to utilize in order to
add new configurable permissions into the system and/or adjust the styling of the
login dialog.

.. _sec-features-access_control-hooks-permissions:

octoprint.access.permissions
............................

See :ref:`here <sec-plugins-hook-permissions>`.

.. _sec-features-access_control-hooks-loginui:

octoprint.plugin.loginui.theming
................................

See :ref:`here <sec-bundledplugins-loginui-hooks-theming>`.

.. _sec-features-access_control-rerunning_wizard:

Rerunning the wizard
Expand Down
32 changes: 24 additions & 8 deletions docs/plugins/hooks.rst
Expand Up @@ -1102,6 +1102,27 @@ octoprint.filemanager.preprocessor
:return: The `file_object` as passed in or None, or a replaced version to use instead for further processing.
:rtype: AbstractFileWrapper or None

.. _sec-plugins-hook-plugin-loginui-theming:

octoprint.plugin.loginui.theming
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See :ref:`here <sec-bundledplugins-loginui-hooks-theming>`.

.. _sec-plugins-hook-plugin-pluginmanager-reconnect:

octoprint.plugin.pluginmanager.reconnect_hooks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See :ref:`here <sec-bundledplugins-pluginmanager-hooks-reconnect_hooks>`.

.. _sec-plugins-hook-plugin-softwareupdate-check_config:

octoprint.plugin.softwareupdate.check_config
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See :ref:`here <sec-bundledplugins-softwareupdate-hooks-check_config>`.

.. _sec-plugins-hook-printer-factory:

octoprint.printer.factory
Expand Down Expand Up @@ -1273,8 +1294,7 @@ octoprint.server.api.after_request
Allows adding additional after-request-handlers to API endpoints defined by OctoPrint itself and installed plugins.

Your plugin might need this to further restrict access to API methods. See the bundled "Force Login" plugin for a
usage example.
Your plugin might need this to further restrict access to API methods.

.. important::

Expand All @@ -1289,8 +1309,7 @@ octoprint.server.api.before_request
Allows adding additional before-request-handlers to API endpoints defined by OctoPrint itself and installed plugins.

Your plugin might need this to further restrict access to API methods. See the bundled "Force Login" plugin for a
usage example.
Your plugin might need this to further restrict access to API methods.

.. important::

Expand All @@ -1305,8 +1324,7 @@ octoprint.server.http.access_validator
Allows adding additional access validators to the default tornado routers.

Your plugin might need to this to restrict acccess to downloads and webcam snapshots further. See the bundled
"Force Login" plugin for a usage example.
Your plugin might need to this to restrict acccess to downloads and webcam snapshots further.

.. important::

Expand Down Expand Up @@ -1430,8 +1448,6 @@ octoprint.server.sockjs.authed
Allows plugins to be notified that a user got authenticated or deauthenticated on the socket (e.g. due to logout).

See the bundled :ref:`Forcelogin Plugin <sec-bundledplugins-forcelogin>` for an example on how to utilize this.

:param object socket: the socket object which is about to be registered
:param object user: the user that got authenticated on the socket, or None if the user got deauthenticated

Expand Down
4 changes: 2 additions & 2 deletions src/octoprint/access/groups.py
Expand Up @@ -126,8 +126,8 @@ def _from_groups(self, *groups):
return [group.key for group in groups]

def _to_groups(self, *groups):
return filter(lambda x: x is not None,
[self._to_group(g) for g in groups])
return list(filter(lambda x: x is not None,
[self._to_group(g) for g in groups]))

def _to_group(self, group):
# noinspection PyCompatibility
Expand Down
18 changes: 11 additions & 7 deletions src/octoprint/access/users.py
Expand Up @@ -105,11 +105,11 @@ def login_user(self, user):
self._logger.exception("Error in on_user_logged_in on {!r}".format(listener),
extra=dict(callback=fqcn(listener)))

self._logger.debug("Logged in user: %r" % user)
self._logger.info("Logged in user: {}".format(user.get_id()))

return user

def logout_user(self, user):
def logout_user(self, user, stale=False):
if user is None or user.is_anonymous or isinstance(user, AdminUser):
return

Expand All @@ -129,23 +129,27 @@ def logout_user(self, user):
pass

if sessionid in self._session_users_by_session:
del self._session_users_by_session[sessionid]
try:
del self._session_users_by_session[sessionid]
except KeyError:
pass

for listener in self._login_status_listeners:
try:
listener.on_user_logged_out(user)
listener.on_user_logged_out(user, stale=stale)
except Exception:
self._logger.exception("Error in on_user_logged_out on {!r}".format(listener),
extra=dict(callback=fqcn(listener)))

self._logger.debug("Logged out user: %r" % user)
self._logger.info("Logged out user: {}".format(user.get_id()))

def _cleanup_sessions(self):
for session, user in list(self._session_users_by_session.items()):
if not isinstance(user, SessionUser):
continue
if user.created + (24 * 60 * 60) < monotonic_time():
self.logout_user(user)
self._logger.info("Cleaning up user session {} for user {}".format(session, user.get_id()))
self.logout_user(user, stale=True)

@staticmethod
def create_password_hash(password, salt=None, settings=None):
Expand Down Expand Up @@ -436,7 +440,7 @@ class LoginStatusListener(object):
def on_user_logged_in(self, user):
pass

def on_user_logged_out(self, user):
def on_user_logged_out(self, user, stale=False):
pass

def on_user_modified(self, user):
Expand Down
13 changes: 8 additions & 5 deletions src/octoprint/filemanager/util.py
Expand Up @@ -107,7 +107,7 @@ class MultiStream(io.RawIOBase):
their contents in the order they are provided to the constructor.
Arguments:
*streams (io.IOBase): One or more streams to concatenate.
*streams (io.RawIOBase): One or more streams to concatenate.
"""
def __init__(self, *streams):
io.RawIOBase.__init__(self)
Expand Down Expand Up @@ -159,10 +159,12 @@ class LineProcessorStream(io.RawIOBase):
While reading from this stream the provided `input_stream` is read line by line, calling the (overridable) method
:meth:`.process_line` for each read line.
Sub classes can thus modify the contents of the `input_stream` in line, while it is being read.
Sub classes can thus modify the contents of the `input_stream` in line, while it is being read. Keep in mind that
``process_line`` will receive the line as a byte stream - if underlying code needs to operate on unicode you'll need
to do the decoding yourself.
Arguments:
input_stream (io.IOBase): The stream to process on the fly.
input_stream (io.RawIOBase): The stream to process on the fly.
"""

def __init__(self, input_stream):
Expand Down Expand Up @@ -220,10 +222,11 @@ def process_line(self, line):
wrapper `input_stream`.
Arguments:
line (str): The line as read from `self.input_stream`
line (bytes): The line as read from `self.input_stream` in byte representation (str under Python 2 and
bytes under Python 3)
Returns:
str or None: The processed version of the line (might also be multiple lines), or None if the line is to be
bytes or None: The processed version of the line (might also be multiple lines), or None if the line is to be
stripped from the processed stream.
"""
return line
Expand Down

0 comments on commit 0c3b0b8

Please sign in to comment.