]> eyrie.org Git - kerberos/krb5-strength.git/commitdiff
Fix various character class check mistakes, add test suite
authorRuss Allbery <eagle@eyrie.org>
Fri, 13 Dec 2013 00:25:03 +0000 (16:25 -0800)
committerRuss Allbery <eagle@eyrie.org>
Fri, 13 Dec 2013 00:25:03 +0000 (16:25 -0800)
This is the first working version of the character class checking,
which is now plugged into the module initialization.  It also adds
a test suite for the external password check utility, although not
the embedded modules yet.

plugin/classes.c
plugin/config.c
plugin/general.c
tests/data/passwords/classes.json [new file with mode: 0644]
tests/tools/heimdal-strength-t

index 683b5de255e00da4d194fe8fa1d4d799dd3639f1..6e79d14d760c6a40bf15d1f782cc65d0b03ba3e7 100644 (file)
@@ -27,7 +27,7 @@ struct password_classes {
 
 /* Abbreviate the most common error reporting syntax. */
 #define MUST_HAVE(ctx, err) \
-    strength_error_class((ctx), "password must contain" err)
+    strength_error_class((ctx), "password must contain " err)
 
 
 /*
@@ -39,7 +39,8 @@ analyze_password(const char *password, struct password_classes *classes)
 {
     const char *p;
 
-    for (p = password; p != '\0'; p++) {
+    memset(classes, 0, sizeof(struct password_classes));
+    for (p = password; *p != '\0'; p++) {
         if (islower((unsigned char) *p))
             classes->lower = true;
         else if (isupper((unsigned char) *p))
@@ -68,9 +69,9 @@ check_rule(krb5_context ctx, struct class_rule *rule, size_t length,
     if (rule->upper && !classes->upper)
         return MUST_HAVE(ctx, "an uppercase letter");
     if (rule->digit && !classes->digit)
-        return MUST_HAVE(ctx, "a digit");
+        return MUST_HAVE(ctx, "a number");
     if (rule->symbol && !classes->symbol)
-        return MUST_HAVE(ctx, "a symbol");
+        return MUST_HAVE(ctx, "a space or punctuation character");
     return 0;
 }
 
index 70394b5093362684de8fabf989e77236ac4c2fe0..414de048fc6ab268d2bdd6837e7729ca61d3f7cd 100644 (file)
@@ -186,7 +186,7 @@ krb5_error_code
 strength_config_classes(krb5_context ctx, const char *opt,
                         struct class_rule **result)
 {
-    struct vector *config;
+    struct vector *config = NULL;
     struct class_rule *rules, *last, *tmp;
     krb5_error_code code;
     size_t i;
@@ -248,7 +248,7 @@ strength_config_list(krb5_context ctx, const char *opt,
 
     /* Obtain the string from [appdefaults]. */
     realm = default_realm(ctx);
-    krb5_appdefault_string(ctx, "krb5-sync", realm, opt, "", &value);
+    krb5_appdefault_string(ctx, "krb5-strength", realm, opt, "", &value);
     free_default_realm(ctx, realm);
 
     /* If we got something back, store it in result. */
index 4dde3eae5bfc57e6699270bc2d97aa0ae9d8ed6e..ca0c23c3f54c378a92c69a848c352fc217d399dd 100644 (file)
@@ -50,10 +50,15 @@ strength_init(krb5_context ctx, const char *dictionary,
     /* Get minimum length information from krb5.conf. */
     strength_config_number(ctx, "minimum_length", &data->minimum_length);
 
-    /* Get character class restrictions from krb5.conf. */
+    /* Get simple character class restrictions from krb5.conf. */
     strength_config_boolean(ctx, "require_ascii_printable", &data->ascii);
     strength_config_boolean(ctx, "require_non_letter", &data->nonletter);
 
+    /* Get complex character class restrictions from krb5.conf. */
+    code = strength_config_classes(ctx, "require_classes", &data->rules);
+    if (code != 0)
+        goto fail;
+
     /*
      * Try to initialize CDB and CrackLib dictionaries.  Both functions handle
      * their own configuration parsing and will do nothing if the
diff --git a/tests/data/passwords/classes.json b/tests/data/passwords/classes.json
new file mode 100644 (file)
index 0000000..b8dfbff
--- /dev/null
@@ -0,0 +1,40 @@
+[
+    {
+        "name": "no lowercase",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "PASSWORD98!",
+        "code": "KADM5_PASS_Q_CLASS",
+        "error": "password must contain a lowercase letter"
+    },
+    {
+        "name": "no uppercase",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "password98!",
+        "code": "KADM5_PASS_Q_CLASS",
+        "error": "password must contain an uppercase letter"
+    },
+    {
+        "name": "no digit",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "passwordXX!",
+        "code": "KADM5_PASS_Q_CLASS",
+        "error": "password must contain a number"
+    },
+    {
+        "name": "no symbol",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "passwordXX9",
+        "code": "KADM5_PASS_Q_CLASS",
+        "error": "password must contain a space or punctuation character"
+    },
+    {
+        "name": "all classes",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "passwordX9!"
+    },
+    {
+        "name": "all classes with space",
+        "principal": "test@EXAMPLE.ORG",
+        "password": "pass wordX9"
+    }
+]
index 918b884e0bbbf070af7d1f52634d6cbdae895597..769f5fc54c9e00dbe9ea159cfd41712dc10d6dc8 100755 (executable)
@@ -149,7 +149,7 @@ sub load_password_tests {
 # Load the password tests from JSON.  Accumulate a total count of tests for
 # the testing plan.
 my (%tests, $count);
-for my $type (qw(cdb cracklib length letter principal)) {
+for my $type (qw(cdb classes cracklib length letter principal)) {
     my $tests = load_password_tests("$type.json");
     $tests{$type} = $tests;
     $count += scalar(@{$tests});
@@ -197,12 +197,23 @@ $krb5_conf = create_krb5_conf(
 );
 local $ENV{KRB5_CONFIG} = $krb5_conf;
 
-# Run the character class tests.
+# Run the simple character class tests.
 note('Simple password character class checks');
 for my $test (@{ $tests{letter} }) {
     check_password($test);
 }
 
+# Install the krb5.conf file for complex character class restrictions.
+$krb5_conf
+  = create_krb5_conf({ require_classes => 'lower,upper,digit,symbol' });
+local $ENV{KRB5_CONFIG} = $krb5_conf;
+
+# Run the complex character class tests.
+note('Complex password character class checks');
+for my $test (@{ $tests{classes} }) {
+    check_password($test);
+}
+
 # Install the krb5.conf file with configuration pointing to the CDB
 # dictionary.
 my $cdb_database = test_file_path('data/wordlist.cdb');