Module: check_mk
Branch: master
Commit: a181ae6987961709bb3118810d2d3a28eff0cba3
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=a181ae69879617…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Sep 7 13:56:16 2018 +0200
6552 FIX Role changes now create change entries on central site
Changes to the roles in WATO triggered change entries for remote sites where the user login
is allowed but were missing to add change entries for the central site.
This is relevant for the "discard changes" feature. In case such a role change is made by one user
and a another, less privileged user, tries to discards his changes it would be possible to discard
the changes of the first user in case no change entry is created.
Change-Id: I5ce62497b00158b6e55459c0fd267528f10ecfba
---
.werks/6552 | 16 ++++++++++++++++
cmk/gui/config.py | 7 ++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/.werks/6552 b/.werks/6552
new file mode 100644
index 0000000..793214e
--- /dev/null
+++ b/.werks/6552
@@ -0,0 +1,16 @@
+Title: Role changes now create change entries on central site
+Level: 1
+Component: wato
+Class: fix
+Compatible: compat
+Edition: cre
+State: unknown
+Version: 1.6.0i1
+Date: 1536239687
+
+Changes to the roles in WATO triggered change entries for remote sites where the user login
+is allowed but were missing to add change entries for the central site.
+
+This is relevant for the "discard changes" feature. In case such a role change is made by one user
+and a another, less privileged user, tries to discards his changes it would be possible to discard
+the changes of the first user in case no change entry is created.
diff --git a/cmk/gui/config.py b/cmk/gui/config.py
index 7acf278..b109980 100644
--- a/cmk/gui/config.py
+++ b/cmk/gui/config.py
@@ -1008,9 +1008,14 @@ def _has_distributed_wato_file():
and os.stat(cmk.paths.check_mk_config_dir + "/distributed_wato.mk").st_size != 0
+def get_login_sites():
+ """Returns the WATO slave sites a user may login and the local site"""
+ return get_login_slave_sites() + [ omd_site() ]
+
+
# TODO: All site listing functions should return the same data structure, e.g. a list of
# pairs (site_id, site)
-def get_login_sites():
+def get_login_slave_sites():
"""Returns a list of site ids which are WATO slave sites and users can login"""
sites = []
for site_id, site in wato_slave_sites():
Module: check_mk
Branch: master
Commit: d83e2ed04df3bc37cca7b84f02ccb59b386fb241
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=d83e2ed04df3bc…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Fri Sep 7 13:55:05 2018 +0200
6551 FIX Fixed missing permission checking during "Discard changes"
Users with reduced privileges that have access to WATO e.g. for managing their
own hosts in specific folders have access to the "Activate changes" page for
activating their config changes. On that page there is a button "discard
changes" which can be used to undo the configuration changes that have been
made since the last activation.
A limitation of this feature is that it can only revert the whole configuration
at all, not only the configuration made by this user. A permitted user would
discard all changes, even the ones made by others in the moment he clicks on
discard changes.
The activation mechanism is aware of the situation where others have made
changes. Users that are not permitted to activate foreign changes are not
able to activate their changes in this situation and get a warning message
about this.
However, the discard changes action was missing such a check which allowed
those users to discard the changes of others while they should not be allowed
to do so.
The discard changes action is now using the same logic as the activate changes
action for checking whether or not a user is allowed to do this.
Change-Id: I09433119f02bc3b4149f431430d7271f542da610
---
.werks/6551 | 32 ++++++++++++++++++++++++++++++++
cmk/gui/wato/__init__.py | 24 ++++++++++++++++++++++--
cmk/gui/watolib.py | 2 +-
3 files changed, 55 insertions(+), 3 deletions(-)
diff --git a/.werks/6551 b/.werks/6551
new file mode 100644
index 0000000..5c54c02
--- /dev/null
+++ b/.werks/6551
@@ -0,0 +1,32 @@
+Title: Fixed missing permission checking during "Discard changes"
+Level: 2
+Component: wato
+Class: fix
+Compatible: compat
+Edition: cre
+State: unknown
+Version: 1.6.0i1
+Date: 1536237858
+
+Users with reduced privileges that have access to WATO e.g. for managing their
+own hosts in specific folders have access to the "Activate changes" page for
+activating their config changes. On that page there is a button "discard
+changes" which can be used to undo the configuration changes that have been
+made since the last activation.
+
+A limitation of this feature is that it can only revert the whole configuration
+at all, not only the configuration made by this user. A permitted user would
+discard all changes, even the ones made by others in the moment he clicks on
+discard changes.
+
+The activation mechanism is aware of the situation where others have made
+changes. Users that are not permitted to activate foreign changes are not
+able to activate their changes in this situation and get a warning message
+about this.
+
+However, the discard changes action was missing such a check which allowed
+those users to discard the changes of others while they should not be allowed
+to do so.
+
+The discard changes action is now using the same logic as the activate changes
+action for checking whether or not a user is allowed to do this.
diff --git a/cmk/gui/wato/__init__.py b/cmk/gui/wato/__init__.py
index 6a222f1..0d57e58 100644
--- a/cmk/gui/wato/__init__.py
+++ b/cmk/gui/wato/__init__.py
@@ -5475,7 +5475,7 @@ class ModeActivateChanges(WatoMode, watolib.ActivateChanges):
home_button()
# TODO: Remove once new changes mechanism has been implemented
- if config.user.may("wato.activate") and self.has_changes() and self._get_last_wato_snapshot_file():
+ if self._may_discard_changes():
html.context_button(_("Discard Changes!"),
html.makeactionuri([("_action", "discard")]),
"discard", id="discard_changes_button")
@@ -5487,6 +5487,23 @@ class ModeActivateChanges(WatoMode, watolib.ActivateChanges):
html.context_button(_("Audit Log"), watolib.folder_preserving_link([("mode", "auditlog")]), "auditlog")
+
+ def _may_discard_changes(self):
+ if not config.user.may("wato.activate"):
+ return False
+
+ if not self.has_changes():
+ return False
+
+ if not config.user.may("wato.activateforeign") and self._has_foreign_changes_on_any_site():
+ return False
+
+ if not self._get_last_wato_snapshot_file():
+ return False
+
+ return True
+
+
def action(self):
if html.var("_action") != "discard":
return
@@ -5494,6 +5511,9 @@ class ModeActivateChanges(WatoMode, watolib.ActivateChanges):
if not html.check_transaction():
return
+ if not self._may_discard_changes():
+ return
+
# TODO: Remove once new changes mechanism has been implemented
# Now remove all currently pending changes by simply restoring the last automatically
# taken snapshot. Then activate the configuration. This should revert all pending changes.
@@ -5593,7 +5613,7 @@ class ModeActivateChanges(WatoMode, watolib.ActivateChanges):
return
if not config.user.may("wato.activateforeign") \
- and self._has_foreign_changes_on_all_sites():
+ and self._has_foreign_changes_on_any_site():
html.show_warning(_("Sorry, you are not allowed to activate changes of other users."))
return
diff --git a/cmk/gui/watolib.py b/cmk/gui/watolib.py
index 689d0f1..9022916 100644
--- a/cmk/gui/watolib.py
+++ b/cmk/gui/watolib.py
@@ -5080,7 +5080,7 @@ class ActivateChanges(object):
if self._is_foreign(change))
- def _has_foreign_changes_on_all_sites(self):
+ def _has_foreign_changes_on_any_site(self):
return any(change for _change_id, change in self._changes
if self._is_foreign(change) and self._affects_all_sites(change))
Module: check_mk
Branch: master
Commit: 8131da5e87db953cda04cf7cfe4afdac549fcaf8
URL: http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=8131da5e87db95…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Thu Aug 23 14:30:15 2018 +0200
Centralized snapin permission name computation
CMK-855
Change-Id: I50ac7825c0686db83d5cff44a16eb71174c4a713
---
cmk/gui/plugins/sidebar/utils.py | 11 +++++++++++
cmk/gui/sidebar.py | 23 +++++++++++++----------
2 files changed, 24 insertions(+), 10 deletions(-)
diff --git a/cmk/gui/plugins/sidebar/utils.py b/cmk/gui/plugins/sidebar/utils.py
index ed9d618..2150483 100644
--- a/cmk/gui/plugins/sidebar/utils.py
+++ b/cmk/gui/plugins/sidebar/utils.py
@@ -48,6 +48,12 @@ class SidebarSnapin(object):
@classmethod
@abc.abstractmethod
+ def type_name(cls):
+ raise NotImplementedError()
+
+
+ @classmethod
+ @abc.abstractmethod
def title(cls):
raise NotImplementedError()
@@ -74,6 +80,11 @@ class SidebarSnapin(object):
@classmethod
+ def permission_name(cls):
+ return "sidesnap.%s" % cls.type_name()
+
+
+ @classmethod
def allowed_roles(cls):
return [ "admin", "user", "guest" ]
diff --git a/cmk/gui/sidebar.py b/cmk/gui/sidebar.py
index 3945402..d4f19f4 100644
--- a/cmk/gui/sidebar.py
+++ b/cmk/gui/sidebar.py
@@ -356,13 +356,17 @@ class UserSidebarConfig(object):
user_config["snapins"] = self._transform_legacy_tuples(user_config["snapins"])
user_config["snapins"] = self._transform_legacy_off_state(user_config["snapins"])
- # Remove entries the user is not allowed for and silently skip
- # configured but not existing snapins
+ # Remove not existing (e.g. legacy) snapins
user_config["snapins"] = [ e for e in user_config["snapins"]
- if e["snapin_type_id"] in snapin_registry
- and self._user.may("sidesnap." + e["snapin_type_id"])]
+ if e["snapin_type_id"] in snapin_registry ]
- return self._from_config(user_config)
+ user_config = self._from_config(user_config)
+
+ # Remove entries the user is not allowed for
+ user_config["snapins"] = [ e for e in user_config["snapins"]
+ if config.user.may(e.snapin_type.permission_name()) ]
+
+ return user_config
def _transform_legacy_list_config(self, user_config):
@@ -478,8 +482,7 @@ def page_side():
html.open_div(class_="scroll" if config.sidebar_show_scrollbar else None, id_="side_content")
for snapin in user_config.snapins:
name = snapin.snapin_type.type_name()
- if not name in snapin_registry or not config.user.may("sidesnap." + name):
- continue
+
# Performs the initial rendering and might return an optional refresh url,
# when the snapin contents are refreshed from an external source
refresh_url = render_snapin(name, snapin.visible)
@@ -602,9 +605,9 @@ def ajax_snapin():
snapin_code = []
for snapname in snapnames:
- if not config.user.may("sidesnap." + snapname):
- continue
snapin_class = snapin_registry.get(snapname)
+ if not config.user.may(snapin_class.permission_name()):
+ continue
snapin = snapin_class()
# When restart snapins are about to be refreshed, only render
@@ -710,7 +713,7 @@ def page_add_snapin():
snapin = snapin_class()
if name in used_snapins:
continue
- if not config.user.may("sidesnap." + name):
+ if not config.user.may(snapin_class.permission_name()):
continue # not allowed for this user
description = snapin.description()