From 95b7b3a115c66794bf0adc2e8dce152aab25a716 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Fri, 4 Dec 2015 15:55:46 -0500 Subject: [PATCH] Ticket 48369 - RFE - Add config setting to always send the password expiring time Description: If password expiration time is set, and the password is not within the warning period, then the expiring time is not returned. A new config setting was added that will force the expiring time to always be returned when the password expiring request control is sent. https://fedorahosted.org/389/ticket/48369 Reviewed by: ? --- dirsrvtests/tickets/ticket48369_test.py | 124 ++++++++++++++++++++++++++++++++ ldap/schema/02common.ldif | 1 + ldap/servers/slapd/libglobs.c | 28 ++++++-- ldap/servers/slapd/proto-slap.h | 1 + ldap/servers/slapd/pw_mgmt.c | 5 ++ ldap/servers/slapd/slap.h | 2 + 6 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 dirsrvtests/tickets/ticket48369_test.py diff --git a/dirsrvtests/tickets/ticket48369_test.py b/dirsrvtests/tickets/ticket48369_test.py new file mode 100644 index 0000000..0b65fa2 --- /dev/null +++ b/dirsrvtests/tickets/ticket48369_test.py @@ -0,0 +1,124 @@ +import os +import time +import ldap +import logging +import pytest +from lib389 import DirSrv, Entry +from lib389._constants import * +from lib389.properties import * +from lib389.tasks import * +from lib389.utils import * +from ldap.controls.ppolicy import PasswordPolicyControl + + +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 test_ticket48369(topology): + """ + Test RFE 48369 - return password policy controls by default without needing + to be requested. + """ + + DN = 'uid=test,' + DEFAULT_SUFFIX + + # + # Setup password policy + # + try: + topology.standalone.modify_s('cn=config', [(ldap.MOD_REPLACE, + 'passwordExp', + 'on'), + (ldap.MOD_REPLACE, + 'passwordMaxAge', + '864000'), + (ldap.MOD_REPLACE, + 'passwordSendExpiringTime', + 'on')]) + except ldap.LDAPError as e: + log.fatal('Failed to set config: %s' % str(e)) + assert False + + # + # Add entry + # + try: + topology.standalone.add_s(Entry((DN, + {'objectclass': 'top extensibleObject'.split(), + 'uid': 'test', + 'userpassword': 'password'}))) + except ldap.LDAPError as e: + log.fatal('Failed to add user entry: %s' % str(e)) + assert False + time.sleep(1) + + # + # Bind as the new user, and request the control + # + try: + msgid = topology.standalone.simple_bind(DN, "password", + serverctrls=[PasswordPolicyControl()]) + res_type, res_data, res_msgid, res_ctrls = \ + topology.standalone.result3(msgid) + except ldap.LDAPError as e: + log.fatal('Failed to bind: %s: Error %s' % (ctl_resp, str(e))) + assert False + + if res_ctrls[0].controlType == PasswordPolicyControl.controlType: + ppolicy_ctrl = res_ctrls[0] + else: + log.fatal('Control not found') + assert False + + log.info('Time until expiration (%s)' % + repr(ppolicy_ctrl.timeBeforeExpiration)) + + log.info('Test complete') + + +if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode + CURRENT_FILE = os.path.realpath(__file__) + pytest.main("-s %s" % CURRENT_FILE) \ No newline at end of file diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif index 5d91628..dda75e7 100644 --- a/ldap/schema/02common.ldif +++ b/ldap/schema/02common.ldif @@ -67,6 +67,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2082 NAME ( 'passwordMinCategories' 'pwd attributeTypes: ( 2.16.840.1.113730.3.1.2083 NAME ( 'passwordMinTokenLength' 'pwdMinTokenLength' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2153 NAME ( 'passwordAdminDN' 'pwdAdminDN' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.2140 NAME ( 'passwordTrackUpdateTime' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) +attributeTypes: ( 2.16.840.1.113730.3.1.2329 NAME ( 'passwordSendExpiringTime' 'pwdSendExpiringTime' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' ) diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c index 2296720..4661964 100644 --- a/ldap/servers/slapd/libglobs.c +++ b/ldap/servers/slapd/libglobs.c @@ -193,6 +193,7 @@ slapi_onoff_t init_pw_is_legacy; slapi_onoff_t init_pw_track_update_time; slapi_onoff_t init_pw_change; slapi_onoff_t init_pw_exp; +slapi_onoff_t init_pw_send_expiring; slapi_onoff_t init_allow_hashed_pw; slapi_onoff_t init_pw_syntax; slapi_onoff_t init_schemacheck; @@ -661,6 +662,10 @@ static struct config_get_and_set { NULL, 0, (void**)&global_slapdFrontendConfig.pw_policy.pw_exp, CONFIG_ON_OFF, NULL, &init_pw_exp}, + {CONFIG_PW_SEND_EXPIRING, config_set_pw_send_expiring, + NULL, 0, + (void**)&global_slapdFrontendConfig.pw_policy.pw_send_expiring, + CONFIG_ON_OFF, NULL, &init_pw_send_expiring}, {CONFIG_ACCESSCONTROL_ATTRIBUTE, config_set_accesscontrol, NULL, 0, (void**)&global_slapdFrontendConfig.accesscontrol, @@ -1506,6 +1511,7 @@ FrontendConfig_init () { init_allow_hashed_pw = cfg->allow_hashed_pw = LDAP_OFF; init_pw_syntax = cfg->pw_policy.pw_syntax = LDAP_OFF; init_pw_exp = cfg->pw_policy.pw_exp = LDAP_OFF; + init_pw_send_expiring = cfg->pw_policy.pw_send_expiring = LDAP_OFF; cfg->pw_policy.pw_minlength = 8; cfg->pw_policy.pw_mindigits = 0; cfg->pw_policy.pw_minalphas = 0; @@ -3188,15 +3194,29 @@ config_set_pw_exp( const char *attrname, char *value, char *errorbuf, int apply slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); retVal = config_set_onoff ( attrname, - value, - &(slapdFrontendConfig->pw_policy.pw_exp), - errorbuf, - apply); + value, + &(slapdFrontendConfig->pw_policy.pw_exp), + errorbuf, + apply); return retVal; } int +config_set_pw_send_expiring( const char *attrname, char *value, char *errorbuf, int apply ) { + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); + + retVal = config_set_onoff ( attrname, + value, + &(slapdFrontendConfig->pw_policy.pw_send_expiring), + errorbuf, + apply); + + return retVal; +} + +int config_set_pw_unlock( const char *attrname, char *value, char *errorbuf, int apply ) { int retVal = LDAP_SUCCESS; slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h index 22e8007..0547bc7 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h @@ -329,6 +329,7 @@ int config_set_pw_is_legacy_policy(const char *attrname, char *value, char *err int config_set_pw_track_last_update_time(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_gracelimit(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_pw_admin_dn( const char *attrname, char *value, char *errorbuf, int apply ); +int config_set_pw_send_expiring( const char *attrname, char *value, char *errorbuf, int apply ); int config_set_useroc(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_return_exact_case(const char *attrname, char *value, char *errorbuf, int apply ); int config_set_result_tweak(const char *attrname, char *value, char *errorbuf, int apply ); diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c index a650b1c..5470556 100644 --- a/ldap/servers/slapd/pw_mgmt.c +++ b/ldap/servers/slapd/pw_mgmt.c @@ -235,6 +235,11 @@ skip: slapi_add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0); } return (2); + } else { + if (pwresponse_req && pwpolicy->pw_send_expiring) { + slapi_pwpolicy_make_response_control( pb, diff_t, -1, -1); + slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, diff_t); + } } pw_apply_mods(sdn, &smods); diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h index 3cc99cf..0b867ab 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -1551,6 +1551,7 @@ typedef struct passwordpolicyarray { int pw_mincategories; int pw_mintokenlength; slapi_onoff_t pw_exp; + slapi_onoff_t pw_send_expiring; long pw_maxage; long pw_minage; long pw_warning; @@ -2043,6 +2044,7 @@ typedef struct _slapdEntryPoints { #define CONFIG_PW_IS_LEGACY "passwordLegacyPolicy" #define CONFIG_PW_TRACK_LAST_UPDATE_TIME "passwordTrackUpdateTime" #define CONFIG_PW_ADMIN_DN_ATTRIBUTE "passwordAdminDN" +#define CONFIG_PW_SEND_EXPIRING "passwordSendExpiringTime" #define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering" #define CONFIG_CSNLOGGING_ATTRIBUTE "nsslapd-csnlogging" #define CONFIG_RETURN_EXACT_CASE_ATTRIBUTE "nsslapd-return-exact-case" -- 2.4.3