7a6e0a
From 1a5c28b6546214054ca44e57dc0c21b9a8a73baa Mon Sep 17 00:00:00 2001
7a6e0a
From: Mark Reynolds <mreynolds@redhat.com>
7a6e0a
Date: Thu, 3 Mar 2022 16:29:41 -0500
7a6e0a
Subject: [PATCH 4/4] Issue 5221 - User with expired password can still login
7a6e0a
 with full privledges
7a6e0a
7a6e0a
Bug Description:
7a6e0a
7a6e0a
A user with an expired password can still login and perform operations
7a6e0a
with its typical access perimssions.  But an expired password means the
7a6e0a
account should be considered anonymous.
7a6e0a
7a6e0a
Fix Description:
7a6e0a
7a6e0a
Clear the bind credentials if the password is expired
7a6e0a
7a6e0a
relates: https://github.com/389ds/389-ds-base/issues/5221
7a6e0a
7a6e0a
Reviewed by: progier(Thanks!)
7a6e0a
---
7a6e0a
 .../suites/password/pw_expired_access_test.py | 62 +++++++++++++++++++
7a6e0a
 ldap/servers/slapd/pw_mgmt.c                  |  1 +
7a6e0a
 2 files changed, 63 insertions(+)
7a6e0a
 create mode 100644 dirsrvtests/tests/suites/password/pw_expired_access_test.py
7a6e0a
7a6e0a
diff --git a/dirsrvtests/tests/suites/password/pw_expired_access_test.py b/dirsrvtests/tests/suites/password/pw_expired_access_test.py
7a6e0a
new file mode 100644
7a6e0a
index 000000000..fb0afb190
7a6e0a
--- /dev/null
7a6e0a
+++ b/dirsrvtests/tests/suites/password/pw_expired_access_test.py
7a6e0a
@@ -0,0 +1,62 @@
7a6e0a
+import ldap
7a6e0a
+import logging
7a6e0a
+import pytest
7a6e0a
+import os
7a6e0a
+import time
7a6e0a
+from lib389._constants import DEFAULT_SUFFIX, PASSWORD
7a6e0a
+from lib389.idm.domain import Domain
7a6e0a
+from lib389.idm.user import UserAccounts
7a6e0a
+from lib389.topologies import topology_st as topo
7a6e0a
+
7a6e0a
+log = logging.getLogger(__name__)
7a6e0a
+
7a6e0a
+def test_expired_user_has_no_privledge(topo):
7a6e0a
+    """Specify a test case purpose or name here
7a6e0a
+
7a6e0a
+    :id: 3df86b45-9929-414b-9bf6-06c25301d207
7a6e0a
+    :setup: Standalone Instance
7a6e0a
+    :steps:
7a6e0a
+        1. Set short password expiration time
7a6e0a
+        2. Add user and wait for expiration time to run out
7a6e0a
+        3. Set one aci that allows authenticated users full access
7a6e0a
+        4. Bind as user (password should be expired)
7a6e0a
+        5. Attempt modify
7a6e0a
+    :expectedresults:
7a6e0a
+        1. Success
7a6e0a
+        2. Success
7a6e0a
+        3. Success
7a6e0a
+        4. Success
7a6e0a
+        5. Success
7a6e0a
+    """
7a6e0a
+
7a6e0a
+    # Configured password epxiration
7a6e0a
+    topo.standalone.config.replace_many(('passwordexp', 'on'), ('passwordmaxage', '1'))
7a6e0a
+
7a6e0a
+    # Set aci
7a6e0a
+    suffix = Domain(topo.standalone, DEFAULT_SUFFIX)
7a6e0a
+    ACI_TEXT = '(targetattr="*")(version 3.0; acl "test aci"; allow (all) (userdn="ldap:///all");)'
7a6e0a
+    suffix.replace('aci', ACI_TEXT)
7a6e0a
+
7a6e0a
+    # Add user
7a6e0a
+    user = UserAccounts(topo.standalone, DEFAULT_SUFFIX, rdn=None).create_test_user()
7a6e0a
+    user.replace('userpassword', PASSWORD)
7a6e0a
+    time.sleep(2)
7a6e0a
+
7a6e0a
+    # Bind as user with expired password.  Need to use raw ldap calls because
7a6e0a
+    # lib389 will close the connection when an error 49 is encountered.
7a6e0a
+    ldap_object = ldap.initialize(topo.standalone.toLDAPURL())
7a6e0a
+    with pytest.raises(ldap.INVALID_CREDENTIALS):
7a6e0a
+        res_type, res_data, res_msgid, res_ctrls = ldap_object.simple_bind_s(
7a6e0a
+            user.dn, PASSWORD)
7a6e0a
+
7a6e0a
+    # Try modify
7a6e0a
+    with pytest.raises(ldap.INSUFFICIENT_ACCESS):
7a6e0a
+        modlist = [ (ldap.MOD_REPLACE, 'description', b'Should not work!') ]
7a6e0a
+        ldap_object.modify_ext_s(DEFAULT_SUFFIX, modlist)
7a6e0a
+
7a6e0a
+
7a6e0a
+if __name__ == '__main__':
7a6e0a
+    # Run isolated
7a6e0a
+    # -s for DEBUG mode
7a6e0a
+    CURRENT_FILE = os.path.realpath(__file__)
7a6e0a
+    pytest.main(["-s", CURRENT_FILE])
7a6e0a
diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
7a6e0a
index ca76fc12f..f9b5a9add 100644
7a6e0a
--- a/ldap/servers/slapd/pw_mgmt.c
7a6e0a
+++ b/ldap/servers/slapd/pw_mgmt.c
7a6e0a
@@ -211,6 +211,7 @@ skip:
7a6e0a
             slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED);
7a6e0a
         }
7a6e0a
         slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
7a6e0a
+        bind_credentials_clear(pb_conn, PR_FALSE, PR_TRUE);
7a6e0a
         slapi_send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
7a6e0a
                                "password expired!", 0, NULL);
7a6e0a
 
7a6e0a
-- 
7a6e0a
2.31.1
7a6e0a