[PATCH 3/3] Allow non-ASCII characters in passwords (#960837)
David Shea
dshea at redhat.com
Fri May 9 20:19:22 UTC 2014
Warn about non-ASCII characters and how keymaps are important and
(maybe) not configurable at login, but let the user set a non-ASCII
password if they really want it.
---
pyanaconda/constants.py | 2 ++
pyanaconda/ui/gui/spokes/password.py | 28 ++++++++++++++++++++++++++--
pyanaconda/ui/gui/spokes/user.py | 27 +++++++++++++++++++++++++--
pyanaconda/ui/tui/spokes/__init__.py | 11 ++++++++++-
pyanaconda/users.py | 11 +----------
5 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/pyanaconda/constants.py b/pyanaconda/constants.py
index f44ef7e..2e84838 100644
--- a/pyanaconda/constants.py
+++ b/pyanaconda/constants.py
@@ -149,6 +149,8 @@ PASSWORD_WEAK = N_("The password you have provided is weak. You will have to pre
PASSWORD_WEAK_WITH_ERROR = N_("The password you have provided is weak: %s. You will have to press Done twice to confirm it.")
PASSWORD_WEAK_CONFIRM = N_("You have provided a weak password. Press Done again to use anyway.")
PASSWORD_WEAK_CONFIRM_WITH_ERROR = N_("You have provided a weak password: %s. Press Done again to use anyway.")
+PASSWORD_ASCII = N_("The password you have provided contains non-ASCII characters. You may not be able to switch between keyboard layouts to login. Press Done twice to continue.")
+PASSWORD_ASCII_CONFIRM = N_("The password you have provided contains non-ASCII characters. Press Done again to continue.")
PASSWORD_STRENGTH_DESC = [N_("Empty"), N_("Weak"), N_("Fair"), N_("Good"), N_("Strong")]
diff --git a/pyanaconda/ui/gui/spokes/password.py b/pyanaconda/ui/gui/spokes/password.py
index 3855758..a12e817 100644
--- a/pyanaconda/ui/gui/spokes/password.py
+++ b/pyanaconda/ui/gui/spokes/password.py
@@ -32,7 +32,8 @@ from pyanaconda.ui.helpers import InputCheck
from pyanaconda.constants import PASSWORD_EMPTY_ERROR, PASSWORD_CONFIRM_ERROR_GUI,\
PASSWORD_STRENGTH_DESC, PASSWORD_WEAK, PASSWORD_WEAK_WITH_ERROR,\
- PASSWORD_WEAK_CONFIRM, PASSWORD_WEAK_CONFIRM_WITH_ERROR
+ PASSWORD_WEAK_CONFIRM, PASSWORD_WEAK_CONFIRM_WITH_ERROR, PW_ASCII_CHARS, PASSWORD_ASCII,\
+ PASSWORD_ASCII_CONFIRM
__all__ = ["PasswordSpoke"]
@@ -63,6 +64,7 @@ class PasswordSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler)
# - Has a password been specified?
# - If a password has been specified and there is data in the confirm box, do they match?
# - How strong is the password?
+ # - Does the password contain non-ASCII characters?
# - Is there any data in the confirm box?
self.add_check(self.pw, self._checkPasswordEmpty)
@@ -75,9 +77,10 @@ class PasswordSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler)
self._confirm_check = self.add_check(self.confirm, self._checkPasswordConfirm)
self._password_check = self.add_check(self.pw, self._checkPasswordConfirm)
- # Keep a reference for this check, since it has to be manually run for the
+ # Keep a reference for these checks, since they have to be manually run for the
# click Done twice check.
self._pwStrengthCheck = self.add_check(self.pw, self._checkPasswordStrength)
+ self._pwASCIICheck = self.add_check(self.pw, self._checkPasswordASCII)
self.add_check(self.confirm, self._checkPasswordEmpty)
@@ -255,10 +258,31 @@ class PasswordSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler)
else:
return InputCheck.CHECK_OK
+ def _checkPasswordASCII(self, inputcheck):
+ """Set an error message if the password contains non-ASCII characters.
+
+ Like the password strength check, this check can be bypassed by
+ pressing Done twice.
+ """
+
+ # If Done has been clicked twice, waive the check
+ if self._waivePasswordClicks > 1:
+ return InputCheck.CHECK_OK
+
+ password = self.get_input(inputcheck.input_obj)
+ if password and any(char not in PW_ASCII_CHARS for char in password):
+ if self._waivePasswordClicks == 0:
+ return _(PASSWORD_ASCII)
+ else:
+ return _(PASSWORD_ASCII_CONFIRM)
+
+ return InputCheck.CHECK_OK
+
def on_back_clicked(self, button):
# Add a click and re-check the password strength
self._waivePasswordClicks += 1
self._pwStrengthCheck.update_check_status()
+ self._pwASCIICheck.update_check_status()
# If neither the password nor the confirm field are set, skip the checks
if (not self.pw.get_text()) and (not self.confirm.get_text()):
diff --git a/pyanaconda/ui/gui/spokes/user.py b/pyanaconda/ui/gui/spokes/user.py
index dd40c68..037e622 100644
--- a/pyanaconda/ui/gui/spokes/user.py
+++ b/pyanaconda/ui/gui/spokes/user.py
@@ -38,7 +38,7 @@ from pykickstart.constants import FIRSTBOOT_RECONFIG
from pyanaconda.constants import ANACONDA_ENVIRON, FIRSTBOOT_ENVIRON,\
PASSWORD_EMPTY_ERROR, PASSWORD_CONFIRM_ERROR_GUI, PASSWORD_STRENGTH_DESC,\
PASSWORD_WEAK, PASSWORD_WEAK_WITH_ERROR, PASSWORD_WEAK_CONFIRM,\
- PASSWORD_WEAK_CONFIRM_WITH_ERROR
+ PASSWORD_WEAK_CONFIRM_WITH_ERROR, PW_ASCII_CHARS, PASSWORD_ASCII, PASSWORD_ASCII_CONFIRM
from pyanaconda.regexes import GECOS_VALID, USERNAME_VALID, GROUPNAME_VALID, GROUPLIST_FANCY_PARSE
__all__ = ["UserSpoke", "AdvancedUserDialog"]
@@ -283,6 +283,7 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
# - if a password is required, is one specified?
# - if a password is specified and there is data in the confirm box, do they match?
# - if a password is specified and the confirm box is empty or match, how strong is it?
+ # - if a strong password is specified, does it contain non-ASCII data?
# - if a password is required, is there any data in the confirm box?
self.add_check(self.pw, self._checkPasswordEmpty)
@@ -295,9 +296,10 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
self._confirm_check = self.add_check(self.confirm, self._checkPasswordConfirm)
self._password_check = self.add_check(self.pw, self._checkPasswordConfirm)
- # Keep a reference to this check, since it has to be manually run for the
+ # Keep a reference to these checks, since they have to be manually run for the
# click Done twice check.
self._pwStrengthCheck = self.add_check(self.pw, self._checkPasswordStrength)
+ self._pwASCIICheck = self.add_check(self.pw, self._checkPasswordASCII)
self.add_check(self.confirm, self._checkPasswordEmpty)
@@ -562,6 +564,26 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
else:
return InputCheck.CHECK_OK
+ def _checkPasswordASCII(self, inputcheck):
+ """Set an error message if the password contains non-ASCII characters.
+
+ Like the password strength check, this check can be bypassed by
+ pressing Done twice.
+ """
+
+ # If Done has been clicked twice, waive the check
+ if self._waivePasswordClicks > 1:
+ return InputCheck.CHECK_OK
+
+ password = self.get_input(inputcheck.input_obj)
+ if password and any(char not in PW_ASCII_CHARS for char in password):
+ if self._waivePasswordClicks == 0:
+ return _(PASSWORD_ASCII)
+ else:
+ return _(PASSWORD_ASCII_CONFIRM)
+
+ return InputCheck.CHECK_OK
+
def on_advanced_clicked(self, _button, data=None):
"""Handler for the Advanced.. button. It starts the Advanced dialog
for setting homedit, uid, gid and groups.
@@ -586,6 +608,7 @@ class UserSpoke(FirstbootSpokeMixIn, NormalSpoke, GUISpokeInputCheckHandler):
# Add a click and re-check the password strength
self._waivePasswordClicks += 1
self._pwStrengthCheck.update_check_status()
+ self._pwASCIICheck.update_check_status()
# If there is no user set, skip the checks
if not self.username.get_text():
diff --git a/pyanaconda/ui/tui/spokes/__init__.py b/pyanaconda/ui/tui/spokes/__init__.py
index 75bc18c..21d726a 100644
--- a/pyanaconda/ui/tui/spokes/__init__.py
+++ b/pyanaconda/ui/tui/spokes/__init__.py
@@ -26,7 +26,7 @@ import re
from collections import namedtuple
from pyanaconda.iutil import setdeepattr, getdeepattr
from pyanaconda.i18n import N_, _
-from pyanaconda.constants import PASSWORD_CONFIRM_ERROR_TUI
+from pyanaconda.constants import PASSWORD_CONFIRM_ERROR_TUI, PW_ASCII_CHARS
__all__ = ["TUISpoke", "EditTUISpoke", "EditTUIDialog", "EditTUISpokeEntry",
"StandaloneSpoke", "NormalTUISpoke"]
@@ -146,6 +146,15 @@ class EditTUIDialog(NormalTUISpoke):
if not question_window.answer:
return None
+ if any(char not in PW_ASCII_CHARS for char in pw):
+ error = _("You have provided a password containing non-ASCII characters.\n"
+ "You may not be able to switch between keyboard layouts to login.\n"
+ "Would you like to use it anyway?")
+ question_window = YesNoDialog(self._app, error)
+ self._app.switch_screen_modal(question_window)
+ if not question_window.answer:
+ return None
+
self.value = cryptPassword(pw)
return None
else:
diff --git a/pyanaconda/users.py b/pyanaconda/users.py
index ca2a0c8..5cb884b 100644
--- a/pyanaconda/users.py
+++ b/pyanaconda/users.py
@@ -29,8 +29,7 @@ import os.path
from pyanaconda import iutil
import pwquality
from pyanaconda.iutil import strip_accents
-from pyanaconda.i18n import _
-from pyanaconda.constants import PASSWORD_MIN_LEN, PW_ASCII_CHARS
+from pyanaconda.constants import PASSWORD_MIN_LEN
import logging
log = logging.getLogger("anaconda")
@@ -162,14 +161,6 @@ def validatePassword(pw, user="root", settings=None):
validatePassword.pwqsettings.minlen = PASSWORD_MIN_LEN
settings = validatePassword.pwqsettings
- for letter in pw:
- if letter not in PW_ASCII_CHARS:
- message = _("Requested password contains "
- "non-ASCII characters, which are "
- "not allowed.")
- valid = False
- break
-
if valid:
try:
strength = settings.check(pw, None, user)
--
1.9.0
More information about the anaconda-patches
mailing list