Beispiel #1
0
    def _action(self) -> None:
        assert user.id is not None

        users = userdb.load_users(lock=True)
        user_spec = users[user.id]

        language = request.get_ascii_input_mandatory("language", "")
        # Set the users language if requested to set it explicitly
        if language != "_default_":
            user_spec["language"] = language
            user.language = language
            set_language_cookie(request, response, language)

        else:
            if "language" in user_spec:
                del user_spec["language"]
            user.reset_language()

        # load the new language
        localize(user.language)

        if user.may("general.edit_notifications") and user_spec.get(
                "notifications_enabled"):
            value = forms.get_input(get_vs_flexible_notifications(),
                                    "notification_method")
            user_spec["notification_method"] = value

        # Custom attributes
        if user.may("general.edit_user_attributes"):
            for name, attr in userdb.get_user_attributes():
                if not attr.user_editable():
                    continue

                perm_name = attr.permission()
                if perm_name and not user.may(perm_name):
                    continue

                vs = attr.valuespec()
                value = vs.from_html_vars("ua_" + name)
                vs.validate_value(value, "ua_" + name)
                # TODO: Dynamically fiddling around with a TypedDict is a bit questionable
                user_spec[name] = value  # type: ignore[literal-required]

        userdb.save_users(users)

        flash(_("Successfully updated user profile."))

        # In distributed setups with remote sites where the user can login, start the
        # user profile replication now which will redirect the user to the destination
        # page after completion. Otherwise directly open up the destination page.
        if user.authorized_login_sites():
            back_url = "user_profile_replicate.py?back=user_profile.py"
        else:
            back_url = "user_profile.py"

        # Ensure theme changes are applied without additional user interaction
        html.reload_whole_page(back_url)
        html.footer()

        raise FinalizeRequest(code=200)
Beispiel #2
0
    def _get_event_stats_query(self, context_filters):
        # In case the user is not allowed to see unrelated events
        ec_filters = ""
        if not user.may("mkeventd.seeall") and not user.may("mkeventd.seeunrelated"):
            ec_filters = "Filter: event_contact_groups != \nFilter: host_name != \nOr: 2\n"

        event_query = (
            # "Events" column
            "GET eventconsoleevents\n"
            "Stats: event_phase = open\n"
            "Stats: event_phase = ack\n"
            "StatsOr: 2\n"
            # "Problems" column
            "Stats: event_phase = open\n"
            "Stats: event_phase = ack\n"
            "StatsOr: 2\n"
            "Stats: event_state != 0\n"
            "StatsAnd: 2\n"
            # "Unhandled" column
            "Stats: event_phase = open\n"
            "Stats: event_state != 0\n"
            "Stats: event_host_in_downtime != 1\n"
            "StatsAnd: 3\n" + ec_filters + context_filters
        )

        # Do not mark the site as dead in case the Event Console is not available.
        return livestatus.Query(
            event_query,
            suppress_exceptions=(
                livestatus.MKLivestatusTableNotFoundError,
                livestatus.MKLivestatusBadGatewayError,
            ),
        )
Beispiel #3
0
 def __init__(self, url_checker: URLChecker[T]) -> None:
     self._category_permissions = {
         "global_settings": user.may("wato.global") or user.may("wato.seeall"),
         "folders": user.may("wato.hosts"),
         "hosts": user.may("wato.hosts"),
         "event_console": user.may("mkeventd.edit") or user.may("wato.seeall"),
         "event_console_settings": user.may("mkeventd.config") or user.may("wato.seeall"),
         "logfile_pattern_analyzer": user.may("wato.pattern_editor") or user.may("wato.seeall"),
     }
     self._url_checker = url_checker
Beispiel #4
0
    def _may_activate_changes(self) -> bool:
        if not user.may("wato.activate"):
            return False

        if not user.may("wato.activateforeign") and self._has_foreign_changes_on_any_site():
            return False

        if read_only.is_enabled() and not read_only.may_override():
            return False

        return True
Beispiel #5
0
    def _activation_form(self):
        if not user.may("wato.activate"):
            html.show_warning(
                _("You are not permitted to activate configuration changes."))
            return

        if not self._changes:
            return

        if not user.may("wato.activateforeign"
                        ) and self._has_foreign_changes_on_any_site():
            html.show_warning(
                _("Sorry, you are not allowed to activate changes of other users."
                  ))
            return

        valuespec = _vs_activation(self.title(), self.has_foreign_changes())

        html.begin_form("activate", method="POST", action="")
        html.hidden_field("activate_until",
                          self._get_last_change_id(),
                          id_="activate_until")

        if valuespec:
            title = valuespec.title()
            assert title is not None
            forms.header(title)
            valuespec.render_input("activate", self._value)
            valuespec.set_focus("activate")
            html.help(valuespec.help())

        if self.has_foreign_changes():
            if user.may("wato.activateforeign"):
                html.show_warning(
                    _("There are some changes made by your colleagues that you will "
                      "activate if you proceed. You need to enable the checkbox above "
                      "to confirm the activation of these changes."))
            else:
                html.show_warning(
                    _("There are some changes made by your colleagues that you can not "
                      "activate because you are not permitted to. You can only activate "
                      "the changes on the sites that are not affected by these changes. "
                      "<br>"
                      "If you need to activate your changes on all sites, please contact "
                      "a permitted user to do it for you."))

        forms.end()
        html.hidden_field("selection_id", weblib.selection_id())
        html.hidden_fields()
        html.end_form()
        init_rowselect(self.name())
Beispiel #6
0
    def __init__(self) -> None:
        super().__init__()

        if not user.id:
            raise MKUserError(None, _("Not logged in."))

        if not user.may("general.change_password") and not user.may(
                "general.edit_profile"):
            raise MKAuthException(
                _("You are not allowed to edit your user profile."))

        if not active_config.wato_enabled:
            raise MKAuthException(
                _("User profiles can not be edited (WATO is disabled)."))
Beispiel #7
0
    def may_see(self):
        """Whether or not the currently logged in user is allowed to see this module"""
        if not self.enabled:
            return False

        if self.permission is None:
            return True

        if "." not in self.permission:
            permission = "wato." + self.permission
        else:
            permission = self.permission

        return user.may(permission) or user.may("wato.seeall")
Beispiel #8
0
    def _show_form(self) -> None:
        assert user.id is not None

        users = userdb.load_users()

        user_spec: Optional[UserSpec] = users.get(user.id)
        if user_spec is None:
            html.show_warning(_("Sorry, your user account does not exist."))
            html.footer()
            return

        html.begin_form("profile", method="POST")
        html.prevent_password_auto_completion()
        html.open_div(class_="wato")
        forms.header(_("Personal settings"))

        forms.section(_("Username"), simple=True)
        html.write_text(user_spec.get("user_id", user.id))

        forms.section(_("Full name"), simple=True)
        html.write_text(user_spec.get("alias", ""))

        select_language(user_spec)

        # Let the user configure how he wants to be notified
        rulebased_notifications = rulebased_notifications_enabled()
        if (not rulebased_notifications
                and user.may("general.edit_notifications")
                and user_spec.get("notifications_enabled")):
            forms.section(_("Notifications"))
            html.help(
                _("Here you can configure how you want to be notified about host and service problems and "
                  "other monitoring events."))
            get_vs_flexible_notifications().render_input(
                "notification_method", user_spec.get("notification_method"))

        if user.may("general.edit_user_attributes"):
            custom_user_attr_topics = get_user_attributes_by_topic()
            _show_custom_user_attr(user_spec,
                                   custom_user_attr_topics.get("personal", []))
            forms.header(_("User interface settings"))
            _show_custom_user_attr(
                user_spec, custom_user_attr_topics.get("interface", []))

        forms.end()
        html.close_div()
        html.hidden_fields()
        html.end_form()
        html.footer()
Beispiel #9
0
    def may_delete(self):
        if not self.is_deletable():
            return False

        if not self.is_stoppable() and self.is_active():
            return False

        if not user.may("background_jobs.delete_jobs"):
            return False

        if self.is_foreign(
        ) and not user.may("background_jobs.delete_foreign_jobs"):
            return False

        return True
Beispiel #10
0
def verify_permission(host_name: HostName,
                      site: Optional[livestatus.SiteId]) -> None:
    if user.may("general.see_all"):
        return

    query = "GET hosts\nFilter: host_name = %s\nStats: state >= 0%s" % (
        livestatus.lqencode(host_name),
        "\nAuthUser: %s" % livestatus.lqencode(user.id) if user.id else "",
    )

    if site:
        sites.live().set_only_sites([site])

    try:
        result = sites.live().query_summed_stats(query, "ColumnHeaders: off\n")
    except livestatus.MKLivestatusNotFoundError:
        raise MKAuthException(
            _("No such inventory tree of host %s."
              " You may also have no access to this host.") % host_name)
    finally:
        if site:
            sites.live().set_only_sites()

    if result[0] == 0:
        raise MKAuthException(
            _("You are not allowed to access the host %s.") % host_name)
Beispiel #11
0
    def _call_auth() -> Response:
        with login.authenticate(request) as authenticated:
            if not authenticated:
                return _handle_not_authenticated()

            # When displaying the crash report message, the user authentication context
            # has already been left. We need to preserve this information to be able to
            # show the correct message for the current user.
            g.may_see_crash_reports = user.may("general.see_crash_reports")

            # This may raise an exception with error messages, which will then be displayed to the user.
            _ensure_general_access()

            # Initialize the multisite cmk.gui.i18n. This will be replaced by
            # language settings stored in the user profile after the user
            # has been initialized
            _localize_request()

            # Update the UI theme with the attribute configured by the user.
            # Returns None on first load
            assert user.id is not None
            theme.set(
                cmk.gui.userdb.load_custom_attr(user_id=user.id,
                                                key="ui_theme",
                                                parser=lambda x: x))

            func()

            return response
Beispiel #12
0
    def _show_sidebar(self) -> None:
        if not user.may("general.see_sidebar"):
            html.div("", id_="check_mk_navigation")
            return

        user_config = UserSidebarConfig(user, active_config.sidebar)

        html.open_div(
            id_="check_mk_navigation",
            class_="min"
            if user.get_attribute("nav_hide_icons_title") else None,
        )
        self._show_sidebar_head()
        html.close_div()

        assert user.id is not None
        sidebar_position = cmk.gui.userdb.load_custom_attr(
            user.id, "ui_sidebar_position", lambda x: None
            if x == "None" else "left")
        html.open_div(id_="check_mk_sidebar", class_=[sidebar_position])

        self._show_snapin_bar(user_config)

        html.close_div()

        if user_config.folded:
            html.final_javascript("cmk.sidebar.fold_sidebar();")
Beispiel #13
0
def page_message():
    if not user.may("general.message"):
        raise MKAuthException(_("You are not allowed to use the message module."))

    title = _("Send user message")
    breadcrumb = make_simple_page_breadcrumb(mega_menu_registry.menu_setup(), title)
    menu = _page_menu(breadcrumb)
    html.header(title, breadcrumb, menu)

    vs_message = _vs_message()

    if transactions.check_transaction():
        try:
            msg = vs_message.from_html_vars("_message")
            vs_message.validate_value(msg, "_message")
            _process_message_message(msg)
        except MKUserError as e:
            html.user_error(e)

    html.begin_form("message", method="POST")
    vs_message.render_input_as_form("_message", {})

    html.hidden_fields()
    html.end_form()
    html.footer()
Beispiel #14
0
def ajax_openclose() -> None:
    response.set_content_type("application/json")
    if not user.may("general.configure_sidebar"):
        return None

    snapin_id = request.var("name")
    if snapin_id is None:
        return None

    state = request.var("state")
    if state not in [
            SnapinVisibility.OPEN.value, SnapinVisibility.CLOSED.value, "off"
    ]:
        raise MKUserError("state", "Invalid state: %s" % state)

    user_config = UserSidebarConfig(user, active_config.sidebar)

    try:
        snapin = user_config.get_snapin(snapin_id)
    except KeyError:
        return None

    if state == "off":
        user_config.remove_snapin(snapin)
    else:
        snapin.visible = SnapinVisibility(state)

    user_config.save()
Beispiel #15
0
    def page(self):
        if not user.may("general.configure_sidebar"):
            raise MKGeneralException(
                _("You are not allowed to change the sidebar."))

        addname = request.var("name")

        if addname is None or addname not in snapin_registry:
            raise MKUserError(None, _("Invalid sidebar element %s") % addname)

        if addname in _used_snapins():
            raise MKUserError(None,
                              _("Element %s is already enabled") % addname)

        user_config = UserSidebarConfig(user, active_config.sidebar)
        snapin = UserSidebarSnapin.from_snapin_type_id(addname)
        user_config.add_snapin(snapin)
        user_config.save()

        with output_funnel.plugged():
            try:
                url = SidebarRenderer().render_snapin(snapin)
            finally:
                snapin_code = output_funnel.drain()

        return {
            "name": addname,
            "url": url,
            "content": snapin_code,
            "refresh": snapin.snapin_type.refresh_regularly(),
            "restart": snapin.snapin_type.refresh_on_restart(),
        }
Beispiel #16
0
def _process_icons(
    what: IconObjectType,
    row: Row,
    tags: List[TagID],
    custom_vars: Dict[str, str],
    toplevel: bool,
    user_icon_ids: List[str],
) -> List[ABCIconEntry]:
    icons: List[ABCIconEntry] = []
    for icon_id, icon in get_multisite_icons().items():
        if icon.toplevel() != toplevel:
            continue

        if icon.type() == "custom_icon" and icon_id not in user_icon_ids:
            continue

        if not user.may("icons_and_actions.%s" % icon_id):
            continue

        try:
            for result in _process_icon(what, row, tags, custom_vars, icon_id, icon):
                icons.append(result)
        except Exception:
            icons.append(
                IconEntry(
                    sort_index=icon.sort_index(),
                    icon_name="alert",
                    title=_("Exception in icon '%s': %s")
                    % (
                        icon_id,
                        traceback.format_exc(),
                    ),
                )
            )
    return icons
Beispiel #17
0
 def _page_menu_entries_setup(self) -> Iterator[PageMenuEntry]:
     if user.may("wato.sites"):
         yield PageMenuEntry(
             title=_("View changes"),
             icon_name="activate",
             item=make_simple_link(folder_preserving_link([("mode", "changelog")])),
         )
Beispiel #18
0
def move_snapin() -> None:
    response.set_content_type("application/json")
    if not user.may("general.configure_sidebar"):
        return None

    snapin_id = request.var("name")
    if snapin_id is None:
        return None

    user_config = UserSidebarConfig(user, active_config.sidebar)

    try:
        snapin = user_config.get_snapin(snapin_id)
    except KeyError:
        return None

    before_id = request.var("before")
    before_snapin: Optional[UserSidebarSnapin] = None
    if before_id:
        try:
            before_snapin = user_config.get_snapin(before_id)
        except KeyError:
            pass

    user_config.move_snapin_before(snapin, before_snapin)
    user_config.save()
Beispiel #19
0
def page_add_snapin() -> None:
    if not user.may("general.configure_sidebar"):
        raise MKGeneralException(
            _("You are not allowed to change the sidebar."))

    title = _("Add sidebar element")
    breadcrumb = make_simple_page_breadcrumb(
        mega_menu_registry.menu_customize(), title)
    html.header(title, breadcrumb, _add_snapins_page_menu(breadcrumb))

    used_snapins = _used_snapins()

    html.open_div(class_=["add_snapin"])
    for name, snapin_class in sorted(snapin_registry.items()):
        if name in used_snapins:
            continue
        if not snapin_class.may_see():
            continue  # not allowed for this user

        html.open_div(
            class_="snapinadder",
            onmouseover="this.style.cursor='pointer';",
            onclick="window.top.cmk.sidebar.add_snapin('%s')" % name,
        )

        html.open_div(class_=["snapin_preview"])
        html.div("", class_=["clickshield"])
        SidebarRenderer().render_snapin(
            UserSidebarSnapin.from_snapin_type_id(name))
        html.close_div()
        html.div(snapin_class.description(), class_=["description"])
        html.close_div()

    html.close_div()
    html.footer()
Beispiel #20
0
    def _create_status_box(
        self,
        site_ids: Collection[livestatus.SiteId],
        css_class: str,
        site_status: str,
    ):
        html.open_div(class_="spacertop")
        html.open_div(class_=css_class)
        message_template = ungettext("%d site is %s.", "%d sites are %s.", len(site_ids))
        message = message_template % (len(site_ids), site_status)
        tooltip_template = ungettext(
            "Associated hosts, services and events are not included "
            "in the Tactical Overview. The %s site is %s.",
            "Associated hosts, services and events are not included "
            "in the Tactical Overview. The %s sites are %s.",
            len(site_ids),
        )
        tooltip = tooltip_template % (site_status, ", ".join(site_ids))

        if user.may("wato.sites"):
            url = makeuri_contextless(request, [("mode", "sites")], filename="wato.py")
            html.icon_button(url, tooltip, "sites", target="main")
            html.a(message, target="main", href=url)
        else:
            html.icon("sites", tooltip)
            html.write_text(message)
        html.close_div()
        html.close_div()
Beispiel #21
0
def _ensure_general_access() -> None:
    if user.may("general.use"):
        return

    reason = [
        _("You are not authorized to use the Check_MK GUI. Sorry. "
          "You are logged in as <b>%s</b>.") % user.id
    ]

    if user.role_ids:
        reason.append(
            _("Your roles are <b>%s</b>.") % ", ".join(user.role_ids))
    else:
        reason.append(_("<b>You do not have any roles.</b>"))

    reason.append(
        _("If you think this is an error, please ask your administrator "
          "to check the permissions configuration."))

    if login.auth_type == "cookie":  # type: ignore[has-type]
        reason.append(
            _("<p>You have been logged out. Please reload the page "
              "to re-authenticate.</p>"))
        login.del_auth_cookie()

    raise MKAuthException(" ".join(reason))
Beispiel #22
0
def _show_command_form(datasource: ABCDataSource, rows: Rows) -> None:
    what = datasource.infos[0]
    html.javascript(
        """
    $(document).ready(function() {
      $('.command_group').has('x').trigger('expand');
      $('x').children().css('background-color', '#f84');
    });
    """
    )

    one_shown = False
    html.open_div(**{"data-role": "collapsible-set"})
    for command_class in command_registry.values():
        command = command_class()
        if what in command.tables and user.may(command.permission.name):
            html.open_div(class_=["command_group"], **{"data-role": "collapsible"})
            html.h3(command.title)
            html.open_p()

            html.begin_form("actions")
            html.hidden_field("_do_actions", "yes")
            html.hidden_field("actions", "yes")
            command.render(what)
            html.hidden_fields()
            html.end_form()

            html.close_p()
            html.close_div()
            one_shown = True
    html.close_div()
    if not one_shown:
        html.write_text(_("No commands are possible in this view"))
Beispiel #23
0
def render_wato(mini):
    if not active_config.wato_enabled:
        html.write_text(_("Setup is disabled."))
        return False
    if not user.may("wato.use"):
        html.write_text(_("You are not allowed to use the setup."))
        return False

    menu = get_wato_menu_items()

    if mini:
        for topic in menu:
            for item in topic.items:
                html.icon_button(
                    url=item.url,
                    class_="show_more_mode" if item.is_show_more else None,
                    title=item.title,
                    icon=item.icon or "wato",
                    target="main",
                )
    else:
        show_topic_menu(treename="wato", menu=menu, show_item_icons=True)

    pending_info = watolib.get_pending_changes_info()
    if pending_info:
        footnotelinks([(pending_info, "wato.py?mode=changelog")])
        html.div("", class_="clear")
Beispiel #24
0
def _page_menu_entry_acknowledge(
    site: Optional[SiteId] = None,
    host_name: Optional[HostName] = None,
    int_filename: Optional[str] = None,
) -> Iterator[PageMenuEntry]:
    if not user.may("general.act") or (host_name
                                       and not may_see(site, host_name)):
        return

    if int_filename:
        label = _("Clear log")
    else:
        label = _("Clear logs")

    urivars: HTTPVariables = [("_ack", "1")]
    if int_filename:
        urivars.append(("file", form_file_to_ext(int_filename)))

    ack_msg = _get_ack_msg(
        host_name,
        form_file_to_ext(int_filename) if int_filename else None)

    yield PageMenuEntry(
        title=label,
        icon_name="delete",
        item=make_simple_link(
            make_confirm_link(
                url=makeactionuri(request, transactions, urivars),
                message=_("Do you really want to acknowledge %s "
                          "by <b>deleting</b> all stored messages?") % ack_msg,
            )),
        is_shortcut=True,
        is_suggested=True,
    )
Beispiel #25
0
    def _page_menu_entries_export(self) -> Iterator[PageMenuEntry]:
        if not self._log_exists():
            return

        if not user.may("wato.auditlog"):
            return

        if not user.may("wato.edit"):
            return

        if not user.may("general.csv_export"):
            return

        yield PageMenuEntry(
            title=_("Export CSV"),
            icon_name="download_csv",
            item=make_simple_link(makeactionuri(request, transactions, [("_action", "csv")])),
        )
Beispiel #26
0
 def permissions_for_items(self) -> Mapping[str, Callable[[str], bool]]:
     return {
         "rules": self._permissions_rule,
         "hosts": lambda url: (
             any(user.may(perm) for perm in ("wato.all_folders", "wato.see_all_folders"))
             or self._permissions_url(url)
         ),
         "setup": self._permissions_url,
     }
Beispiel #27
0
    def _stats_query(cls) -> str:
        # In case the user is not allowed to see unrelated events
        ec_filters = ""
        if not user.may("mkeventd.seeall") and not user.may(
                "mkeventd.seeunrelated"):
            ec_filters = "\n".join([
                "Filter: event_contact_groups != ",
                "Filter: host_name != ",
                "Or: 2",
            ])

        return ("\n".join([
            "GET eventconsoleevents",
            "Stats: event_state = 0",  # ok
            "Stats: event_state = 1",  # warning
            "Stats: event_state = 3",  # unknown
            "Stats: event_state = 2",  # critical
        ]) + ec_filters)
Beispiel #28
0
def do_log_ack(site, host_name, file_name):
    sites.live().set_auth_domain("action")

    logs_to_ack = []
    if not host_name and not file_name:  # all logs on all hosts
        for this_site, this_host, logs in all_logs():
            for int_filename in logs:
                file_display = form_file_to_ext(int_filename)
                logs_to_ack.append(
                    (this_site, this_host, int_filename, file_display))

    elif host_name and not file_name:  # all logs on one host
        for int_filename in logfiles_of_host(site, host_name):
            file_display = form_file_to_ext(int_filename)
            logs_to_ack.append((site, host_name, int_filename, file_display))

    elif host_name and file_name:  # one log on one host
        int_filename = form_file_to_int(file_name)
        logs_to_ack = [(site, host_name, int_filename,
                        form_file_to_ext(int_filename))]

    else:
        for this_site, this_host, logs in all_logs():
            file_display = form_file_to_ext(file_name)
            if file_name in logs:
                logs_to_ack.append(
                    (this_site, this_host, file_name, file_display))

    ack_msg = _get_ack_msg(host_name, file_name)
    ack = request.var("_ack")

    if not user.may("general.act"):
        html.h1(_("Permission denied"), class_=["error"])
        html.div(_("You are not allowed to acknowledge %s") % ack_msg,
                 class_=["error"])
        html.footer()
        return

    # filter invalid values
    if ack != "1":
        raise MKUserError("_ack", _("Invalid value for ack parameter."))

    for this_site, this_host, int_filename, display_name in logs_to_ack:
        try:
            acknowledge_logfile(this_site, this_host, int_filename,
                                display_name)
        except Exception as e:
            html.show_error(
                _("The log file <tt>%s</tt> of host <tt>%s</tt> could not be deleted: %s."
                  ) % (display_name, this_host, e))
            html.footer()
            return

    html.show_message("<b>%s</b><p>%s</p>" %
                      (_("Acknowledged %s") % ack_msg,
                       _("Acknowledged all messages in %s.") % ack_msg))
    html.footer()
Beispiel #29
0
    def show(self):
        show_topic_menu(treename="views", menu=get_view_menu_items())

        links = []
        if user.may("general.edit_views"):
            if active_config.debug:
                links.append((_("Export"), "export_views.py"))
            links.append((_("Edit"), "edit_views.py"))
            footnotelinks(links)
Beispiel #30
0
    def _page_menu_entries_setup(self) -> Iterator[PageMenuEntry]:
        if user.may("wato.sites"):
            yield PageMenuEntry(
                title=_("Sites"),
                icon_name="sites",
                item=make_simple_link(
                    makeuri_contextless(
                        request,
                        [("mode", "sites")],
                    )),
            )

        if user.may("wato.auditlog"):
            yield PageMenuEntry(
                title=_("Audit log"),
                icon_name="auditlog",
                item=make_simple_link(
                    folder_preserving_link([("mode", "auditlog")])),
            )