1 # Unix SMB/CIFS implementation.
2 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Tests for the Auth and AuthZ logging of password changes.
22 from samba
.samdb
import SamDB
23 from samba
.auth
import system_session
25 import samba
.tests
.auth_log_base
26 from samba
.tests
import delete_force
27 from samba
.net
import Net
29 from ldb
import LdbError
30 from samba
.tests
.password_test
import PasswordCommon
31 from samba
.dcerpc
.windows_event_ids
import (
32 EVT_ID_SUCCESSFUL_LOGON
,
33 EVT_ID_UNSUCCESSFUL_LOGON
,
37 USER_NAME
= "authlogtestuser"
38 USER_PASS
= samba
.generate_random_password(32, 32)
41 class AuthLogPassChangeTests(samba
.tests
.auth_log_base
.AuthLogTestBase
):
46 self
.server_ip
= os
.environ
["SERVER_IP"]
48 host
= "ldap://%s" % os
.environ
["SERVER"]
49 self
.ldb
= SamDB(url
=host
,
50 session_info
=system_session(),
51 credentials
=self
.get_credentials(),
52 lp
=self
.get_loadparm())
54 # permit password changes during this test
55 PasswordCommon
.allow_password_changes(self
, self
.ldb
)
57 self
.base_dn
= self
.ldb
.domain_dn()
59 # (Re)adds the test user USER_NAME with password USER_PASS
60 delete_force(self
.ldb
, "cn=" + USER_NAME
+ ",cn=users," + self
.base_dn
)
62 "dn": "cn=" + USER_NAME
+ ",cn=users," + self
.base_dn
,
63 "objectclass": "user",
64 "sAMAccountName": USER_NAME
,
65 "userPassword": USER_PASS
68 # discard any auth log messages for the password setup
69 type(self
).discardMessages()
71 def _authDescription(self
):
72 return "samr_ChangePasswordUser4"
74 def test_admin_change_password(self
):
75 def isLastExpectedMessage(msg
):
76 return ((msg
["type"] == "Authentication") and
77 (msg
["Authentication"]["status"] == "NT_STATUS_OK") and
78 (msg
["Authentication"]["serviceDescription"] ==
79 "SAMR Password Change") and
80 (msg
["Authentication"]["authDescription"] ==
81 self
._authDescription
()) and
82 (msg
["Authentication"]["eventId"] ==
83 EVT_ID_SUCCESSFUL_LOGON
) and
84 (msg
["Authentication"]["logonType"] ==
87 creds
= self
.insta_creds(template
=self
.get_credentials())
89 lp
= self
.get_loadparm()
90 net
= Net(creds
, lp
, server
=self
.server_ip
)
91 password
= "newPassword!!42"
93 net
.change_password(newpassword
=password
,
95 oldpassword
=USER_PASS
)
96 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
97 "Did not receive the expected message")
99 def test_admin_change_password_new_password_fails_restriction(self
):
100 def isLastExpectedMessage(msg
):
101 return ((msg
["type"] == "Authentication") and
102 (msg
["Authentication"]["status"] ==
103 "NT_STATUS_PASSWORD_RESTRICTION") and
104 (msg
["Authentication"]["serviceDescription"] ==
105 "SAMR Password Change") and
106 (msg
["Authentication"]["authDescription"] ==
107 self
._authDescription
()) and
108 (msg
["Authentication"]["eventId"] ==
109 EVT_ID_UNSUCCESSFUL_LOGON
) and
110 (msg
["Authentication"]["logonType"] ==
113 creds
= self
.insta_creds(template
=self
.get_credentials())
115 lp
= self
.get_loadparm()
116 net
= Net(creds
, lp
, server
=self
.server_ip
)
117 password
= "newPassword"
119 exception_thrown
= False
121 net
.change_password(newpassword
=password
,
122 oldpassword
=USER_PASS
,
125 exception_thrown
= True
126 self
.assertEqual(True, exception_thrown
,
127 "Expected exception not thrown")
128 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
129 "Did not receive the expected message")
131 def test_admin_change_password_unknown_user(self
):
132 def isLastExpectedMessage(msg
):
133 return ((msg
["type"] == "Authentication") and
134 (msg
["Authentication"]["status"] ==
135 "NT_STATUS_NO_SUCH_USER") and
136 (msg
["Authentication"]["serviceDescription"] ==
137 "SAMR Password Change") and
138 (msg
["Authentication"]["authDescription"] ==
139 self
._authDescription
()) and
140 (msg
["Authentication"]["eventId"] ==
141 EVT_ID_UNSUCCESSFUL_LOGON
) and
142 (msg
["Authentication"]["logonType"] ==
145 creds
= self
.insta_creds(template
=self
.get_credentials())
147 lp
= self
.get_loadparm()
148 net
= Net(creds
, lp
, server
=self
.server_ip
)
149 password
= "newPassword!!42"
151 exception_thrown
= False
153 net
.change_password(newpassword
=password
,
154 oldpassword
=USER_PASS
,
157 exception_thrown
= True
158 self
.assertEqual(True, exception_thrown
,
159 "Expected exception not thrown")
161 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
162 "Did not receive the expected message")
164 def test_admin_change_password_bad_original_password(self
):
165 def isLastExpectedMessage(msg
):
166 return ((msg
["type"] == "Authentication") and
167 (msg
["Authentication"]["status"] ==
168 "NT_STATUS_WRONG_PASSWORD") and
169 (msg
["Authentication"]["serviceDescription"] ==
170 "SAMR Password Change") and
171 (msg
["Authentication"]["authDescription"] ==
172 self
._authDescription
()) and
173 (msg
["Authentication"]["eventId"] ==
174 EVT_ID_UNSUCCESSFUL_LOGON
) and
175 (msg
["Authentication"]["logonType"] ==
178 creds
= self
.insta_creds(template
=self
.get_credentials())
180 lp
= self
.get_loadparm()
181 net
= Net(creds
, lp
, server
=self
.server_ip
)
182 password
= "newPassword!!42"
184 exception_thrown
= False
186 net
.change_password(newpassword
=password
,
187 oldpassword
="badPassword",
190 exception_thrown
= True
191 self
.assertEqual(True, exception_thrown
,
192 "Expected exception not thrown")
194 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
195 "Did not receive the expected message")
197 def test_ldap_change_password(self
):
198 def isLastExpectedMessage(msg
):
199 return ((msg
["type"] == "Authentication") and
200 (msg
["Authentication"]["status"] == "NT_STATUS_OK") and
201 (msg
["Authentication"]["serviceDescription"] ==
202 "LDAP Password Change") and
203 (msg
["Authentication"]["authDescription"] ==
205 (msg
["Authentication"]["eventId"] ==
206 EVT_ID_SUCCESSFUL_LOGON
) and
207 (msg
["Authentication"]["logonType"] ==
210 new_password
= samba
.generate_random_password(32, 32)
211 self
.ldb
.modify_ldif(
212 "dn: cn=" + USER_NAME
+ ",cn=users," + self
.base_dn
+ "\n" +
213 "changetype: modify\n" +
214 "delete: userPassword\n" +
215 "userPassword: " + USER_PASS
+ "\n" +
216 "add: userPassword\n" +
217 "userPassword: " + new_password
+ "\n")
219 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
220 "Did not receive the expected message")
223 # Currently this does not get logged, so we expect to see no messages.
225 def test_ldap_change_password_bad_user(self
):
226 def isLastExpectedMessage(msg
):
227 msg_type
= msg
["type"]
229 # Accept any message we receive, except for those produced while
230 # the Administrator authenticates in setUp().
231 return (msg_type
!= "Authentication" or (
232 "Administrator" not in msg
[msg_type
]["clientAccount"])) and (
233 msg_type
!= "Authorization" or (
234 "Administrator" not in msg
[msg_type
]["account"]))
236 new_password
= samba
.generate_random_password(32, 32)
238 self
.ldb
.modify_ldif(
239 "dn: cn=" + "badUser" + ",cn=users," + self
.base_dn
+ "\n" +
240 "changetype: modify\n" +
241 "delete: userPassword\n" +
242 "userPassword: " + USER_PASS
+ "\n" +
243 "add: userPassword\n" +
244 "userPassword: " + new_password
+ "\n")
246 except LdbError
as e
:
250 self
.assertFalse(self
.waitForMessages(isLastExpectedMessage
),
251 "Received unexpected messages")
253 def test_ldap_change_password_bad_original_password(self
):
254 def isLastExpectedMessage(msg
):
255 return ((msg
["type"] == "Authentication") and
256 (msg
["Authentication"]["status"] ==
257 "NT_STATUS_WRONG_PASSWORD") and
258 (msg
["Authentication"]["serviceDescription"] ==
259 "LDAP Password Change") and
260 (msg
["Authentication"]["authDescription"] ==
262 (msg
["Authentication"]["eventId"] ==
263 EVT_ID_UNSUCCESSFUL_LOGON
) and
264 (msg
["Authentication"]["logonType"] ==
267 new_password
= samba
.generate_random_password(32, 32)
269 self
.ldb
.modify_ldif(
270 "dn: cn=" + USER_NAME
+ ",cn=users," + self
.base_dn
+ "\n" +
271 "changetype: modify\n" +
272 "delete: userPassword\n" +
273 "userPassword: " + "badPassword" + "\n" +
274 "add: userPassword\n" +
275 "userPassword: " + new_password
+ "\n")
277 except LdbError
as e1
:
281 self
.assertTrue(self
.waitForMessages(isLastExpectedMessage
),
282 "Did not receive the expected message")