2017-03-20 23:59:45 +03:00
# Unix SMB/CIFS implementation.
# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
""" Tests for the Auth and AuthZ logging of password changes.
"""
import samba . tests
from samba . samdb import SamDB
from samba . auth import system_session
import os
import samba . tests . auth_log_base
from samba . tests import delete_force
from samba . net import Net
import samba
2017-03-17 05:58:17 +03:00
from ldb import LdbError
2018-05-11 02:03:03 +03:00
from samba . tests . password_test import PasswordCommon
2018-12-13 00:20:28 +03:00
from samba . dcerpc . windows_event_ids import (
EVT_ID_SUCCESSFUL_LOGON ,
2018-12-13 04:46:31 +03:00
EVT_ID_UNSUCCESSFUL_LOGON ,
EVT_LOGON_NETWORK
2018-12-13 00:20:28 +03:00
)
2017-03-20 23:59:45 +03:00
USER_NAME = " authlogtestuser "
2018-04-30 01:35:25 +03:00
USER_PASS = samba . generate_random_password ( 32 , 32 )
2017-03-20 23:59:45 +03:00
class AuthLogPassChangeTests ( samba . tests . auth_log_base . AuthLogTestBase ) :
def setUp ( self ) :
2023-11-28 06:38:22 +03:00
super ( ) . setUp ( )
2017-03-20 23:59:45 +03:00
self . server_ip = os . environ [ " SERVER_IP " ]
host = " ldap:// %s " % os . environ [ " SERVER " ]
self . ldb = SamDB ( url = host ,
session_info = system_session ( ) ,
credentials = self . get_credentials ( ) ,
lp = self . get_loadparm ( ) )
2018-05-11 02:03:03 +03:00
# permit password changes during this test
PasswordCommon . allow_password_changes ( self , self . ldb )
2017-03-20 23:59:45 +03:00
self . base_dn = self . ldb . domain_dn ( )
# (Re)adds the test user USER_NAME with password USER_PASS
delete_force ( self . ldb , " cn= " + USER_NAME + " ,cn=users, " + self . base_dn )
self . ldb . add ( {
2018-04-30 01:35:25 +03:00
" dn " : " cn= " + USER_NAME + " ,cn=users, " + self . base_dn ,
" objectclass " : " user " ,
" sAMAccountName " : USER_NAME ,
" userPassword " : USER_PASS
2017-03-24 03:52:58 +03:00
} )
2017-03-20 23:59:45 +03:00
# discard any auth log messages for the password setup
2023-05-25 03:16:32 +03:00
type ( self ) . discardMessages ( )
2022-10-21 19:14:44 +03:00
def _authDescription ( self ) :
2022-10-26 23:57:06 +03:00
return " samr_ChangePasswordUser4 "
2017-03-20 23:59:45 +03:00
def test_admin_change_password ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] == " NT_STATUS_OK " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" SAMR Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2022-10-21 19:14:44 +03:00
self . _authDescription ( ) ) and
2018-12-13 00:20:28 +03:00
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_SUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2017-03-20 23:59:45 +03:00
2018-04-30 01:35:25 +03:00
creds = self . insta_creds ( template = self . get_credentials ( ) )
2017-03-20 23:59:45 +03:00
lp = self . get_loadparm ( )
net = Net ( creds , lp , server = self . server_ip )
password = " newPassword!!42 "
2018-11-28 17:06:54 +03:00
net . change_password ( newpassword = password ,
2017-03-24 03:52:58 +03:00
username = USER_NAME ,
oldpassword = USER_PASS )
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )
2017-03-20 23:59:45 +03:00
def test_admin_change_password_new_password_fails_restriction ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] ==
" NT_STATUS_PASSWORD_RESTRICTION " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" SAMR Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2022-10-21 19:14:44 +03:00
self . _authDescription ( ) ) and
2018-12-13 00:20:28 +03:00
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_UNSUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2017-03-20 23:59:45 +03:00
creds = self . insta_creds ( template = self . get_credentials ( ) )
lp = self . get_loadparm ( )
net = Net ( creds , lp , server = self . server_ip )
password = " newPassword "
exception_thrown = False
try :
2018-11-28 17:06:54 +03:00
net . change_password ( newpassword = password ,
2017-03-24 03:52:58 +03:00
oldpassword = USER_PASS ,
username = USER_NAME )
2018-04-30 01:35:25 +03:00
except Exception :
2017-03-20 23:59:45 +03:00
exception_thrown = True
2020-02-07 01:02:38 +03:00
self . assertEqual ( True , exception_thrown ,
2017-03-20 23:59:45 +03:00
" Expected exception not thrown " )
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )
2017-03-20 23:59:45 +03:00
def test_admin_change_password_unknown_user ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] ==
" NT_STATUS_NO_SUCH_USER " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" SAMR Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2022-10-21 19:14:44 +03:00
self . _authDescription ( ) ) and
2018-12-13 00:20:28 +03:00
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_UNSUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2017-03-20 23:59:45 +03:00
creds = self . insta_creds ( template = self . get_credentials ( ) )
lp = self . get_loadparm ( )
net = Net ( creds , lp , server = self . server_ip )
password = " newPassword!!42 "
exception_thrown = False
try :
2018-11-28 17:06:54 +03:00
net . change_password ( newpassword = password ,
2017-03-24 03:52:58 +03:00
oldpassword = USER_PASS ,
username = " badUser " )
2018-04-30 01:35:25 +03:00
except Exception :
2017-03-20 23:59:45 +03:00
exception_thrown = True
2020-02-07 01:02:38 +03:00
self . assertEqual ( True , exception_thrown ,
2017-03-20 23:59:45 +03:00
" Expected exception not thrown " )
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )
2017-03-20 23:59:45 +03:00
def test_admin_change_password_bad_original_password ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] ==
" NT_STATUS_WRONG_PASSWORD " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" SAMR Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2022-10-21 19:14:44 +03:00
self . _authDescription ( ) ) and
2018-12-13 00:20:28 +03:00
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_UNSUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2017-03-20 23:59:45 +03:00
creds = self . insta_creds ( template = self . get_credentials ( ) )
lp = self . get_loadparm ( )
net = Net ( creds , lp , server = self . server_ip )
password = " newPassword!!42 "
exception_thrown = False
try :
2018-11-28 17:06:54 +03:00
net . change_password ( newpassword = password ,
2017-03-24 03:52:58 +03:00
oldpassword = " badPassword " ,
username = USER_NAME )
2018-04-30 01:35:25 +03:00
except Exception :
2017-03-20 23:59:45 +03:00
exception_thrown = True
2020-02-07 01:02:38 +03:00
self . assertEqual ( True , exception_thrown ,
2017-03-20 23:59:45 +03:00
" Expected exception not thrown " )
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )
2017-03-20 23:59:45 +03:00
2017-03-17 05:58:17 +03:00
def test_ldap_change_password ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] == " NT_STATUS_OK " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" LDAP Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2018-12-13 00:20:28 +03:00
" LDAP Modify " ) and
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_SUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2018-04-30 01:35:25 +03:00
new_password = samba . generate_random_password ( 32 , 32 )
2017-03-17 05:58:17 +03:00
self . ldb . modify_ldif (
" dn: cn= " + USER_NAME + " ,cn=users, " + self . base_dn + " \n " +
" changetype: modify \n " +
" delete: userPassword \n " +
" userPassword: " + USER_PASS + " \n " +
" add: userPassword \n " +
2018-04-30 01:35:25 +03:00
" userPassword: " + new_password + " \n " )
2017-03-17 05:58:17 +03:00
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )
2017-03-17 05:58:17 +03:00
#
2023-05-26 07:00:50 +03:00
# Currently this does not get logged, so we expect to see no messages.
2017-03-17 05:58:17 +03:00
#
def test_ldap_change_password_bad_user ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2023-06-20 01:11:50 +03:00
msg_type = msg [ " type " ]
# Accept any message we receive, except for those produced while
# the Administrator authenticates in setUp().
return ( msg_type != " Authentication " or (
" Administrator " not in msg [ msg_type ] [ " clientAccount " ] ) ) and (
msg_type != " Authorization " or (
" Administrator " not in msg [ msg_type ] [ " account " ] ) )
2017-03-17 05:58:17 +03:00
2018-04-30 01:35:25 +03:00
new_password = samba . generate_random_password ( 32 , 32 )
2017-03-17 05:58:17 +03:00
try :
self . ldb . modify_ldif (
" dn: cn= " + " badUser " + " ,cn=users, " + self . base_dn + " \n " +
" changetype: modify \n " +
" delete: userPassword \n " +
" userPassword: " + USER_PASS + " \n " +
" add: userPassword \n " +
2018-04-30 01:35:25 +03:00
" userPassword: " + new_password + " \n " )
2017-03-17 05:58:17 +03:00
self . fail ( )
2018-02-23 17:32:17 +03:00
except LdbError as e :
( num , msg ) = e . args
2017-03-17 05:58:17 +03:00
pass
2023-05-26 07:00:50 +03:00
self . assertFalse ( self . waitForMessages ( isLastExpectedMessage ) ,
" Received unexpected messages " )
2017-03-17 05:58:17 +03:00
def test_ldap_change_password_bad_original_password ( self ) :
2017-03-24 03:52:58 +03:00
def isLastExpectedMessage ( msg ) :
2018-04-30 01:35:25 +03:00
return ( ( msg [ " type " ] == " Authentication " ) and
( msg [ " Authentication " ] [ " status " ] ==
" NT_STATUS_WRONG_PASSWORD " ) and
( msg [ " Authentication " ] [ " serviceDescription " ] ==
" LDAP Password Change " ) and
( msg [ " Authentication " ] [ " authDescription " ] ==
2018-12-13 00:20:28 +03:00
" LDAP Modify " ) and
( msg [ " Authentication " ] [ " eventId " ] ==
2018-12-13 04:46:31 +03:00
EVT_ID_UNSUCCESSFUL_LOGON ) and
( msg [ " Authentication " ] [ " logonType " ] ==
EVT_LOGON_NETWORK ) )
2018-04-30 01:35:25 +03:00
new_password = samba . generate_random_password ( 32 , 32 )
2017-03-17 05:58:17 +03:00
try :
self . ldb . modify_ldif (
" dn: cn= " + USER_NAME + " ,cn=users, " + self . base_dn + " \n " +
" changetype: modify \n " +
" delete: userPassword \n " +
" userPassword: " + " badPassword " + " \n " +
" add: userPassword \n " +
2018-04-30 01:35:25 +03:00
" userPassword: " + new_password + " \n " )
2017-03-17 05:58:17 +03:00
self . fail ( )
2018-02-23 17:32:17 +03:00
except LdbError as e1 :
( num , msg ) = e1 . args
2017-03-17 05:58:17 +03:00
pass
2019-03-07 06:10:27 +03:00
self . assertTrue ( self . waitForMessages ( isLastExpectedMessage ) ,
" Did not receive the expected message " )