Beispiel #1
0
 def _get_timeperiod(self, name):
     try:
         return self._timeperiods[name]
     except KeyError:
         raise MKUserError(None, _("This timeperiod does not exist."))
Beispiel #2
0
    def page_list(cls):
        cls.load()

        # custom_columns = []
        # render_custom_buttons = None
        # render_custom_columns = None
        # render_custom_context_buttons = None
        # check_deletable_handler = None

        cls.need_overriding_permission("edit")

        html.header(cls.phrase("title_plural"))
        html.begin_context_buttons()
        html.context_button(cls.phrase("new"), cls.create_url(), "new_" + cls.type_name())

        # TODO: Remove this legacy code as soon as views, dashboards and reports have been
        # moved to pagetypes.py
        html.context_button(_("Views"), "edit_views.py", "view")
        html.context_button(_("Dashboards"), "edit_dashboards.py", "dashboard")

        def has_reporting():
            try:
                # The suppression below is OK, we just want to check if the module is there.
                import cmk.gui.cee.reporting as _dummy  # noqa: F401 # pylint: disable=import-outside-toplevel
                return True
            except ImportError:
                return False

        if has_reporting():
            html.context_button(_("Reports"), "edit_reports.py", "report")

        # ## if render_custom_context_buttons:
        # ##     render_custom_context_buttons()

        for other_type_name, other_pagetype in page_types.items():
            if cls.type_name() != other_type_name:
                html.context_button(
                    other_pagetype.phrase("title_plural").title(), '%ss.py' % other_type_name,
                    other_type_name)
        html.end_context_buttons()

        # Deletion
        delname = html.request.var("_delete")
        if delname and html.transaction_valid():
            owner = UserId(html.request.get_unicode_input_mandatory('_owner', config.user.id))

            try:
                instance = cls.instance((owner, delname))
            except KeyError:
                raise MKUserError(
                    "_delete",
                    _("The %s you are trying to delete "
                      "does not exist.") % cls.phrase("title"))

            if not instance.may_delete():
                raise MKUserError("_delete", _("You are not permitted to perform this action."))

            try:
                if owner != config.user.id:
                    owned_by = _(" (owned by %s)") % owner
                else:
                    owned_by = ""
                c = html.confirm(
                    _("Please confirm the deletion of \"%s\"%s.") % (instance.title(), owned_by))
                if c:
                    cls.remove_instance((owner, delname))
                    cls.save_user_instances(owner)
                    html.reload_sidebar()
                elif c is False:
                    html.footer()
                    return
            except MKUserError as e:
                html.user_error(e)

        # Bulk delete
        if html.request.var("_bulk_delete_my") and html.transaction_valid():
            if cls._bulk_delete_after_confirm("my") is False:
                html.footer()
                return

        elif html.request.var("_bulk_delete_foreign") and html.transaction_valid():
            if cls._bulk_delete_after_confirm("foreign") is False:
                html.footer()
                return

        my_instances, foreign_instances, builtin_instances = cls.get_instances()
        for what, title, instances in [
            ("my", _('Customized'), my_instances),
            ("foreign", _('Owned by other users'), foreign_instances),
            ("builtin", _('Builtin'), builtin_instances),
        ]:
            if not instances:
                continue

            html.open_h3()
            html.write(title)
            html.close_h3()

            if what != "builtin":
                html.begin_form("bulk_delete_%s" % what, method="POST")

            with table_element(limit=None) as table:
                for instance in instances:
                    table.row()

                    if what != "builtin" and instance.may_delete():
                        table.cell(html.render_input(
                            "_toggle_group",
                            type_="button",
                            class_="checkgroup",
                            onclick="cmk.selection.toggle_all_rows(this.form);",
                            value='X'),
                                   sortable=False,
                                   css="checkbox")
                        html.checkbox("_c_%s+%s+%s" % (what, instance.owner(), instance.name()))

                    # Actions
                    table.cell(_('Actions'), css='buttons visuals')

                    # View
                    if isinstance(instance, PageRenderer):
                        html.icon_button(instance.page_url(), _("View"), "new_" + cls.type_name())

                    # Clone / Customize
                    html.icon_button(instance.clone_url(), _("Create a customized copy of this"),
                                     "clone")

                    # Delete
                    if instance.may_delete():
                        html.icon_button(instance.delete_url(), _("Delete!"), "delete")

                    # Edit
                    if instance.may_edit():
                        html.icon_button(instance.edit_url(), _("Edit"), "edit")

                    cls.custom_list_buttons(instance)

                    # Internal ID of instance (we call that 'name')
                    table.cell(_('ID'), instance.name(), css="narrow")

                    # Title
                    table.cell(_('Title'))
                    html.write_text(instance.render_title())
                    html.help(_u(instance.description()))

                    # Custom columns specific to that page type
                    instance.render_extra_columns(table)

                    # ## for title, renderer in custom_columns:
                    # ##     table.cell(title, renderer(visual))

                    # Owner
                    if instance.is_builtin():
                        ownertxt = html.render_i(_("builtin"))
                    else:
                        ownertxt = instance.owner()
                    table.cell(_('Owner'), ownertxt)
                    table.cell(_('Public'), _("yes") if instance.is_public() else _("no"))
                    table.cell(_('Hidden'), _("yes") if instance.is_hidden() else _("no"))

                    # FIXME: WTF?!?
                    # TODO: Haeeh? Another custom columns
                    # ## if render_custom_columns:
                    # ##     render_custom_columns(visual_name, visual)

            if what != "builtin":
                html.button("_bulk_delete_%s" % what,
                            _("Bulk delete"),
                            "submit",
                            style="margin-top:10px")
                html.hidden_fields()
                html.end_form()

        html.footer()
        return
Beispiel #3
0
 def _validate_value(self, value: DropdownChoiceValue,
                     varprefix: str) -> None:
     if value is not None and not self._regex.match(ensure_str(value)):
         raise MKUserError(varprefix, self._regex_error)
Beispiel #4
0
    def action(self, cmdtag, spec, row, row_index, num_rows):
        down_from = int(time.time())
        down_to = None

        if self._has_recurring_downtimes() and html.get_checkbox("_down_do_recur"):
            from cmk.gui.cee.plugins.wato.cmc import recurring_downtimes_types  # pylint: disable=no-name-in-module
            recurring_type = int(html.request.var("_down_recurring"))
            title_start = _("schedule a periodic downtime every %s") % recurring_downtimes_types(
            )[recurring_type]
        else:
            title_start = _("schedule an immediate downtime")

        rangebtns = (varname for varname, _value in html.request.itervars(prefix="_downrange"))

        def resolve_end(name):
            now = time.localtime(down_from)
            if name == "next_day":
                return time.mktime((now.tm_year, now.tm_mon, now.tm_mday, 23, 59, 59, 0, 0, now.tm_isdst)) + 1, \
                    _("<b>%s until 24:00:00</b> on") % title_start
            elif name == "next_week":
                wday = now.tm_wday
                days_plus = 6 - wday
                res = time.mktime(
                    (now.tm_year, now.tm_mon, now.tm_mday, 23, 59, 59, 0, 0, now.tm_isdst)) + 1
                res += days_plus * 24 * 3600
                return res, _("<b>%s until sunday night</b> on") % title_start
            elif name == "next_month":
                new_month = now.tm_mon + 1
                if new_month == 13:
                    new_year = now.tm_year + 1
                    new_month = 1
                else:
                    new_year = now.tm_year
                return time.mktime((new_year, new_month, 1, 0, 0, 0, 0, 0, now.tm_isdst)), \
                    _("<b>%s until end of month</b> on") % title_start
            elif name == "next_year":
                return time.mktime((now.tm_year, 12, 31, 23, 59, 59, 0, 0, now.tm_isdst)) + 1, \
                    _("<b>%s until end of %d</b> on") % (title_start, now.tm_year)
            else:
                duration = int(name)
                return down_from + duration, \
                    _("<b>%s of %s length</b> on") %\
                    (title_start, self._get_duration_human_readable(duration))

        try:
            rangebtn = next(rangebtns)
        except StopIteration:
            rangebtn = None

        if rangebtn:
            _btnname, end = rangebtn.split("__", 1)
            down_to, title = resolve_end(end)
        elif html.request.var("_down_from_now"):
            try:
                minutes = int(html.request.var("_down_minutes", ""))
            except ValueError:
                minutes = 0

            if minutes <= 0:
                raise MKUserError("_down_minutes", _("Please enter a positive number of minutes."))

            down_to = time.time() + minutes * 60
            title = _("<b>%s for the next %d minutes</b> on") % (title_start, minutes)

        elif html.request.var("_down_adhoc"):
            minutes = config.adhoc_downtime.get("duration", 0)
            down_to = time.time() + minutes * 60
            title = _("<b>%s for the next %d minutes</b> on") % (title_start, minutes)

        elif html.request.var("_down_custom"):
            down_from = html.get_datetime_input("_down_from")
            down_to = html.get_datetime_input("_down_to")
            if down_to < time.time():
                raise MKUserError(
                    "_down_to",
                    _("You cannot set a downtime that ends in the past. "
                      "This incident will be reported."))

            if down_to < down_from:
                raise MKUserError("_down_to", _("Your end date is before your start date."))

            title = _("<b>schedule a downtime from %s to %s</b> on ") % (time.asctime(
                time.localtime(down_from)), time.asctime(time.localtime(down_to)))

        elif html.request.var("_down_remove") and config.user.may("action.remove_all_downtimes"):
            if html.request.var("_on_hosts"):
                raise MKUserError(
                    "_on_hosts",
                    _("The checkbox for setting host downtimes does not work when removing downtimes."
                     ))

            downtime_ids = []
            if cmdtag == "HOST":
                prefix = "host_"
            else:
                prefix = "service_"
            for id_ in row[prefix + "downtimes"]:
                if id_ != "":
                    downtime_ids.append(int(id_))

            commands = []
            for dtid in downtime_ids:
                commands.append("DEL_%s_DOWNTIME;%d\n" % (cmdtag, dtid))
            title = _("<b>remove all scheduled downtimes</b> of ")
            return commands, title

        if down_to:
            if html.request.var("_down_adhoc"):
                comment = config.adhoc_downtime.get("comment", "")
            else:
                comment = html.get_unicode_input("_down_comment")
            if not comment:
                raise MKUserError("_down_comment",
                                  _("You need to supply a comment for your downtime."))
            if html.request.var("_down_flexible"):
                fixed = 0
                duration = html.get_time_input("_down_duration", _("the duration"))
            else:
                fixed = 1
                duration = 0

            if html.get_checkbox("_down_do_recur"):
                fixed_and_recurring = recurring_type * 2 + fixed
            else:
                fixed_and_recurring = fixed

            def make_command(spec, cmdtag):
                return ("SCHEDULE_" + cmdtag + "_DOWNTIME;%s;" % spec) + ("%d;%d;%d;0;%d;%s;" % (
                    down_from,
                    down_to,
                    fixed_and_recurring,
                    duration,
                    config.user.id,
                )) + livestatus.lqencode(comment)

            if "aggr_tree" in row:  # BI mode
                commands = []
                for site, host, service in bi.find_all_leaves(row["aggr_tree"]):
                    if service:
                        spec = "%s;%s" % (host, service)
                        cmdtag = "SVC"
                    else:
                        spec = host
                        cmdtag = "HOST"
                    commands.append((site, make_command(spec, cmdtag)))
            else:
                if html.request.var("_include_childs"):  # only for hosts
                    specs = [spec] + self._get_child_hosts(
                        row["site"], [spec],
                        recurse=bool(html.request.var("_include_childs_recurse")))
                elif html.request.var("_on_hosts"):  # set on hosts instead of services
                    specs = [spec.split(";")[0]]
                    title += " the hosts of"
                    cmdtag = "HOST"
                else:
                    specs = [spec]

                commands = [make_command(spec, cmdtag) for spec in specs]

            return commands, title
Beispiel #5
0
def validate_start_url(value, varprefix):
    if not is_allowed_url(value):
        raise MKUserError(
            varprefix,
            _("The given value is not allowed. You may only configure "
              "relative URLs like <tt>dashboard.py?name=my_dashboard</tt>."))
Beispiel #6
0
 def _validate_ldap_connection_id(self, value, varprefix):
     if value in [c["id"] for c in config.user_connections]:
         raise MKUserError(
             varprefix,
             _("This ID is already used by another connection. Please choose another one."),
         )
Beispiel #7
0
    def _set(self, request):
        # Py2: This encoding here should be kept Otherwise and unicode encoded text will be written
        # into the configuration file with unknown side effects
        ruleset_name = six.ensure_str(request["ruleset_name"])

        # Future validation, currently the rule API actions are admin only, so the check is pointless
        # may_edit_ruleset(ruleset_name)

        # Check if configuration hash has changed in the meantime
        ruleset_dict = self._get_ruleset_configuration(ruleset_name)
        if "configuration_hash" in request:
            validate_config_hash(request["configuration_hash"], ruleset_dict)

        # Check permissions of new rules and rules we are going to delete
        new_ruleset = request["ruleset"]
        folders_set_ruleset = set(new_ruleset.keys())
        folders_obsolete_ruleset = set(
            ruleset_dict.keys()) - folders_set_ruleset

        for check_folders in [folders_set_ruleset, folders_obsolete_ruleset]:
            for folder_path in check_folders:
                if not watolib.Folder.folder_exists(folder_path):
                    raise MKUserError(
                        None,
                        _("Folder %s does not exist") % folder_path)
                rule_folder = watolib.Folder.folder(folder_path)
                rule_folder.need_permission("write")

        tag_to_group_map = ruleset_matcher.get_tag_to_group_map(config.tags)

        # Verify all rules
        rule_vs = watolib.Ruleset(ruleset_name,
                                  tag_to_group_map).rulespec.valuespec

        for folder_path, rules in new_ruleset.items():
            for rule in rules:
                value = rule["value"]

                try:
                    rule_vs.validate_datatype(value, "test_value")
                    rule_vs.validate_value(value, "test_value")
                except MKException as e:
                    raise MKGeneralException("ERROR: %s. Affected Rule %r" %
                                             (str(e), rule))

        # Add new rulesets
        for folder_path, rules in new_ruleset.items():
            folder = watolib.Folder.folder(folder_path)

            new_ruleset = watolib.Ruleset(ruleset_name, tag_to_group_map)
            new_ruleset.from_config(folder, rules)

            folder_rulesets = watolib.FolderRulesets(folder)
            folder_rulesets.load()
            # TODO: This add_change() call should be made by the data classes
            watolib.add_change("edit-ruleset",
                               _("Set ruleset '%s' for '%s' with %d rules") % (
                                   new_ruleset.title(),
                                   folder.title(),
                                   len(rules),
                               ),
                               sites=folder.all_site_ids())
            folder_rulesets.set(ruleset_name, new_ruleset)
            folder_rulesets.save()

        # Remove obsolete rulesets
        for folder_path in folders_obsolete_ruleset:
            folder = watolib.Folder.folder(folder_path)

            folder_rulesets = watolib.FolderRulesets(folder)
            folder_rulesets.load()
            # TODO: This add_change() call should be made by the data classes
            watolib.add_change(
                "edit-ruleset",
                _("Deleted ruleset '%s' for '%s'") % (
                    watolib.Ruleset(ruleset_name, tag_to_group_map).title(),
                    folder.title(),
                ),
                sites=folder.all_site_ids())

            new_ruleset = watolib.Ruleset(ruleset_name, tag_to_group_map)
            new_ruleset.from_config(folder, [])
            folder_rulesets.set(ruleset_name, new_ruleset)
            folder_rulesets.save()
Beispiel #8
0
 def validate_dynamic_levels(value, varprefix):
     if [v for v in value if v[0] < 0]:
         raise MKUserError(
             varprefix,
             _("You need to specify levels "
               "of at least 0 bytes."))
Beispiel #9
0
def do_log_ack(site, host_name, file_name):
    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))
        ack_msg = _('all logfiles on all hosts')

    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))
        ack_msg = _('all logfiles of host %s') % html.render_text(host_name)

    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))]
        ack_msg = html.render_text(_('the log file %s on host %s') % (file_name, host_name))

    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 = html.render_text(_('log file %s on all hosts') % file_name)

    html.header(_("Acknowledge %s") % ack_msg)

    html.begin_context_buttons()
    button_all_logfiles()
    if host_name:
        html.context_button(_("All Logfiles of Host"), html.makeuri([('file', '')]))
    if host_name and file_name:
        html.context_button(_("Back to Logfile"), html.makeuri([]))
    html.end_context_buttons()

    ack = html.request.var('_ack')
    if not html.confirm(
            _("Do you really want to acknowledge %s by <b>deleting</b> all stored messages?") %
            ack_msg):
        html.footer()
        return

    if not config.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.message('<b>%s</b><p>%s</p>' %
                 (_('Acknowledged %s') % ack_msg, _('Acknowledged all messages in %s.') % ack_msg))
    html.footer()
Beispiel #10
0
def _validate_user_attributes(all_users,
                              user_id,
                              user_attrs,
                              is_new_user=True):
    # Check user_id
    if is_new_user:
        if user_id in all_users:
            raise MKUserError(
                "user_id",
                _("This username is already being used by another user."))
        vs_user_id = UserID(allow_empty=False)
        vs_user_id.validate_value(user_id, "user_id")
    else:
        if user_id not in all_users:
            raise MKUserError(
                None, _("The user you are trying to edit does not exist."))

    # Full name
    alias = user_attrs.get("alias")
    if not alias:
        raise MKUserError(
            "alias",
            _("Please specify a full name or descriptive alias for the user."))

    # Locking
    locked = user_attrs.get("locked")
    if user_id == config.user.id and locked:
        raise MKUserError("locked", _("You cannot lock your own account!"))

    # Authentication: Password or Secret
    if "automation_secret" in user_attrs:
        secret = user_attrs["automation_secret"]
        if len(secret) < 10:
            raise MKUserError(
                'secret',
                _("Please specify a secret of at least 10 characters length."))
    else:
        password = user_attrs.get("password")
        if password:
            verify_password_policy(password)

    # Email
    email = user_attrs.get("email")
    vs_email = EmailAddressUnicode()
    vs_email.validate_value(email, "email")

    # Idle timeout
    idle_timeout = user_attrs.get("idle_timeout")
    vs_user_idle_timeout = get_vs_user_idle_timeout()
    vs_user_idle_timeout.validate_value(idle_timeout, "idle_timeout")

    # Notification settings are only active if we do *not* have rule based notifications!
    rulebased_notifications = load_configuration_settings().get(
        "enable_rulebased_notifications")
    if not rulebased_notifications:
        # Notifications
        notifications_enabled = user_attrs.get("notification_enabled")

        # Check if user can receive notifications
        if notifications_enabled:
            if not email:
                raise MKUserError(
                    "email",
                    _('You have enabled the notifications but missed to configure a '
                      'Email address. You need to configure your mail address in order '
                      'to be able to receive emails.'))

            contactgroups = user_attrs.get("contactgroups")
            if not contactgroups:
                raise MKUserError(
                    "notifications_enabled",
                    _('You have enabled the notifications but missed to make the '
                      'user member of at least one contact group. You need to make '
                      'the user member of a contact group which has hosts assigned '
                      'in order to be able to receive emails.'))

            roles = user_attrs.get("roles")
            if not roles:
                raise MKUserError(
                    "role_user",
                    _("Your user has no roles. Please assign at least one role."
                      ))

        notification_method = user_attrs.get("notification_method")
        get_vs_flexible_notifications().validate_value(notification_method,
                                                       "notification_method")
    else:
        fallback_contact = user_attrs.get("fallback_contact")
        if fallback_contact and not email:
            raise MKUserError(
                "email",
                _("You have enabled the fallback notifications but missed to configure an "
                  "email address. You need to configure your mail address in order "
                  "to be able to receive fallback notifications."))

    # Custom user attributes
    for name, attr in userdb.get_user_attributes():
        value = user_attrs.get(name)
        attr.valuespec().validate_value(value, "ua_" + name)
Beispiel #11
0
 def validate_only_services(value, varprefix):
     for s in value:
         if s and s[0] != '!':
             return
     raise MKUserError(varprefix + "_0",
                       _("The list of services will never match"))
Beispiel #12
0
def _wato_page_handler(current_mode: str,
                       mode_permissions: Optional[List[PermissionName]],
                       mode_class: Type[WatoMode]) -> None:
    # Check general permission for this mode
    if mode_permissions is not None and not user.may("wato.seeall"):
        _ensure_mode_permissions(mode_permissions)

    mode = mode_class()

    # Do actions (might switch mode)
    if transactions.is_transaction():
        try:
            user.need_permission("wato.edit")

            # Even if the user has seen this mode because auf "seeall",
            # he needs an explicit access permission for doing changes:
            if user.may("wato.seeall"):
                if mode_permissions:
                    _ensure_mode_permissions(mode_permissions)

            if (cmk.gui.watolib.read_only.is_enabled()
                    and not cmk.gui.watolib.read_only.may_override()):
                raise MKUserError(None, cmk.gui.watolib.read_only.message())

            result = mode.action()
            if isinstance(result, (tuple, str, bool)):
                raise MKGeneralException(
                    f'WatoMode "{current_mode}" returns unsupported return value: {result!r}'
                )

            # We assume something has been modified and increase the config generation ID by one.
            update_config_generation()

            if config.wato_use_git:
                do_git_commit()

            # Handle two cases:
            # a) Don't render the page content after action
            #    (a confirm dialog is displayed by the action, or a non-HTML content was sent)
            # b) Redirect to another page
            if isinstance(result, FinalizeRequest):
                raise result

        except MKUserError as e:
            user_errors.add(e)

        except MKAuthException as e:
            user_errors.add(MKUserError(None, e.args[0]))

    breadcrumb = make_main_menu_breadcrumb(
        mode.main_menu()) + mode.breadcrumb()
    page_menu = mode.page_menu(breadcrumb)
    wato_html_head(
        title=mode.title(),
        breadcrumb=breadcrumb,
        page_menu=page_menu,
        show_body_start=display_options.enabled(display_options.H),
        show_top_heading=display_options.enabled(display_options.T),
    )

    if not transactions.is_transaction() or (
            cmk.gui.watolib.read_only.is_enabled()
            and cmk.gui.watolib.read_only.may_override()):
        _show_read_only_warning()

    # Show outcome of failed action on this page
    html.show_user_errors()

    # Show outcome of previous page (that redirected to this one)
    for message in get_flashed_messages():
        html.show_message(message)

    # Show content
    mode.handle_page()

    if is_sidebar_reload_needed():
        html.reload_whole_page()

    wato_html_footer(show_body_end=display_options.enabled(display_options.H))
Beispiel #13
0
 def _validate_alias(self, value, varprefix):
     unique, message = watolib.is_alias_used("timeperiods", self._name,
                                             value)
     if not unique:
         raise MKUserError("alias", message)
Beispiel #14
0
 def _validate_id(self, value, varprefix):
     if value in self._timeperiods:
         raise MKUserError(
             varprefix,
             _("This name is already being used by another timeperiod."))
Beispiel #15
0
def _verify_empty(value, varprefix):
    if not value:
        raise MKUserError(varprefix, _("Please specify at least one type of levels"))
Beispiel #16
0
def edit_dictionaries(
        dictionaries: 'Sequence[Tuple[str, Union[Transform, Dictionary]]]',
        value: Dict[str, Any],
        focus: Optional[str] = None,
        hover_help: bool = True,
        validate: Optional[Callable[[Any], None]] = None,
        title: Optional[str] = None,
        method: str = "GET",
        preview: bool = False,
        varprefix: str = "",
        formname: str = "form",
        consume_transid: bool = True):

    if html.request.get_ascii_input(
            "filled_in") == formname and transactions.transaction_valid():
        if not preview and consume_transid:
            transactions.check_transaction()

        messages: List[str] = []
        new_value: Dict[str, Dict[str, Any]] = {}
        for keyname, vs_dict in dictionaries:
            dict_varprefix = varprefix + keyname
            new_value[keyname] = {}
            try:
                edited_value = vs_dict.from_html_vars(dict_varprefix)
                vs_dict.validate_value(edited_value, dict_varprefix)
                new_value[keyname].update(edited_value)
            except MKUserError as e:
                messages.append("%s: %s" %
                                (vs_dict.title() or _("Properties"), e))
                user_errors.add(e)
            except Exception as e:
                messages.append("%s: %s" %
                                (vs_dict.title() or _("Properties"), e))
                user_errors.add(MKUserError(None, str(e)))

            if validate and not user_errors:
                try:
                    validate(new_value[keyname])
                except MKUserError as e:
                    messages.append(str(e))
                    user_errors.add(e)

        if messages:
            messages_joined = "".join(["%s<br>\n" % m for m in messages])
            if not preview:
                html.show_error(messages_joined)
            else:
                raise MKUserError(None, messages_joined)
        else:
            return new_value

    html.begin_form(formname, method=method)
    for keyname, vs_dict in dictionaries:
        dict_varprefix = varprefix + keyname
        subvalue = value.get(keyname, {})
        vs_dict.render_input_as_form(dict_varprefix, subvalue)

    end()
    # Should be ignored be hidden_fields, but I do not dare to change it there
    html.request.del_var("filled_in")
    html.hidden_fields()
    html.end_form()
Beispiel #17
0
    def validate_configuration(cls, site_id, site_configuration, all_sites):
        if not re.match("^[-a-z0-9A-Z_]+$", site_id):
            raise MKUserError(
                "id",
                _("The site id must consist only of letters, digit and the underscore."
                  ))

        if not site_configuration.get("alias"):
            raise MKUserError(
                "alias",
                _("Please enter an alias name or description for the site %s.")
                % site_id)

        if site_configuration.get("url_prefix") and site_configuration.get(
                "url_prefix")[-1] != "/":
            raise MKUserError("url_prefix",
                              _("The URL prefix must end with a slash."))

        # Connection
        if site_configuration["socket"][
                0] == "local" and site_id != config.omd_site():
            raise MKUserError(
                "method_sel",
                _("You can only configure a local site connection for "
                  "the local site. The site IDs ('%s' and '%s') are "
                  "not equal.") % (site_id, config.omd_site()))

        # Timeout
        if "timeout" in site_configuration:
            timeout = site_configuration["timeout"]
            try:
                int(timeout)
            except ValueError:
                raise MKUserError(
                    "timeout",
                    _("The timeout %s is not a valid integer number.") %
                    timeout)

        # Status host
        status_host = site_configuration.get("status_host")
        if status_host:
            status_host_site, status_host_name = status_host
            if status_host_site not in all_sites:
                raise MKUserError(
                    "sh_site",
                    _("The site of the status host does not exist."))
            if status_host_site == site_id:
                raise MKUserError(
                    "sh_site",
                    _("You cannot use the site itself as site of the status host."
                      ))
            if not status_host_name:
                raise MKUserError(
                    "sh_host",
                    _("Please specify the name of the status host."))

        if site_configuration.get("replication"):
            multisiteurl = site_configuration.get("multisiteurl")
            if not site_configuration.get("multisiteurl"):
                raise MKUserError(
                    "multisiteurl",
                    _("Please enter the Multisite URL of the slave site."))

            if not multisiteurl.endswith("/check_mk/"):
                raise MKUserError(
                    "multisiteurl",
                    _("The Multisite URL must end with /check_mk/"))

            if not multisiteurl.startswith("http://") and \
               not multisiteurl.startswith("https://"):
                raise MKUserError(
                    "multisiteurl",
                    _("The Multisites URL must begin with <tt>http://</tt> or <tt>https://</tt>."
                      ))

            if site_configuration["socket"][0] == "local":
                raise MKUserError(
                    "replication",
                    _("You cannot do replication with the local site."))

        # User synchronization
        user_sync_valuespec = cls.user_sync_valuespec()
        user_sync_valuespec.validate_value(site_configuration.get("user_sync"),
                                           "user_sync")
Beispiel #18
0
def validate_process_discovery_descr_option(description, varprefix):
    if '%s' in description and re.search(r'%(\d+)', description):
        raise MKUserError(
            varprefix,
            _('Combining "%s" and "%1" style replacements in the sevice description is not allowed.'
             ))
Beispiel #19
0
    def _discover_services(self, request):
        mode = request.get("mode", "new")
        hostname = request.get("hostname")

        check_hostname(hostname, should_exist=True)

        host = watolib.Host.host(hostname)

        host_attributes = host.effective_attributes()

        if host.is_cluster():
            # This is currently the only way to get some actual discovery statitics.
            # Start a dry-run -> Get statistics
            # Do an actual discovery on the nodes -> data is written
            result = watolib.check_mk_automation(host_attributes.get("site"),
                                                 "try-inventory",
                                                 ["@scan"] + [hostname])
            # TODO: This *way* too general, even for our very low standards...
            counts = {"new": 0, "old": 0}  # type: Dict[Any, Any]
            for entry in result["check_table"]:
                if entry[0] in counts:
                    counts[entry[0]] += 1

            counts = {
                hostname: (
                    counts["new"],
                    0,  # this info is not available for clusters
                    counts["old"],
                    counts["new"] + counts["old"])
            }

            # A cluster cannot fail, just the nodes. This information is currently discarded
            failed_hosts = None
            watolib.check_mk_automation(host_attributes.get("site"),
                                        "inventory",
                                        ["@scan", mode] + host.cluster_nodes())
        else:
            counts, failed_hosts = watolib.check_mk_automation(
                host_attributes.get("site"), "inventory",
                ["@scan", mode] + [hostname])

        if failed_hosts:
            if not host.discovery_failed():
                host.set_discovery_failed()
            raise MKUserError(
                None,
                _("Failed to inventorize %s: %s") %
                (hostname, failed_hosts[hostname]))

        if host.discovery_failed():
            host.clear_discovery_failed()

        if mode == "refresh":
            message = _(
                "Refreshed check configuration of host [%s] with %d services"
            ) % (hostname, counts[hostname][3])
            watolib.add_service_change(host, "refresh-autochecks", message)
        else:
            message = _(
                "Saved check configuration of host [%s] with %d services") % (
                    hostname, counts[hostname][3])
            watolib.add_service_change(host, "set-autochecks", message)

        msg = _(
            "Service discovery successful. Added %d, removed %d, kept %d, total %d services "
            "and %d new, %d total host labels") % tuple(counts[hostname])
        return msg
Beispiel #20
0
    def action(self):
        if not html.check_transaction():
            return "tags"

        vs = self._valuespec()
        tag_group_spec = vs.from_html_vars("tag_group")
        vs.validate_value(tag_group_spec, "tag_group")

        # Create new object with existing host tags
        changed_hosttags_config = cmk.utils.tags.TagConfig()
        changed_hosttags_config.parse_config(
            self._tag_config_file.load_for_modification())

        changed_tag_group = cmk.utils.tags.TagGroup(tag_group_spec)
        self._tag_group = changed_tag_group

        if self._new:
            # Inserts and verifies changed tag group
            changed_hosttags_config.insert_tag_group(changed_tag_group)
            try:
                changed_hosttags_config.validate_config()
            except MKGeneralException as e:
                raise MKUserError(None, "%s" % e)
            self._save_tags_and_update_hosts(
                changed_hosttags_config.get_dict_format())
            add_change(
                "edit-hosttags",
                _("Created new host tag group '%s'") % changed_tag_group.id)
            return "tags", _(
                "Created new host tag group '%s'") % changed_tag_group.title

        # Updates and verifies changed tag group
        changed_hosttags_config.update_tag_group(changed_tag_group)
        try:
            changed_hosttags_config.validate_config()
        except MKGeneralException as e:
            raise MKUserError(None, "%s" % e)

        remove_tag_ids, replace_tag_ids = [], {}
        new_by_title = dict([(tag.title, tag.id)
                             for tag in changed_tag_group.tags])

        for former_tag in self._untainted_tag_group.tags:
            # Detect renaming
            if former_tag.title in new_by_title:
                new_id = new_by_title[former_tag.title]
                if new_id != former_tag.id:
                    # new_id may be None
                    replace_tag_ids[former_tag.id] = new_id
                    continue

            # Detect removal
            if former_tag.id is not None \
                    and former_tag.id not in [ tmp_tag.id for tmp_tag in changed_tag_group.tags ]:
                # remove explicit tag (hosts/folders) or remove it from tag specs (rules)
                remove_tag_ids.append(former_tag.id)

        operation = OperationReplaceGroupedTags(self._tag_group.id,
                                                remove_tag_ids,
                                                replace_tag_ids)

        # Now check, if any folders, hosts or rules are affected
        message = _rename_tags_after_confirmation(operation)
        if message:
            self._save_tags_and_update_hosts(
                changed_hosttags_config.get_dict_format())
            add_change(
                "edit-hosttags",
                _("Edited host tag group %s (%s)") % (message, self._id))
            return "tags", message != True and message or None

        return "tags"
Beispiel #21
0
 def _comment(self):
     comment = html.request.get_unicode_input("_down_comment")
     if not comment:
         raise MKUserError("_down_comment", _("You need to supply a comment for your downtime."))
     return comment
Beispiel #22
0
 def get_request(self) -> SiteRequest:
     ascii_input = request.get_ascii_input("request")
     if ascii_input is None:
         raise MKUserError("request",
                           _('The parameter "%s" is missing.') % "request")
     return SiteRequest.deserialize(ast.literal_eval(ascii_input))
Beispiel #23
0
def _rename_tags_after_confirmation(
        breadcrumb: Breadcrumb, operation: ABCOperation) -> Union[bool, str]:
    """Handle renaming and deletion of tags

    Find affected hosts, folders and rules. Remove or fix those rules according
    the users' wishes.

    Returns:
        True: Proceed, no "question" dialog shown
        False: "Question dialog" shown
        str: Action done after "question" dialog
    """
    repair_mode = html.request.var("_repair")
    if repair_mode is not None:
        try:
            mode = TagCleanupMode(repair_mode)
        except ValueError:
            raise MKUserError("_repair", "Invalid mode")

        if mode == TagCleanupMode.ABORT:
            raise MKUserError("id_0", _("Aborting change."))

        # make attribute unknown to system, important for save() operations
        if isinstance(operation, OperationRemoveTagGroup):
            watolib.host_attributes.undeclare_host_tag_attribute(
                operation.tag_group_id)

        affected_folders, affected_hosts, affected_rulesets = \
            change_host_tags_in_folders(operation, mode, watolib.Folder.root_folder())

        return _("Modified folders: %d, modified hosts: %d, modified rulesets: %d") % \
            (len(affected_folders), len(affected_hosts), len(affected_rulesets))

    message = HTML()
    affected_folders, affected_hosts, affected_rulesets = \
        change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder())

    if affected_folders:
        message += _("Affected folders with an explicit reference to this tag "
                     "group and that are affected by the change") + ":"
        with html.plugged():
            _show_affected_folders(affected_folders)
            message += HTML(html.drain())

    if affected_hosts:
        message += _("Hosts where this tag group is explicitely set "
                     "and that are effected by the change") + ":"
        with html.plugged():
            _show_affected_hosts(affected_hosts)
            message += HTML(html.drain())

    if affected_rulesets:
        message += _(
            "Rulesets that contain rules with references to the changed tags"
        ) + ":"
        with html.plugged():
            _show_affected_rulesets(affected_rulesets)
            message += HTML(html.drain())

    if message:
        wato_html_head(title=operation.confirm_title(), breadcrumb=breadcrumb)
        html.open_div(class_="really")
        html.h3(_("Your modifications affect some objects"))
        html.write_text(message)
        html.br()
        html.write_text(
            _("WATO can repair things for you. It can rename tags in folders, host and rules. "
              "Removed tag groups will be removed from hosts and folders, removed tags will be "
              "replaced with the default value for the tag group (for hosts and folders). What "
              "rules concern, you have to decide how to proceed."))
        html.begin_form("confirm", method="POST")

        if affected_rulesets and _is_removing_tags(operation):
            html.br()
            html.b(
                _("Some tags that are used in rules have been removed by you. What "
                  "shall we do with that rules?"))
            html.open_ul()
            html.radiobutton(
                "_repair", "remove", True,
                _("Just remove the affected tags from the rules."))
            html.br()
            html.radiobutton(
                "_repair", "delete", False,
                _("Delete rules containing tags that have been removed, if tag is used in a positive sense. Just remove that tag if it's used negated."
                  ))
        else:
            html.open_ul()
            html.radiobutton("_repair", "repair", True,
                             _("Fix affected folders, hosts and rules."))

        html.br()
        html.radiobutton("_repair", "abort", False,
                         _("Abort your modifications."))
        html.close_ul()

        html.button("_do_confirm", _("Proceed"), "")
        html.hidden_fields(add_action_vars=True)
        html.end_form()
        html.close_div()
        return False

    return True
Beispiel #24
0
    def _do_login(self) -> None:
        """handle the sent login form"""
        if not request.var("_login"):
            return

        try:
            if not config.user_login:
                raise MKUserError(None,
                                  _("Login is not allowed on this site."))

            username_var = request.get_str_input("_username", "")
            assert username_var is not None
            username = UserId(username_var.rstrip())
            if not username:
                raise MKUserError("_username", _("Missing username"))

            password = request.var("_password", "")
            if not password:
                raise MKUserError("_password", _("Missing password"))

            default_origtarget = url_prefix() + "check_mk/"
            origtarget = request.get_url_input("_origtarget",
                                               default_origtarget)

            # Disallow redirections to:
            #  - logout.py: Happens after login
            #  - side.py: Happens when invalid login is detected during sidebar refresh
            if "logout.py" in origtarget or "side.py" in origtarget:
                origtarget = default_origtarget

            result = userdb.check_credentials(username, password)
            if result:
                # use the username provided by the successful login function, this function
                # might have transformed the username provided by the user. e.g. switched
                # from mixed case to lower case.
                username = result

                session_id = userdb.on_succeeded_login(username)

                # The login succeeded! Now:
                # a) Set the auth cookie
                # b) Unset the login vars in further processing
                # c) Redirect to really requested page
                _create_auth_session(username, session_id)

                # Never use inplace redirect handling anymore as used in the past. This results
                # in some unexpected situations. We simpy use 302 redirects now. So we have a
                # clear situation.
                # userdb.need_to_change_pw returns either False or the reason description why the
                # password needs to be changed
                change_pw_result = userdb.need_to_change_pw(username)
                if change_pw_result:
                    raise HTTPRedirect(
                        "user_change_pw.py?_origtarget=%s&reason=%s" %
                        (urlencode(origtarget), change_pw_result))

                if userdb.is_two_factor_login_enabled(username):
                    raise HTTPRedirect(
                        "user_login_two_factor.py?_origtarget=%s" %
                        urlencode(makeuri(request, [])))

                raise HTTPRedirect(origtarget)

            userdb.on_failed_login(username)
            raise MKUserError(None, _("Invalid login"))
        except MKUserError as e:
            user_errors.add(e)
Beispiel #25
0
    def page_edit(cls):
        back_url = html.get_url_input("back", cls.list_url())

        cls.load()
        cls.need_overriding_permission("edit")

        # Three possible modes:
        # "create" -> create completely new page
        # "clone"  -> like new, but prefill form with values from existing page
        # "edit"   -> edit existing page
        mode = html.request.var('mode', 'edit')
        if mode == "create":
            title = cls.phrase("create")
            page_dict = {
                "name": cls.default_name(),
                "topic": cls.default_topic(),
            }
        else:
            # Load existing page. visual from disk - and create a copy if 'load_user' is set
            page_name = html.request.var("load_name")
            if mode == "edit":
                title = cls.phrase("edit")

                owner_user_id = UserId(
                    html.request.get_unicode_input_mandatory("owner", config.user.id))
                if owner_user_id == config.user.id:
                    page = cls.find_my_page(page_name)
                else:
                    page = cls.find_foreign_page(owner_user_id, page_name)

                if page is None:
                    raise MKUserError(None,
                                      _("The requested %s does not exist") % cls.phrase("title"))

                # TODO FIXME: Looks like a hack
                cls.remove_instance((owner_user_id, page_name))  # will be added later again
            else:  # clone
                title = cls.phrase("clone")
                load_user = html.request.get_unicode_input(
                    "load_user")  # FIXME: Change varname to "owner"

                try:
                    page = cls.instance((load_user, page_name))
                except KeyError:
                    raise MKUserError(None,
                                      _("The requested %s does not exist") % cls.phrase("title"))
            page_dict = page.internal_representation()

        html.header(title)
        html.begin_context_buttons()
        html.context_button(_("Back"), back_url, "back")
        html.end_context_buttons()

        parameters, keys_by_topic = cls._collect_parameters(mode)
        vs = Dictionary(
            title=_("General Properties"),
            render='form',
            optional_keys=False,
            elements=parameters,
            headers=keys_by_topic,
        )

        def validate(page_dict):
            owner_user_id = UserId(html.request.get_unicode_input_mandatory(
                "owner", config.user.id))
            page_name = page_dict["name"]
            if owner_user_id == config.user.id:
                page = cls.find_my_page(page_name)
            else:
                page = cls.find_foreign_page(owner_user_id, page_name)
            if page:
                raise MKUserError(
                    "_p_name",
                    _("You already have an element with the ID <b>%s</b>") % page_dict["name"])

        new_page_dict = forms.edit_valuespec(vs,
                                             page_dict,
                                             validate=validate,
                                             focus="_p_title",
                                             method="POST")
        if new_page_dict is not None:
            # Take over keys from previous value that are specific to the page type
            # and not edited here.
            if mode in ("edit", "clone"):
                for key, value in page_dict.items():
                    new_page_dict.setdefault(key, value)

            owner = UserId(html.request.get_unicode_input_mandatory("owner", config.user.id))
            new_page_dict["owner"] = owner
            new_page = cls(new_page_dict)

            cls.add_page(new_page)
            cls.save_user_instances(owner)
            if mode == "create":
                redirect_url = new_page.after_create_url() or back_url
            else:
                redirect_url = back_url

            html.immediate_browser_redirect(0.5, redirect_url)
            html.show_message(_('Your changes haven been saved.'))
            # Reload sidebar.TODO: This code logically belongs to PageRenderer. How
            # can we simply move it there?
            # TODO: This is not true for all cases. e.g. the BookmarkList is not
            # of type PageRenderer but has a dedicated sidebar snapin. Maybe
            # the best option would be to make a dedicated method to decide whether
            # or not to reload the sidebar.
            if new_page_dict.get("hidden") in [ None, False ] \
               or new_page_dict.get("hidden") != page_dict.get("hidden"):
                html.reload_sidebar()

        else:
            html.show_localization_hint()

        html.footer()
Beispiel #26
0
def test_user_error(request_context):
    with output_funnel.plugged():
        html.user_error(
            MKUserError(None, "asd <script>alert(1)</script> <br> <b>"))
        c = output_funnel.drain()
    assert c == '<div class="error">asd &lt;script&gt;alert(1)&lt;/script&gt; <br> <b></div>'
Beispiel #27
0
 def _require_metric(value, varprefix):
     if value is None:
         raise MKUserError(varprefix, _("You need to select a metric"))
Beispiel #28
0
def _wato_page_handler(current_mode: str,
                       mode_permissions: List[PermissionName],
                       mode_class: Type[WatoMode]) -> None:
    try:
        init_wato_datastructures(with_wato_lock=not html.is_transaction())
    except Exception:
        # Snapshot must work in any case
        if current_mode == 'snapshot':
            pass
        else:
            raise

    # Check general permission for this mode
    if mode_permissions is not None and not config.user.may("wato.seeall"):
        _ensure_mode_permissions(mode_permissions)

    mode = mode_class()

    # Do actions (might switch mode)
    action_message: Optional[str] = None
    if html.is_transaction():
        try:
            config.user.need_permission("wato.edit")

            # Even if the user has seen this mode because auf "seeall",
            # he needs an explicit access permission for doing changes:
            if config.user.may("wato.seeall"):
                if mode_permissions:
                    _ensure_mode_permissions(mode_permissions)

            if cmk.gui.watolib.read_only.is_enabled(
            ) and not cmk.gui.watolib.read_only.may_override():
                raise MKUserError(None, cmk.gui.watolib.read_only.message())

            result = mode.action()
            if isinstance(result, tuple):
                newmode, action_message = result
            else:
                newmode = result

            # We assume something has been modified and increase the config generation ID by one.
            update_config_generation()

            # If newmode is False, then we shall immediately abort.
            # This is e.g. the case, if the page outputted non-HTML
            # data, such as a tarball (in the export function). We must
            # be sure not to output *any* further data in that case.
            if newmode is False:
                return

            # if newmode is not None, then the mode has been changed
            if newmode is not None:
                assert not isinstance(newmode, bool)
                if newmode == "":  # no further information: configuration dialog, etc.
                    if action_message:
                        html.show_message(action_message)
                        wato_html_footer()
                    return
                mode_permissions, mode_class = _get_mode_permission_and_class(
                    newmode)
                current_mode = newmode
                mode = mode_class()
                html.request.set_var("mode",
                                     newmode)  # will be used by makeuri

                # Check general permissions for the new mode
                if mode_permissions is not None and not config.user.may(
                        "wato.seeall"):
                    for pname in mode_permissions:
                        if '.' not in pname:
                            pname = "wato." + pname
                        config.user.need_permission(pname)

        except MKUserError as e:
            action_message = "%s" % e
            html.add_user_error(e.varname, action_message)

        except MKAuthException as e:
            reason = e.args[0]
            action_message = reason
            html.add_user_error(None, reason)

    breadcrumb = make_main_menu_breadcrumb(
        mode.main_menu()) + mode.breadcrumb()
    wato_html_head(mode.title(),
                   breadcrumb=breadcrumb,
                   show_body_start=display_options.enabled(display_options.H),
                   show_top_heading=display_options.enabled(display_options.T))

    if display_options.enabled(display_options.B):
        # Show contexts buttons
        html.begin_context_buttons()
        mode.buttons()
        html.end_context_buttons()

    if not html.is_transaction() or (cmk.gui.watolib.read_only.is_enabled() and
                                     cmk.gui.watolib.read_only.may_override()):
        _show_read_only_warning()

    # Show outcome of action
    if html.has_user_errors():
        html.show_user_errors()
    elif action_message:
        html.show_message(action_message)

    # Show content
    mode.handle_page()

    if is_sidebar_reload_needed():
        html.reload_sidebar()

    if config.wato_use_git and html.is_transaction():
        do_git_commit()

    wato_html_footer(show_footer=display_options.enabled(display_options.Z),
                     show_body_end=display_options.enabled(display_options.H))
Beispiel #29
0
    def action(self):
        if not html.check_transaction():
            return "users"

        if self._user_id is None:  # same as self._is_new_user
            self._user_id = UserID(allow_empty=False).from_html_vars("user_id")
            user_attrs = {}
        else:
            self._user_id = html.request.get_unicode_input_mandatory(
                "edit").strip()
            user_attrs = self._users[UserId(self._user_id)]

        # Full name
        user_attrs["alias"] = html.request.get_unicode_input_mandatory(
            "alias").strip()

        # Locking
        user_attrs["locked"] = html.get_checkbox("locked")
        increase_serial = False

        if (UserId(self._user_id) in self._users and self._users[UserId(
                self._user_id)]["locked"] != user_attrs["locked"]
                and user_attrs["locked"]):
            increase_serial = True  # when user is being locked now, increase the auth serial

        # Authentication: Password or Secret
        auth_method = html.request.var("authmethod")
        if auth_method == "secret":
            secret = html.request.get_str_input_mandatory("_auth_secret",
                                                          "").strip()
            user_attrs["automation_secret"] = secret
            user_attrs["password"] = hash_password(secret)
            increase_serial = True  # password changed, reflect in auth serial

        else:
            password = html.request.get_str_input_mandatory(
                "_password_" + self._pw_suffix(), '').strip()
            password2 = html.request.get_str_input_mandatory(
                "_password2_" + self._pw_suffix(), '').strip()

            # We compare both passwords only, if the user has supplied
            # the repeation! We are so nice to our power users...
            # Note: this validation is done before the main-validiation later on
            # It doesn't make any sense to put this block into the main validation function
            if password2 and password != password2:
                raise MKUserError("_password2",
                                  _("The both passwords do not match."))

            # Detect switch back from automation to password
            if "automation_secret" in user_attrs:
                del user_attrs["automation_secret"]
                if "password" in user_attrs:
                    del user_attrs[
                        "password"]  # which was the encrypted automation password!

            if password:
                user_attrs["password"] = hash_password(password)
                user_attrs["last_pw_change"] = int(time.time())
                increase_serial = True  # password changed, reflect in auth serial

            # PW change enforcement
            user_attrs["enforce_pw_change"] = html.get_checkbox(
                "enforce_pw_change")
            if user_attrs["enforce_pw_change"]:
                increase_serial = True  # invalidate all existing user sessions, enforce relogon

        # Increase serial (if needed)
        if increase_serial:
            user_attrs["serial"] = user_attrs.get("serial", 0) + 1

        # Email address
        user_attrs["email"] = EmailAddress().from_html_vars("email")

        idle_timeout = watolib.get_vs_user_idle_timeout().from_html_vars(
            "idle_timeout")
        user_attrs["idle_timeout"] = idle_timeout
        if idle_timeout is not None:
            user_attrs["idle_timeout"] = idle_timeout
        elif idle_timeout is None and "idle_timeout" in user_attrs:
            del user_attrs["idle_timeout"]

        # Pager
        user_attrs["pager"] = html.request.get_str_input_mandatory(
            "pager", '').strip()

        if cmk_version.is_managed_edition():
            customer = self._vs_customer.from_html_vars("customer")
            self._vs_customer.validate_value(customer, "customer")

            if customer != managed.default_customer_id():
                user_attrs["customer"] = customer
            elif "customer" in user_attrs:
                del user_attrs["customer"]

        vs_sites = self._vs_sites()
        authorized_sites = vs_sites.from_html_vars("authorized_sites")
        vs_sites.validate_value(authorized_sites, "authorized_sites")

        if authorized_sites is not None:
            user_attrs["authorized_sites"] = authorized_sites
        elif "authorized_sites" in user_attrs:
            del user_attrs["authorized_sites"]

        # Roles
        user_attrs["roles"] = [
            role for role in self._roles.keys()
            if html.get_checkbox("role_" + role)
        ]

        # Language configuration
        language = html.request.get_ascii_input_mandatory("language", "")
        if language != "_default_":
            user_attrs["language"] = language
        elif "language" in user_attrs:
            del user_attrs["language"]

        # Contact groups
        cgs = []
        for c in self._contact_groups:
            if html.get_checkbox("cg_" + c):
                cgs.append(c)
        user_attrs["contactgroups"] = cgs

        # Notification settings are only active if we do *not* have
        # rule based notifications!
        if not self._rbn_enabled():
            # Notifications
            user_attrs["notifications_enabled"] = html.get_checkbox(
                "notifications_enabled")

            ntp = html.request.var("notification_period")
            if ntp not in self._timeperiods:
                ntp = "24X7"
            user_attrs["notification_period"] = ntp

            for what, opts in [("host", "durfs"), ("service", "wucrfs")]:
                user_attrs[what + "_notification_options"] = "".join([
                    opt for opt in opts if html.get_checkbox(what + "_" + opt)
                ])

            value = watolib.get_vs_flexible_notifications().from_html_vars(
                "notification_method")
            user_attrs["notification_method"] = value
        else:
            user_attrs["fallback_contact"] = html.get_checkbox(
                "fallback_contact")

        # Custom user attributes
        for name, attr in userdb.get_user_attributes():
            value = attr.valuespec().from_html_vars('ua_' + name)
            user_attrs[name] = value

        # Generate user "object" to update
        user_object = {
            self._user_id: {
                "attributes": user_attrs,
                "is_new_user": self._is_new_user
            }
        }
        # The following call validates and updated the users
        edit_users(user_object)
        return "users"
Beispiel #30
0
def decrypt_private_key(encrypted_private_key, passphrase):
    try:
        return crypto.load_privatekey(crypto.FILETYPE_PEM, encrypted_private_key,
                                      passphrase.encode("utf-8"))
    except crypto.Error:
        raise MKUserError("key_p_passphrase", _("Invalid pass phrase"))