Implement a new 'virtual global setting' to change root password from webadmin

This commit is contained in:
Alexandre Aubin 2022-10-08 18:30:17 +02:00
parent 403efe4873
commit 5addb2f68f
5 changed files with 62 additions and 3 deletions

View file

@ -397,6 +397,9 @@
"global_settings_setting_pop3_enabled_help": "Enable the POP3 protocol for the mail server",
"global_settings_setting_postfix_compatibility": "Postfix Compatibility",
"global_settings_setting_postfix_compatibility_help": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_root_access_explain": "On Linux systems, 'root' is the absolute admin. In YunoHost context, direct 'root' SSH login is by default disable - except from the local network of the server. Members of the 'admins' group can use the sudo command to act as root from the command line. However, it can be helpful to have a (robust) root password to debug the system if for some reason regular admins can not login anymore.",
"global_settings_setting_root_password": "New root password",
"global_settings_setting_root_password_confirm": "New root password (confirm)",
"global_settings_setting_security_experimental_enabled": "Experimental security features",
"global_settings_setting_security_experimental_enabled_help": "Enable experimental security features (don't enable this if you don't know what you're doing!)",
"global_settings_setting_smtp_allow_ipv6": "Allow IPv6",
@ -582,6 +585,7 @@
"pattern_password_app": "Sorry, passwords can not contain the following characters: {forbidden_chars}",
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
"password_confirmation_not_the_same": "The password and its confirmation do not match",
"permission_already_allowed": "Group '{group}' already has permission '{permission}' enabled",
"permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled",
"permission_already_exist": "Permission '{permission}' already exists",
@ -637,6 +641,7 @@
"restore_running_hooks": "Running restoration hooks...",
"restore_system_part_failed": "Could not restore the '{part}' system part",
"root_password_desynchronized": "The admin password was changed, but YunoHost could not propagate this to the root password!",
"root_password_changed": "root's password was changed",
"server_reboot": "The server will reboot",
"server_reboot_confirm": "The server will reboot immediatly, are you sure? [{answers}]",
"server_shutdown": "The server will shut down",

View file

@ -12,7 +12,7 @@ name = "Security"
choices.2 = "ditto, but also require at least one digit, one lower and one upper char"
choices.3 = "ditto, but also require at least one special char"
choices.4 = "ditto, but also require at least 12 chars"
default = 1
default = "1"
[security.password.user_strength]
type = "select"
@ -20,7 +20,7 @@ name = "Security"
choices.2 = "ditto, but also require at least one digit, one lower and one upper char"
choices.3 = "ditto, but also require at least one special char"
choices.4 = "ditto, but also require at least 12 chars"
default = 1
default = "1"
[security.ssh]
name = "SSH"
@ -70,6 +70,24 @@ name = "Security"
optional = true
default = ""
[security.root_access]
name = "Change root password"
[security.root_access.root_access_explain]
type = "alert"
style = "info"
icon = "info"
[security.root_access.root_password]
type = "password"
optional = true
default = ""
[security.root_access.root_password_confirm]
type = "password"
optional = true
default = ""
[security.experimental]
name = "Experimental"
[security.experimental.security_experimental_enabled]

View file

@ -108,6 +108,29 @@ class SettingsConfigPanel(ConfigPanel):
super().__init__("settings")
def _apply(self):
root_password = self.new_values.pop("root_password")
root_password_confirm = self.new_values.pop("root_password_confirm")
if "root_password" in self.values:
del self.values["root_password"]
if "root_password_confirm" in self.values:
del self.values["root_password_confirm"]
if "root_password" in self.new_values:
del self.new_values["root_password"]
if "root_password_confirm" in self.new_values:
del self.new_values["root_password_confirm"]
assert "root_password" not in self.future_values
if root_password and root_password.strip():
if root_password != root_password_confirm:
raise YunohostValidationError("password_confirmation_not_the_same")
from yunohost.tools import tools_rootpw
tools_rootpw(root_password, check_strength=True)
super()._apply()
settings = {
@ -122,7 +145,18 @@ class SettingsConfigPanel(ConfigPanel):
logger.error(f"Post-change hook for setting failed : {e}")
raise
def _load_current_values(self):
super()._load_current_values()
# Specific logic for those settings who are "virtual" settings
# and only meant to have a custom setter mapped to tools_rootpw
self.values["root_password"] = ""
self.values["root_password_confirm"] = ""
def get(self, key="", mode="classic"):
result = super().get(key=key, mode=mode)
if mode == "full":

View file

@ -94,6 +94,8 @@ def tools_rootpw(new_password, check_strength=True):
except (IOError, KeyError):
logger.warning(m18n.n("root_password_desynchronized"))
return
else:
logger.info(m18n.n("root_password_changed"))
def tools_maindomain(new_main_domain=None):

View file

@ -85,7 +85,7 @@ class PasswordValidator:
# from settings.py because this file is also meant to be
# use as a script by ssowat.
# (or at least that's my understanding -- Alex)
settings = yaml.load(open("/etc/yunohost/settings.yml", "r"))
settings = yaml.safe_load(open("/etc/yunohost/settings.yml", "r"))
setting_key = profile + "_strength"
self.validation_strength = int(settings[setting_key])
except Exception: