This moves some common code up to users.py and then makes use of it from both the gui and the text password spokes. Tested many ways.
--jlk
This moves it to a more central spot so that it can be used by both the gui and the text spoke, or any other thing that wants to validate passwords. --- pyanaconda/users.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/pyanaconda/users.py b/pyanaconda/users.py index c10dd4a..f4d92d4 100644 --- a/pyanaconda/users.py +++ b/pyanaconda/users.py @@ -27,11 +27,15 @@ import tempfile import os import os.path import iutil +import pwquality from pyanaconda.constants import ROOT_PATH
import logging log = logging.getLogger("anaconda")
+import gettext +_ = lambda x: gettext.ldgettext("anaconda", x) + def createLuserConf(instPath, algoname='sha512'): """ Writes a libuser.conf for instPath.
@@ -111,6 +115,40 @@ def cryptPassword(password, algo=None):
return crypt.crypt (password, saltstr)
+def validatePassword(pw, confirm, minlen=6): + # Do various steps to validate the password + # Return an error string, or None for no errors + # If inital checks pass, pwquality will be tested. Raises + # from pwquality will pass up to the calling code + + # if both pw and confirm are blank, password is disabled. + if (pw and not confirm) or (confirm and not pw): + error = _("You must enter your root password " + "and confirm it by typing it a second " + "time to continue.") + return error + + if pw != confirm: + error = _("The passwords you entered were " + "different. Please try again.") + return error + + legal = string.digits + string.ascii_letters + string.punctuation + " " + for letter in pw: + if letter not in legal: + error = _("Requested password contains " + "non-ASCII characters, which are " + "not allowed.") + return error + + if pw: + settings = pwquality.PWQSettings() + settings.read_config() + settings.minlen = minlen + settings.check(pw, None, "root") + + return None + class Users: def __init__ (self): self.admin = libuser.admin()
On Thu, 2012-10-11 at 19:21 -0700, Jesse Keating wrote:
+def validatePassword(pw, confirm, minlen=6):
- # Do various steps to validate the password
- # Return an error string, or None for no errors
- # If inital checks pass, pwquality will be tested. Raises
- # from pwquality will pass up to the calling code
- # if both pw and confirm are blank, password is disabled.
- if (pw and not confirm) or (confirm and not pw):
error = _("You must enter your root password "
"and confirm it by typing it a second "
"time to continue.")
return error
- if pw != confirm:
error = _("The passwords you entered were "
"different. Please try again.")
return error
- legal = string.digits + string.ascii_letters + string.punctuation + " "
- for letter in pw:
if letter not in legal:
error = _("Requested password contains "
"non-ASCII characters, which are "
"not allowed.")
return error
You could replace for and if with:
if not all(letter in legal for letter in pw)
But I guess both are equally good, so it's up to you.
Errors bring returned is a simple mismatch or invalid chars, which we can't allow. Raised items are actual quality issues which the user could use anyway. --- pyanaconda/ui/gui/spokes/password.py | 54 ++++++++++-------------------------- 1 file changed, 15 insertions(+), 39 deletions(-)
diff --git a/pyanaconda/ui/gui/spokes/password.py b/pyanaconda/ui/gui/spokes/password.py index 74acd4e..c67afb6 100644 --- a/pyanaconda/ui/gui/spokes/password.py +++ b/pyanaconda/ui/gui/spokes/password.py @@ -25,8 +25,8 @@ N_ = lambda x: x
from gi.repository import Gtk
-from pyanaconda.users import cryptPassword -import pwquality +from pyanaconda.users import cryptPassword, validatePassword +from pwquality import PWQError import string
from pyanaconda.ui.gui.spokes import NormalSpoke @@ -101,49 +101,25 @@ class PasswordSpoke(NormalSpoke): # Do various steps to validate the password # sets self._error to an error string # Return True if valid, False otherwise + self._error = False pw = self.pw.get_text() confirm = self.confirm.get_text()
- # if both pw and confirm are blank, password is disabled. - if (pw and not confirm) or (confirm and not pw): - self._error = _("You must enter your root password " - "and confirm it by typing it a second " - "time to continue.") - return False - - if pw != confirm: - self._error = _("The passwords you entered were " - "different. Please try again.") - return False + try: + self._error = validatePassword(pw, confirm) + except PWQError as (e, msg): + if pw == self._oldweak: + # We got a second attempt with the same weak password + pass + else: + self._error = _("You have provided a weak password: %s. " + " Press Done again to use anyway.") % msg + self._oldweak = pw + return False
- if pw and len(pw) < 6: - self._error = _("The root password must be at least " - "six characters long.") + if self._error: return False
- if pw: - try: - settings = pwquality.PWQSettings() - settings.read_config() - settings.check(pw, None, "root") - except pwquality.PWQError as (e, msg): - if pw == self._oldweak: - # We got a second attempt with the same weak password - pass - else: - self._error = _("You have provided a weak password: %s. " - " Press Done again to use anyway.") % msg - self._oldweak = pw - return False - - legal = string.digits + string.ascii_letters + string.punctuation + " " - for letter in pw: - if letter not in legal: - self._error = _("Requested password contains " - "non-ASCII characters, which are " - "not allowed.") - return False - # if no errors, clear the info for next time we go into the spoke self._password = pw self.window.clear_info()
This brings it up to feature parity with the gui spoke, mostly. Still don't have a way to completely disable the password here, but that's a good thing for now. --- pyanaconda/ui/tui/spokes/password.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/pyanaconda/ui/tui/spokes/password.py b/pyanaconda/ui/tui/spokes/password.py index b556af2..8942e17 100644 --- a/pyanaconda/ui/tui/spokes/password.py +++ b/pyanaconda/ui/tui/spokes/password.py @@ -17,11 +17,14 @@ # Red Hat, Inc. # # Red Hat Author(s): Martin Sivak msivak@redhat.com +# Jesse Keating jkeating@redhat.com #
from pyanaconda.ui.tui.spokes import NormalTUISpoke from pyanaconda.ui.tui.simpleline import TextWidget -from pyanaconda.flags import flags +from pyanaconda.ui.tui import YesNoDialog +from pyanaconda.users import validatePassword +from pwquality import PWQError import getpass
import gettext @@ -58,17 +61,29 @@ class PasswordSpoke(NormalTUISpoke):
def prompt(self, args = None): """Overriden prompt as password typing is special.""" - p1 = getpass.getpass(_("Password: ")) - p2 = getpass.getpass(_("Password (confirm): ")) + pw = getpass.getpass(_("Password: ")) + confirm = getpass.getpass(_("Password (confirm): "))
- if p1 != p2: - print _("Passwords do not match!") - else: - self._password = p1 - self.apply() + error = None + # just returning an error is either blank or mismatched + # passwords. Raising is because of poor quality. + try: + error = validatePassword(pw, confirm) + if error: + print(error) + return None + except PWQError as (e, msg): + error = _("You have provided a weak password: %s. " % msg) + error += _("\nWould 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._password = pw + self.apply()
self.close() - #return None
def apply(self): self.data.rootpw.password = self._password
Apart from the one rather cosmetic suggestion, these all look good to me.
On Thu, 2012-10-11 at 19:21 -0700, Jesse Keating wrote:
This moves some common code up to users.py and then makes use of it from both the gui and the text password spokes. Tested many ways.
--jlk
anaconda-patches mailing list anaconda-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/anaconda-patches
anaconda-patches@lists.fedorahosted.org