Beispiel #1
0
    def _bulk_delete_after_confirm(cls, what):
        to_delete = []
        for varname, _value in html.request.itervars(prefix="_c_%s+" % what):
            if html.get_checkbox(varname):
                checkbox_ident = varname.split("_c_%s+" % what)[-1]
                to_delete.append(checkbox_ident.split("+", 1))

        if not to_delete:
            return

        c = html.confirm(
            _("Do you really want to delete %d %s?") % (len(to_delete), cls.phrase("title_plural")))

        if c:
            for owner, instance_id in to_delete:
                cls.remove_instance((owner, instance_id))

            for owner in {e[0] for e in to_delete}:
                cls.save_user_instances(owner)

            html.reload_sidebar()
        elif c is False:
            return False
Beispiel #2
0
 def _add_extra_attrs_from_html_vars(self):
     self._attr['user_editable'] = html.get_checkbox('user_editable')
Beispiel #3
0
    def action(self) -> ActionResult:
        # TODO: remove subclass specific things specifict things (everything with _type == 'user')
        if not html.check_transaction():
            return None

        title = html.request.get_unicode_input_mandatory("title").strip()
        if not title:
            raise MKUserError("title", _("Please specify a title."))

        for this_attr in self._attrs:
            if title == this_attr['title'] and self._name != this_attr['name']:
                raise MKUserError(
                    "alias",
                    _("This alias is already used by the attribute %s.") %
                    this_attr['name'])

        topic = html.request.get_unicode_input_mandatory('topic', '').strip()
        help_txt = html.request.get_unicode_input_mandatory('help', '').strip()
        show_in_table = html.get_checkbox('show_in_table')
        add_custom_macro = html.get_checkbox('add_custom_macro')

        if self._new:
            self._name = html.request.get_ascii_input_mandatory("name",
                                                                '').strip()
            if not self._name:
                raise MKUserError(
                    "name", _("Please specify a name for the new attribute."))
            if ' ' in self._name:
                raise MKUserError(
                    "name",
                    _("Sorry, spaces are not allowed in attribute names."))
            if not re.match("^[-a-z0-9A-Z_]*$", self._name):
                raise MKUserError(
                    "name",
                    _("Invalid attribute name. Only the characters a-z, A-Z, 0-9, _ and - are allowed."
                      ))
            if [a for a in self._attrs if a['name'] == self._name]:
                raise MKUserError(
                    "name",
                    _("Sorry, there is already an attribute with that name."))

            ty = html.request.get_ascii_input_mandatory('type', '').strip()
            if ty not in [t[0] for t in custom_attr_types()]:
                raise MKUserError('type',
                                  _('The choosen attribute type is invalid.'))

            self._attr = {
                'name': self._name,
                'type': ty,
            }
            self._attrs.append(self._attr)

            add_change(
                "edit-%sattr" % self._type,
                _("Create new %s attribute %s") % (self._type, self._name))
        else:
            add_change(
                "edit-%sattr" % self._type,
                _("Modified %s attribute %s") % (self._type, self._name))
        self._attr.update({
            'title': title,
            'topic': topic,
            'help': help_txt,
            'show_in_table': show_in_table,
            'add_custom_macro': add_custom_macro,
        })

        self._add_extra_attrs_from_html_vars()

        save_custom_attrs_to_mk_file(self._all_attrs)
        self._update_config()

        return redirect(mode_url(self._type + "_attrs"))
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
            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 _show_page_user_profile(change_pw):
    start_async_replication = False

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

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

    if not config.wato_enabled:
        raise MKAuthException(
            _('User profiles can not be edited (WATO is disabled).'))

    success = None
    if html.request.has_var('_save') and html.check_transaction():
        users = userdb.load_users(lock=True)

        try:
            # Profile edit (user options like language etc.)
            if config.user.may('general.edit_profile'):
                if not change_pw:
                    set_lang = html.get_checkbox('_set_lang')
                    language = html.request.var('language')
                    # Set the users language if requested
                    if set_lang:
                        if language == '':
                            language = None
                        # Set custom language
                        users[config.user.id]['language'] = language
                        config.user.language = language
                        html.set_language_cookie(language)

                    else:
                        # Remove the customized language
                        if 'language' in users[config.user.id]:
                            del users[config.user.id]['language']
                        config.user.reset_language()

                    # load the new language
                    cmk.gui.i18n.localize(config.user.language)

                    user = users.get(config.user.id)
                    if config.user.may('general.edit_notifications'
                                       ) and user.get("notifications_enabled"):
                        value = forms.get_input(
                            watolib.get_vs_flexible_notifications(),
                            "notification_method")
                        users[config.user.id]["notification_method"] = value

                    # Custom attributes
                    if config.user.may('general.edit_user_attributes'):
                        for name, attr in userdb.get_user_attributes():
                            if attr.user_editable():
                                if not attr.permission() or config.user.may(
                                        attr.permission()):
                                    vs = attr.valuespec()
                                    value = vs.from_html_vars('ua_' + name)
                                    vs.validate_value(value, "ua_" + name)
                                    users[config.user.id][name] = value

            # Change the password if requested
            password_changed = False
            if config.user.may('general.change_password'):
                cur_password = html.request.var('cur_password')
                password = html.request.var('password')
                password2 = html.request.var('password2', '')

                if change_pw:
                    # Force change pw mode
                    if not cur_password:
                        raise MKUserError(
                            "cur_password",
                            _("You need to provide your current password."))
                    if not password:
                        raise MKUserError(
                            "password", _("You need to change your password."))
                    if cur_password == password:
                        raise MKUserError(
                            "password",
                            _("The new password must differ from your current one."
                              ))

                if cur_password and password:
                    if userdb.hook_login(config.user.id,
                                         cur_password) is False:
                        raise MKUserError("cur_password",
                                          _("Your old password is wrong."))
                    if password2 and password != password2:
                        raise MKUserError(
                            "password2",
                            _("The both new passwords do not match."))

                    watolib.verify_password_policy(password)
                    users[config.user.id]['password'] = hash_password(password)
                    users[config.user.id]['last_pw_change'] = int(time.time())

                    if change_pw:
                        # Has been changed, remove enforcement flag
                        del users[config.user.id]['enforce_pw_change']

                    # Increase serial to invalidate old cookies
                    if 'serial' not in users[config.user.id]:
                        users[config.user.id]['serial'] = 1
                    else:
                        users[config.user.id]['serial'] += 1

                    password_changed = True

            # Now, if in distributed environment where users can login to remote sites,
            # set the trigger for pushing the new auth information to the slave sites
            # asynchronous
            if config.user.authorized_login_sites():
                start_async_replication = True

            userdb.save_users(users)

            if password_changed:
                # Set the new cookie to prevent logout for the current user
                login.set_auth_cookie(config.user.id)

            success = True
        except MKUserError as e:
            html.add_user_error(e.varname, e)
    else:
        users = userdb.load_users()

    watolib.init_wato_datastructures(with_wato_lock=True)

    # When in distributed setup, display the replication dialog instead of the normal
    # profile edit dialog after changing the password.
    if start_async_replication:
        user_profile_async_replication_page()
        return

    if change_pw:
        title = _("Change Password")
    else:
        title = _("Edit User Profile")

    html.header(title)

    # Rule based notifications: The user currently cannot simply call the according
    # WATO module due to WATO permission issues. So we cannot show this button
    # right now.
    if not change_pw:
        rulebased_notifications = watolib.load_configuration_settings().get(
            "enable_rulebased_notifications")
        if rulebased_notifications and config.user.may(
                'general.edit_notifications'):
            html.begin_context_buttons()
            url = "wato.py?mode=user_notifications_p"
            html.context_button(_("Notifications"), url, "notifications")
            html.end_context_buttons()
    else:
        reason = html.request.var('reason')
        if reason == 'expired':
            html.p(
                _('Your password is too old, you need to choose a new password.'
                  ))
        else:
            html.p(
                _('You are required to change your password before proceeding.'
                  ))

    if success:
        html.reload_sidebar()
        if change_pw:
            html.show_message(_("Your password has been changed."))
            raise HTTPRedirect(html.request.var('_origtarget', 'index.py'))
        else:
            html.show_message(_("Successfully updated user profile."))
            # Ensure theme changes are applied without additional user interaction
            html.immediate_browser_redirect(0.5, html.makeuri([]))

    if html.has_user_errors():
        html.show_user_errors()

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

    # Returns true if an attribute is locked and should be read only. Is only
    # checked when modifying an existing user
    locked_attributes = userdb.locked_attributes(user.get('connector'))

    def is_locked(attr):
        return attr in locked_attributes

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

    if not change_pw:
        forms.section(_("Name"), simple=True)
        html.write_text(user.get("alias", config.user.id))

    if config.user.may(
            'general.change_password') and not is_locked('password'):
        forms.section(_("Current Password"))
        html.password_input('cur_password', autocomplete="new-password")

        forms.section(_("New Password"))
        html.password_input('password', autocomplete="new-password")

        forms.section(_("New Password Confirmation"))
        html.password_input('password2', autocomplete="new-password")

    if not change_pw and config.user.may('general.edit_profile'):
        select_language(user)

        # Let the user configure how he wants to be notified
        if not rulebased_notifications \
            and config.user.may('general.edit_notifications') \
            and user.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."))
            watolib.get_vs_flexible_notifications().render_input(
                "notification_method", user.get("notification_method"))

        if config.user.may('general.edit_user_attributes'):
            for name, attr in userdb.get_user_attributes():
                if attr.user_editable():
                    vs = attr.valuespec()
                    forms.section(_u(vs.title()))
                    value = user.get(name, vs.default_value())
                    if not attr.permission() or config.user.may(
                            attr.permission()):
                        vs.render_input("ua_" + name, value)
                        html.help(_u(vs.help()))
                    else:
                        html.write(vs.value_to_text(value))

    # Save button
    forms.end()
    html.button("_save", _("Save"))
    html.close_div()
    html.hidden_fields()
    html.end_form()
    html.footer()
Beispiel #6
0
    def action(self):
        if not html.check_transaction():
            return "users"

        if self._is_new_user:
            self._user_id = UserID(allow_empty=False).from_html_vars("user_id")
            user_attrs = {}
        else:
            self._user_id = html.get_unicode_input("edit").strip()
            user_attrs = self._users[self._user_id]

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

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

        if self._user_id in self._users and self._users[
                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.var("_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.var("_password_" + self._pw_suffix(), '').strip()
            password2 = html.request.var("_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"] = EmailAddressUnicode().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.var("pager", '').strip()

        if cmk.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
        set_lang = html.get_checkbox("_set_lang")
        language = html.request.var("language")
        if set_lang:
            if language == "":
                language = None
            user_attrs["language"] = language
        elif not set_lang and "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"