[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[firstboot] Use pwquality for password strength checking



---
 firstboot.spec         |    2 +-
 firstboot/pwcheck.py   |  124 +++++++++--------------------------------------
 modules/create_user.py |    6 ++-
 3 files changed, 29 insertions(+), 103 deletions(-)

diff --git a/firstboot.spec b/firstboot.spec
index 53f2101..283d94c 100644
--- a/firstboot.spec
+++ b/firstboot.spec
@@ -23,7 +23,7 @@ Requires: system-config-users >= 1.2.111-1
 Requires: authconfig-gtk, python-meh
 Requires: system-config-keyboard
 Requires: python-ethtool
-Requires: cracklib-python
+Requires: python-pwquality
 Requires(post): systemd-units systemd-sysv chkconfig
 Requires(preun): systemd-units
 Requires(postun): systemd-units
diff --git a/firstboot/pwcheck.py b/firstboot/pwcheck.py
index 3440a78..2d2d3dd 100644
--- a/firstboot/pwcheck.py
+++ b/firstboot/pwcheck.py
@@ -20,7 +20,7 @@
 #
 
 import re
-import cracklib
+import pwquality
 
 import pygtk
 pygtk.require("2.0")
@@ -34,125 +34,49 @@ import gettext
 _ = lambda x: gettext.ldgettext("firstboot", x)
 
 
-class PwError(Exception):
-    pass
-
-
-class PwRule(object):
-
-    def __init__(self, rule, weight=1, required=False, desc=""):
-        if callable(rule):
-            # is a func
-            self.rule = rule
-        else:
-            # is a regex
-            pattern = re.compile(rule)
-            self.rule = lambda x: bool(pattern.search(x))
-
-        if not weight:
-            raise PwError("weight must be a non-zero value")
-
-        self.weight = weight
-        self.required = required
-
-        self.desc = desc
-
-    @property
-    def include(self):
-        return self.weight > 0
-
-    @property
-    def exclude(self):
-        return self.weight < 0
-
-    def check(self, password):
-        passed = self.rule(password)
-
-        if ((self.include and self.required and not passed) or
-            (self.exclude and self.required and passed)):
-            logger.debug("%s: %d", self.desc, 0)
-            raise PwError("password does not meet required criteria")
-
-        if ((self.include and passed) or
-            (self.exclude and not passed)):
-            logger.debug("%s: %d", self.desc, self.weight)
-            return self.weight
-        else:
-            logger.debug("%s: %d", self.desc, 0)
-            return 0
+def clamp(value, lowerbound, upperbound):
+    return min(max(value, lowerbound), upperbound)
 
 
 class Password(object):
 
-    def cracklib_check(password):
-        try:
-            cracklib.FascistCheck(password)
-        except ValueError:
-            return False
-        else:
-            return True
-
-    RULES = [ PwRule(rule=lambda x: len(x) >= 4, weight=1, required=True,
-                     desc="4 characters or more"),
-              PwRule(rule=lambda x: len(x) >= 8, weight=1, required=False,
-                     desc="8 characters or more"),
-              PwRule(rule=lambda x: len(x) >= 12, weight=1, required=False,
-                     desc="12 characters or more"),
-              PwRule(rule=r"[a-z]+", weight=1, required=False,
-                     desc="at least one lowercase character"),
-              PwRule(rule=r"[A-Z]+", weight=1, required=False,
-                     desc="at least one uppercase character"),
-              PwRule(rule=r"[0-9]+", weight=1, required=False,
-                     desc="at least one digit"),
-              PwRule(rule=r"[^a-zA-Z0-9]+", weight=1, required=False,
-                     desc="at least one special character"),
-              PwRule(rule=cracklib_check, weight=-2, required=False,
-                     desc="cracklib") ]
-
-    MAX_STRENGTH = 7
+    MIN_STRENGTH = 0
+    MAX_STRENGTH = 100
 
     STRENGTH_STRINGS = [ _("Very weak"),
-                         _("Very weak"),
-                         _("Weak"),
                          _("Weak"),
                          _("Fairly strong"),
                          _("Strong"),
-                         _("Very strong"),
                          _("Very strong") ]
 
-    def __init__(self, password):
+    def __init__(self, password, username=None):
         self.password = password
+        self.username = username
+        self.pwq_settings = pwquality.PWQSettings()
+        self.pwq_settings.read_config()
 
-    @property
-    def strength(self):
-        strength = 0
-        for rule in self.RULES:
-            try:
-                strength += rule.check(self.password)
-            except PwError:
-                return 0
+        self.strength = self.MIN_STRENGTH
+        self.pwq_msg = ''
+        try:
+            self.strength = self.pwq_settings.check(self.password, None, self.username)
+        except pwquality.PWQError as (e, msg):
+            self.pwq_msg = msg
 
-        return strength
+        self.strength = clamp(self.strength, self.MIN_STRENGTH, self.MAX_STRENGTH)
 
     @property
-    def strength_string(self):
-        strength = self.strength
+    def strength_frac(self):
+        return float(self.strength) / self.MAX_STRENGTH
 
-        if strength < 0:
-            return self.STRENGTH_STRINGS[0]
+    @property
+    def strength_string(self):
+        strings_count = len(self.STRENGTH_STRINGS)
+        index = int(self.strength / (self.MAX_STRENGTH / strings_count))
 
         try:
-            return self.STRENGTH_STRINGS[strength]
+            return self.STRENGTH_STRINGS[index]
         except IndexError:
-            return _("Undefined")
-
-    @property
-    def strength_frac(self):
-        frac = float(self.strength) / self.MAX_STRENGTH
-        if frac > 1:
-            frac = 1.0
-
-        return frac
+            return self.STRENGTH_STRINGS[-1]
 
     def __str__(self):
         return "%s" % self.password
diff --git a/modules/create_user.py b/modules/create_user.py
index 3050852..4f1ebab 100644
--- a/modules/create_user.py
+++ b/modules/create_user.py
@@ -495,9 +495,11 @@ class moduleClass(Module):
             strengthLabel.set_fraction(0.0)
             return
 
-        pw = Password(pw)
-        strengthLabel.set_text('%s' % pw.strength_string)
+        username = self.usernameEntry.get_text() or None
+
+        pw = Password(pw, username)
         strengthLabel.set_fraction(pw.strength_frac)
+        strengthLabel.set_text('%s' % pw.strength_string)
 
     def confirmEntry_changed(self, entry, passwordEntry, confirmIcon):
         pw = passwordEntry.get_text()
-- 
1.7.5.4


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]