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

[firstboot 1/2] Add the pwcheck module for getting the password strength



pwcheck returns the strength of a password in an interval
of 0 to 7, 0 meaning weak, and 7 strong. It also has a
mapping of string representations of these strength values,
so we can show this information to the user.
---
 firstboot/pwcheck.py |  123 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 123 insertions(+), 0 deletions(-)
 create mode 100644 firstboot/pwcheck.py

diff --git a/firstboot/pwcheck.py b/firstboot/pwcheck.py
new file mode 100644
index 0000000..6aae573
--- /dev/null
+++ b/firstboot/pwcheck.py
@@ -0,0 +1,123 @@
+import re
+import cracklib
+
+import logging
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger("pwcheck")
+
+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
+
+
+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=-1, required=False,
+                     desc="cracklib") ]
+
+    STRENGTH_STRINGS = [ _("Very weak"),
+                         _("Very weak"),
+                         _("Weak"),
+                         _("Weak"),
+                         _("Fairly strong"),
+                         _("Strong"),
+                         _("Very strong"),
+                         _("Very strong") ]
+
+    def __init__(self, password):
+        self.password = password
+
+    @property
+    def strength(self):
+        strength = 0
+        for rule in self.RULES:
+            try:
+                strength += rule.check(self.password)
+            except PwError:
+                return 0
+
+        return strength
+
+    @property
+    def strength_string(self):
+        strength = self.strength
+
+        if strength < 0:
+            return self.STRENGTH_STRINGS[0]
+
+        try:
+            return self.STRENGTH_STRINGS[strength]
+        except IndexError:
+            return _("Undefined")
+
+    def __str__(self):
+        return "%s" % self.password
-- 
1.7.1.1


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