Wednesday, August 31, 2016

[389-commits] 2 commits - dirsrvtests/tests ldap/servers

dirsrvtests/tests/tickets/ticket48896_test.py | 181 ++++++++++++++++++++++++++
ldap/servers/slapd/modify.c | 3
ldap/servers/slapd/pw.c | 43 ++++--
ldap/servers/slapd/slapi-plugin.h | 4
ldap/servers/slapd/utf8.c | 46 ++++++
5 files changed, 266 insertions(+), 11 deletions(-)

New commits:
commit 19e75b97d2d54f082d518843e3d09f2da2deb1a6
Author: Noriko Hosoi <nhosoi@redhat.com>
Date: Wed Jun 22 18:17:15 2016 -0700

Ticket #48896 - CI test: test case for ticket 48896

Description: Default Setting for passwordMinTokenLength does not work

diff --git a/dirsrvtests/tests/tickets/ticket48896_test.py b/dirsrvtests/tests/tickets/ticket48896_test.py
new file mode 100644
index 0000000..b2675ec
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket48896_test.py
@@ -0,0 +1,181 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2016 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+log = logging.getLogger(__name__)
+
+installation1_prefix = None
+
+CONFIG_DN = 'cn=config'
+UID = 'buser123'
+TESTDN = 'uid=%s,' % UID + DEFAULT_SUFFIX
+
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+log = logging.getLogger(__name__)
+
+installation1_prefix = None
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+@pytest.fixture(scope="module")
+def topology(request):
+ global installation1_prefix
+ if installation1_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
+
+ # Creating standalone instance ...
+ standalone = DirSrv(verbose=False)
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ standalone.delete()
+ standalone.create()
+ standalone.open()
+
+ # Delete each instance in the end
+ def fin():
+ standalone.delete()
+ request.addfinalizer(fin)
+
+ # Clear out the tmp dir
+ standalone.clearTmpDir(__file__)
+
+ return TopologyStandalone(standalone)
+
+def check_attr_val(topology, dn, attr, expected):
+ try:
+ centry = topology.standalone.search_s(dn, ldap.SCOPE_BASE, 'cn=*')
+ if centry:
+ val = centry[0].getValue(attr)
+ if val == expected:
+ log.info('Default value of %s is %s' % (attr, expected))
+ else:
+ log.info('Default value of %s is not %s, but %s' % (attr, expected, val))
+ assert False
+ else:
+ log.fatal('Failed to get %s' % dn)
+ assert False
+ except ldap.LDAPError as e:
+ log.fatal('Failed to search ' + dn + ': ' + e.message['desc'])
+ assert False
+
+def replace_pw(server, curpw, newpw, expstr, rc):
+ log.info('Binding as {%s, %s}' % (TESTDN, curpw))
+ server.simple_bind_s(TESTDN, curpw)
+
+ hit = 0
+ log.info('Replacing password: %s -> %s, which should %s' % (curpw, newpw, expstr))
+ try:
+ server.modify_s(TESTDN, [(ldap.MOD_REPLACE, 'userPassword', newpw)])
+ except Exception as e:
+ log.info("Exception (expected): %s" % type(e).__name__)
+ hit = 1
+ assert isinstance(e, rc)
+
+ if (0 != rc) and (0 == hit):
+ log.info('Expected to fail with %d, but passed' % rc)
+ assert False
+
+ log.info('PASSED')
+
+def test_ticket48896(topology):
+ """
+ """
+ log.info('Testing Ticket 48896 - Default Setting for passwordMinTokenLength does not work')
+
+ log.info("Setting global password policy with password syntax.")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+
+ config = topology.standalone.search_s(CONFIG_DN, ldap.SCOPE_BASE, 'cn=*')
+ mintokenlen = config[0].getValue('passwordMinTokenLength')
+ history = config[0].getValue('passwordInHistory')
+
+ log.info('Default passwordMinTokenLength == %s' % mintokenlen)
+ log.info('Default passwordInHistory == %s' % history)
+
+ log.info('Adding a user.')
+ curpw = 'password'
+ topology.standalone.add_s(Entry((TESTDN,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test user',
+ 'sn': 'user',
+ 'userPassword': curpw})))
+
+ newpw = 'Abcd012+'
+ exp = 'be ok'
+ rc = 0
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = 'user'
+ exp = 'fail'
+ rc = ldap.CONSTRAINT_VIOLATION
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = UID
+ exp = 'fail'
+ rc = ldap.CONSTRAINT_VIOLATION
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = 'Tuse!1234'
+ exp = 'fail'
+ rc = ldap.CONSTRAINT_VIOLATION
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = 'Tuse!0987'
+ exp = 'fail'
+ rc = ldap.CONSTRAINT_VIOLATION
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = 'Tabc!1234'
+ exp = 'fail'
+ rc = ldap.CONSTRAINT_VIOLATION
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ curpw = 'Abcd012+'
+ newpw = 'Direc+ory389'
+ exp = 'be ok'
+ rc = 0
+ replace_pw(topology.standalone, curpw, newpw, exp, rc)
+
+ log.info('SUCCESS')
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)


commit 054f3ce507650935a54582141abac235fd1b0c00
Author: Noriko Hosoi <nhosoi@redhat.com>
Date: Wed Jun 22 17:38:08 2016 -0700

Ticket #48896 - Default Setting for passwordMinTokenLength does not work

Description: passwordMinTokenLength is supposed to be used for the
length of comparison between the substring of obvious strings and
a new password. But it was not used to generate substrings. This
patch implements it.

Also, old_pw was leaked in modify if password history was not enabled.

https://fedorahosted.org/389/ticket/48896

Reviewed by mreynolds@redhat.com (Thank you, Mark!)

diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
index 72f2db4..2be6930 100644
--- a/ldap/servers/slapd/modify.c
+++ b/ldap/servers/slapd/modify.c
@@ -390,7 +390,8 @@ do_modify( Slapi_PBlock *pb )
ldap_mods_free (normalized_mods, 1 /* Free the Array and the Elements */);

free_and_return:;
- slapi_ch_free ((void**)&rawdn);
+ slapi_ch_free_string(&old_pw);
+ slapi_ch_free_string(&rawdn);
slapi_mods_done(&smods);
}

diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 7658064..ed83ded 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -621,7 +621,6 @@ update_pw_info ( Slapi_PBlock *pb , char *old_pw)
/* update passwordHistory */
if ( old_pw != NULL && pwpolicy->pw_history == 1 ) {
(void)update_pw_history(pb, sdn, old_pw);
- slapi_ch_free ( (void**)&old_pw );
}

/* Update the "pwdUpdateTime" attribute */
@@ -1046,9 +1045,13 @@ retry:
* This is because password policy assumes that there's only one
* password in the userpassword attribute.
*/
- *old_pw = slapi_ch_strdup(slapi_value_get_string(va[0]));
+ if (old_pw) {
+ *old_pw = slapi_ch_strdup(slapi_value_get_string(va[0]));
+ }
} else {
- *old_pw = NULL;
+ if (old_pw) {
+ *old_pw = NULL;
+ }
}
}
}
@@ -1472,13 +1475,13 @@ check_trivial_words (Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Value **vals, char
{
/* Add new value to valueset */
valp = slapi_value_new_berval( bvp );
- slapi_valueset_add_value_ext( vs, valp, SLAPI_VALUE_FLAG_PASSIN );
+ slapi_valueset_add_value_ext( vs, valp, SLAPI_VALUE_FLAG_PASSIN );
valp = NULL;
}
}
}
/* Free smod */
- slapi_mod_free(&smod);
+ slapi_mod_free(&smod);
smod = NULL;
smodp = NULL;
}
@@ -1490,17 +1493,37 @@ check_trivial_words (Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Value **vals, char
(i != -1) && (valp != NULL);
i = slapi_valueset_next_value( vs, i, &valp) )
{
+ char *sp, *ep, *wp;
+ int found = 0;
/* If the value is smaller than the max token length,
* we don't need to check the password */
if ( (int)ldap_utf8characters(slapi_value_get_string( valp )) < toklen )
continue;

+ sp = slapi_ch_strdup(slapi_value_get_string(valp));
+ ep = sp + strlen(sp);
+ ep = ldap_utf8prevn(sp, ep, toklen);
+ if (!ep || (sp >= ep)) {
+ continue;
+ }
/* See if the password contains the value */
- if ( PL_strcasestr( slapi_value_get_string( vals[0] ),
- slapi_value_get_string( valp ) ) )
- {
- if ( pwresponse_req == 1 )
- {
+ for (wp = sp; wp && (wp <= ep); wp = ldap_utf8next(wp)) {
+ char *tp = ldap_utf8nextn(wp, toklen);
+ char c;
+ if (tp) {
+ c = *tp;
+ *tp = '\0';
+ } else {
+ break;
+ }
+ if (PL_strcasestr(slapi_value_get_string(vals[0]), wp)) {
+ found = 1;
+ }
+ *tp = c;
+ }
+ slapi_ch_free_string(&sp);
+ if (found) {
+ if ( pwresponse_req == 1 ) {
slapi_pwpolicy_make_response_control ( pb, -1, -1,
LDAP_PWPOLICY_INVALIDPWDSYNTAX );
}
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 89853c0..7022e59 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7455,6 +7455,10 @@ int ldap_utf8len( const char* );
char *ldap_utf8next( char* );
/* find previous character */
char *ldap_utf8prev( char* );
+/* find n-th character */
+char *ldap_utf8nextn (char* s, int n);
+/* find n-th previous character from "from" */
+char *ldap_utf8prevn (char *s, char *from, int n);
/* copy one character */
int ldap_utf8copy( char* dst, const char* src );
/* total number of characters */
diff --git a/ldap/servers/slapd/utf8.c b/ldap/servers/slapd/utf8.c
index a1330ee..27843c0 100644
--- a/ldap/servers/slapd/utf8.c
+++ b/ldap/servers/slapd/utf8.c
@@ -93,6 +93,52 @@ ldap_utf8prev (char* s)
return (char*) prev;
}

+/*
+ * Return a pointer to the n-th character following *s.
+ * Handle any valid UTF-8 character, including '\0' and ASCII.
+ * Try to handle a misaligned pointer or a malformed character.
+ * If the n-th character is beyond the string, it returns NULL.
+ */
+char*
+ldap_utf8nextn (char* s, int n)
+{
+ char *endp;
+ char *next = s;
+ if (!s) {
+ return NULL;
+ }
+ endp = s + strlen(s);
+ for ( ;n > 0; --n) {
+ next = ldap_utf8next(next);
+ if ((next > endp) && (n > 0)) {
+ return NULL;
+ }
+ }
+ return next;
+}
+
+/*
+ * Return a pointer to the n-th character preceding *from.
+ * Handle any valid UTF-8 character, including '\0' and ASCII.
+ * Try to handle a misaligned pointer or a malformed character.
+ * If the n-th previous character is beyond the start address, it returns NULL.
+ */
+char*
+ldap_utf8prevn (char *s, char *from, int n)
+{
+ char *prev = from;
+ if (!s || !from || (s > from)) {
+ return NULL;
+ }
+ for ( ;n > 0; --n) {
+ prev = ldap_utf8prev(prev);
+ if ((prev <= s) && (n > 0)) {
+ return NULL;
+ }
+ }
+ return prev;
+}
+
int
ldap_utf8copy (char* dst, const char* src)
/* Copy a character from src to dst; return the number of char's copied.

--
389-commits mailing list
389-commits@lists.fedoraproject.org
https://lists.fedoraproject.org/admin/lists/389-commits@lists.fedoraproject.org

No comments:

Post a Comment