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_pop3_enabled_help": "Enable the POP3 protocol for the mail server",
"global_settings_setting_postfix_compatibility": "Postfix Compatibility", "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_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": "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_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", "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_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_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", "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_allowed": "Group '{group}' already has permission '{permission}' enabled",
"permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled", "permission_already_disallowed": "Group '{group}' already has permission '{permission}' disabled",
"permission_already_exist": "Permission '{permission}' already exists", "permission_already_exist": "Permission '{permission}' already exists",
@ -637,6 +641,7 @@
"restore_running_hooks": "Running restoration hooks...", "restore_running_hooks": "Running restoration hooks...",
"restore_system_part_failed": "Could not restore the '{part}' system part", "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_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": "The server will reboot",
"server_reboot_confirm": "The server will reboot immediatly, are you sure? [{answers}]", "server_reboot_confirm": "The server will reboot immediatly, are you sure? [{answers}]",
"server_shutdown": "The server will shut down", "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.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.3 = "ditto, but also require at least one special char"
choices.4 = "ditto, but also require at least 12 chars" choices.4 = "ditto, but also require at least 12 chars"
default = 1 default = "1"
[security.password.user_strength] [security.password.user_strength]
type = "select" 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.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.3 = "ditto, but also require at least one special char"
choices.4 = "ditto, but also require at least 12 chars" choices.4 = "ditto, but also require at least 12 chars"
default = 1 default = "1"
[security.ssh] [security.ssh]
name = "SSH" name = "SSH"
@ -70,6 +70,24 @@ name = "Security"
optional = true optional = true
default = "" 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] [security.experimental]
name = "Experimental" name = "Experimental"
[security.experimental.security_experimental_enabled] [security.experimental.security_experimental_enabled]

View file

@ -108,6 +108,29 @@ class SettingsConfigPanel(ConfigPanel):
super().__init__("settings") super().__init__("settings")
def _apply(self): 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() super()._apply()
settings = { settings = {
@ -122,7 +145,18 @@ class SettingsConfigPanel(ConfigPanel):
logger.error(f"Post-change hook for setting failed : {e}") logger.error(f"Post-change hook for setting failed : {e}")
raise 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"): def get(self, key="", mode="classic"):
result = super().get(key=key, mode=mode) result = super().get(key=key, mode=mode)
if mode == "full": if mode == "full":

View file

@ -94,6 +94,8 @@ def tools_rootpw(new_password, check_strength=True):
except (IOError, KeyError): except (IOError, KeyError):
logger.warning(m18n.n("root_password_desynchronized")) logger.warning(m18n.n("root_password_desynchronized"))
return return
else:
logger.info(m18n.n("root_password_changed"))
def tools_maindomain(new_main_domain=None): 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 # from settings.py because this file is also meant to be
# use as a script by ssowat. # use as a script by ssowat.
# (or at least that's my understanding -- Alex) # (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" setting_key = profile + "_strength"
self.validation_strength = int(settings[setting_key]) self.validation_strength = int(settings[setting_key])
except Exception: except Exception: