[enh] Check password in cli/api

This commit is contained in:
ljf 2018-08-27 03:40:50 +02:00
parent cda8bcf206
commit 06276a621b
5 changed files with 51 additions and 10 deletions

View file

@ -1489,6 +1489,9 @@ tools:
--ignore-dyndns: --ignore-dyndns:
help: Do not subscribe domain to a DynDNS service help: Do not subscribe domain to a DynDNS service
action: store_true action: store_true
--force-password:
help: Use this if you really want to set a weak password
action: store_true
### tools_update() ### tools_update()
update: update:

View file

@ -2251,6 +2251,9 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
raise MoulinetteError(errno.EINVAL, raise MoulinetteError(errno.EINVAL,
m18n.n('app_argument_choice_invalid', m18n.n('app_argument_choice_invalid',
name=arg_name, choices='yes, no, y, n, 1, 0')) name=arg_name, choices='yes, no, y, n, 1, 0'))
elif arg_type == 'password':
from yunohost.tools import _check_password
_check_password(arg_value)
args_dict[arg_name] = arg_value args_dict[arg_name] = arg_value
# END loop over action_args... # END loop over action_args...

View file

@ -35,6 +35,12 @@ DEFAULTS = OrderedDict([
("example.int", {"type": "int", "default": 42}), ("example.int", {"type": "int", "default": 42}),
("example.string", {"type": "string", "default": "yolo swag"}), ("example.string", {"type": "string", "default": "yolo swag"}),
("example.enum", {"type": "enum", "default": "a", "choices": ["a", "b", "c"]}), ("example.enum", {"type": "enum", "default": "a", "choices": ["a", "b", "c"]}),
# Control the way password are checked
# -1 No control
# 0 Just display weak password info in debug
# 1 Warn user about weak password
# 2 Raise an error when the user put a weak password
("security.password.check_mode", {"type": "int", "default": 2}),
]) ])
@ -90,9 +96,12 @@ def settings_set(key, value):
received_type=type(value).__name__, expected_type=key_type)) received_type=type(value).__name__, expected_type=key_type))
elif key_type == "int": elif key_type == "int":
if not isinstance(value, int) or isinstance(value, bool): if not isinstance(value, int) or isinstance(value, bool):
raise MoulinetteError(errno.EINVAL, m18n.n( if isinstance(value, str):
'global_settings_bad_type_for_setting', setting=key, value=int(value)
received_type=type(value).__name__, expected_type=key_type)) else:
raise MoulinetteError(errno.EINVAL, m18n.n(
'global_settings_bad_type_for_setting', setting=key,
received_type=type(value).__name__, expected_type=key_type))
elif key_type == "string": elif key_type == "string":
if not isinstance(value, basestring): if not isinstance(value, basestring):
raise MoulinetteError(errno.EINVAL, m18n.n( raise MoulinetteError(errno.EINVAL, m18n.n(

View file

@ -32,6 +32,7 @@ import logging
import subprocess import subprocess
import pwd import pwd
import socket import socket
import cracklib
from xmlrpclib import Fault from xmlrpclib import Fault
from importlib import import_module from importlib import import_module
from collections import OrderedDict from collections import OrderedDict
@ -53,6 +54,7 @@ from yunohost.monitor import monitor_disk, monitor_system
from yunohost.utils.packages import ynh_packages_version from yunohost.utils.packages import ynh_packages_version
from yunohost.utils.network import get_public_ip from yunohost.utils.network import get_public_ip
from yunohost.log import is_unit_operation, OperationLogger from yunohost.log import is_unit_operation, OperationLogger
from yunohost.settings import settings_get
# FIXME this is a duplicate from apps.py # FIXME this is a duplicate from apps.py
APPS_SETTING_PATH = '/etc/yunohost/apps/' APPS_SETTING_PATH = '/etc/yunohost/apps/'
@ -127,6 +129,8 @@ def tools_adminpw(auth, new_password):
""" """
from yunohost.user import _hash_user_password from yunohost.user import _hash_user_password
_check_password(new_password)
try: try:
auth.update("cn=admin", { auth.update("cn=admin", {
"userPassword": _hash_user_password(new_password), "userPassword": _hash_user_password(new_password),
@ -250,7 +254,8 @@ def _is_inside_container():
@is_unit_operation() @is_unit_operation()
def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False): def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
force_password=False):
""" """
YunoHost post-install YunoHost post-install
@ -268,6 +273,10 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False):
raise MoulinetteError(errno.EPERM, raise MoulinetteError(errno.EPERM,
m18n.n('yunohost_already_installed')) m18n.n('yunohost_already_installed'))
# Check password
if not force_password:
_check_password(password)
if not ignore_dyndns: if not ignore_dyndns:
# Check if yunohost dyndns can handle the given domain # Check if yunohost dyndns can handle the given domain
# (i.e. is it a .nohost.me ? a .noho.st ?) # (i.e. is it a .nohost.me ? a .noho.st ?)
@ -299,6 +308,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False):
else: else:
dyndns = False dyndns = False
operation_logger.start() operation_logger.start()
logger.info(m18n.n('yunohost_installing')) logger.info(m18n.n('yunohost_installing'))
@ -1046,3 +1056,24 @@ class Migration(object):
@property @property
def description(self): def description(self):
return m18n.n("migration_description_%s" % self.id) return m18n.n("migration_description_%s" % self.id)
def _check_password(password):
security_level = settings_get('security.password.check_mode')
if security_level == -1:
return
try:
if password in ["yunohost", "olinuxino", "olinux"]:
raise MoulinetteError(errno.EINVAL, m18n.n('password_too_weak') +
' : it is based on a (reversed) dictionary word' )
try:
cracklib.VeryFascistCheck(password)
except ValueError as e:
raise MoulinetteError(errno.EINVAL, m18n.n('password_too_weak') + " : " + str(e) )
except MoulinetteError as e:
if security_level >= 2:
raise
elif security_level == 1:
logger.warn(e.strerror)
else:
logger.debug(e.strerror)

View file

@ -39,15 +39,10 @@ from moulinette.core import MoulinetteError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from yunohost.service import service_status from yunohost.service import service_status
from yunohost.log import is_unit_operation from yunohost.log import is_unit_operation
from yunohost.tools import _check_password
logger = getActionLogger('yunohost.user') logger = getActionLogger('yunohost.user')
def _check_password(password):
try:
cracklib.VeryFascistCheck(password)
except ValueError as e:
raise MoulinetteError(errno.EINVAL, m18n.n('password_too_weak') + " : " + str(e) )
def user_list(auth, fields=None): def user_list(auth, fields=None):
""" """
List users List users