1 # Unix SMB/CIFS implementation.
3 # Copyright (C) Samuel Cabrero <scabrero@suse.de> 2018
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from subprocess
import Popen
, PIPE
21 from samba
.tests
import BlackboxProcessError
22 from samba
.tests
.ntlm_auth_base
import NTLMAuthTestCase
23 from samba
.common
import get_string
25 class NTLMAuthHelpersTests(NTLMAuthTestCase
):
29 self
.username
= os
.environ
["DC_USERNAME"]
30 self
.password
= os
.environ
["DC_PASSWORD"]
31 self
.domain
= os
.environ
["DOMAIN"]
32 out
= get_string(self
.check_output("wbinfo -n %s" % self
.username
))
33 self
.group_sid
= out
.split(" ")[0]
34 self
.assertTrue(self
.group_sid
.startswith("S-1-5-21-"))
35 self
.bad_group_sid
= self
.group_sid
[:-2]
37 def test_specified_domain(self
):
38 """ ntlm_auth with specified domain """
44 ret
= self
.run_helper(client_username
=username
,
45 client_password
=password
,
47 server_username
=username
,
48 server_password
=password
,
50 server_use_winbind
=False)
57 ret
= self
.run_helper(client_username
=username
,
58 client_password
=password
,
60 server_username
=username
,
61 server_password
=password
,
63 server_use_winbind
=False)
66 def test_against_winbind(self
):
67 """ ntlm_auth against winbindd """
69 ret
= self
.run_helper(client_username
=self
.username
,
70 client_password
=self
.password
,
71 client_domain
=self
.domain
,
72 server_use_winbind
=True)
75 def test_ntlmssp_gss_spnego(self
):
76 """ ntlm_auth with NTLMSSP client and gss-spnego server """
82 ret
= self
.run_helper(client_username
=username
,
83 client_password
=password
,
85 server_username
=username
,
86 server_password
=password
,
88 client_helper
="ntlmssp-client-1",
89 server_helper
="gss-spnego",
90 server_use_winbind
=False)
93 def test_gss_spnego(self
):
94 """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server """
100 ret
= self
.run_helper(client_username
=username
,
101 client_password
=password
,
102 client_domain
=domain
,
103 server_username
=username
,
104 server_password
=password
,
105 server_domain
=domain
,
106 client_helper
="gss-spnego-client",
107 server_helper
="gss-spnego",
108 server_use_winbind
=False)
111 def test_gss_spnego_winbind(self
):
112 """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server
115 ret
= self
.run_helper(client_username
=self
.username
,
116 client_password
=self
.password
,
117 client_domain
=self
.domain
,
118 client_helper
="gss-spnego-client",
119 server_helper
="gss-spnego",
120 server_use_winbind
=True)
123 def test_ntlmssp_gss_spnego_cached_creds(self
):
124 """ ntlm_auth with NTLMSSP client and gss-spnego server against
125 winbind with cached credentials """
127 param
= "--ccache-save=%s%s%s%%%s" % (self
.domain
,
128 self
.winbind_separator
,
131 cache_cmd
= ["wbinfo",
133 self
.check_exit_code(cache_cmd
, 0)
135 ret
= self
.run_helper(client_username
=self
.username
,
136 client_password
=None,
137 client_domain
=self
.domain
,
138 client_use_cached_creds
=True,
139 client_helper
="ntlmssp-client-1",
140 server_helper
="gss-spnego",
141 server_use_winbind
=True)
144 def test_require_membership(self
):
145 """ ntlm_auth against winbindd with require-membership-of """
147 ret
= self
.run_helper(client_username
=self
.username
,
148 client_password
=self
.password
,
149 client_domain
=self
.domain
,
150 require_membership
=self
.group_sid
,
151 server_use_winbind
=True)
154 ret
= self
.run_helper(client_username
=self
.username
,
155 client_password
=self
.password
,
156 client_domain
=self
.domain
,
157 require_membership
=self
.bad_group_sid
,
158 server_use_winbind
=True)
159 self
.assertFalse(ret
)
161 def test_require_membership_gss_spnego(self
):
162 """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server
163 against winbind with require-membership-of """
165 ret
= self
.run_helper(client_username
=self
.username
,
166 client_password
=self
.password
,
167 client_domain
=self
.domain
,
168 require_membership
=self
.group_sid
,
169 client_helper
="gss-spnego-client",
170 server_helper
="gss-spnego",
171 server_use_winbind
=True)
174 ret
= self
.run_helper(client_username
=self
.username
,
175 client_password
=self
.password
,
176 client_domain
=self
.domain
,
177 require_membership
=self
.bad_group_sid
,
178 client_helper
="gss-spnego-client",
179 server_helper
="gss-spnego",
180 server_use_winbind
=True)
181 self
.assertFalse(ret
)
183 def test_plaintext_with_membership(self
):
184 """ ntlm_auth plaintext authentication with require-membership-of """
186 proc
= Popen([self
.ntlm_auth_path
,
187 "--require-membership-of", self
.group_sid
,
188 "--helper-protocol", "squid-2.5-basic"],
189 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
190 creds
= "%s%s%s %s\n" % (self
.domain
, self
.winbind_separator
,
193 (out
, err
) = proc
.communicate(input=creds
.encode('utf-8'))
194 self
.assertEqual(proc
.returncode
, 0)
195 self
.assertTrue(out
.startswith(b
"OK\n"))
197 # Check membership failure
198 proc
= Popen([self
.ntlm_auth_path
,
199 "--require-membership-of", self
.bad_group_sid
,
200 "--helper-protocol", "squid-2.5-basic"],
201 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
202 creds
= "%s%s%s %s\n" % (self
.domain
,
203 self
.winbind_separator
,
206 (out
, err
) = proc
.communicate(input=creds
.encode('utf-8'))
207 self
.assertEqual(proc
.returncode
, 0)
208 self
.assertTrue(out
.startswith(b
"ERR\n"))
210 def test_ntlm_server_1_with_fixed_password(self
):
211 """ ntlm_auth ntlm-server-1 with fixed password """
214 "LANMAN-Challenge: 0123456789abcdef",
215 "NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6",
217 "Username: testuser",
218 "Request-User-Session-Key: Yes",
221 proc
= Popen([self
.ntlm_auth_path
,
222 "--password", "SecREt01",
223 "--helper-protocol", "ntlm-server-1"],
224 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
225 buf
= "\n".join(ntlm_cmds
)
226 (out
, err
) = proc
.communicate(input=buf
.encode('utf-8'))
227 self
.assertEqual(proc
.returncode
, 0)
229 lines
= out
.split(b
"\n")
231 self
.assertEqual(len(lines
), 4)
232 self
.assertEqual(lines
[0], b
"Authenticated: Yes")
234 lines
[1], b
"User-Session-Key: 3F373EA8E4AF954F14FAA506F8EEBDC4")
235 self
.assertEqual(lines
[2], b
".")
236 self
.assertEqual(lines
[3], b
"")
238 # Break the password with a leading A on the challenge
239 ntlm_cmds
[0] = "LANMAN-Challenge: A123456789abcdef"
241 proc
= Popen([self
.ntlm_auth_path
,
242 "--password", "SecREt01",
243 "--helper-protocol", "ntlm-server-1"],
244 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
245 buf
= "\n".join(ntlm_cmds
)
246 (out
, err
) = proc
.communicate(input=buf
.encode('utf-8'))
247 self
.assertEqual(proc
.returncode
, 0)
249 lines
= out
.split(b
"\n")
250 self
.assertEqual(len(lines
), 5)
251 self
.assertEqual(lines
[0], b
"Authenticated: No")
253 def test_ntlm_server_1_with_plaintext_winbind(self
):
254 """ ntlm_auth ntlm-server-1 with plaintext password against winbind """
257 "Password: %s" % self
.password
,
258 "NT-Domain: %s" % self
.domain
,
259 "Username: %s" % self
.username
,
260 "Request-User-Session-Key: Yes",
263 proc
= Popen([self
.ntlm_auth_path
,
264 "--require-membership-of", self
.group_sid
,
265 "--helper-protocol", "ntlm-server-1"],
266 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
267 buf
= "\n".join(ntlm_cmds
)
268 (out
, err
) = proc
.communicate(input=buf
.encode('utf-8'))
269 self
.assertEqual(proc
.returncode
, 0)
271 lines
= out
.split(b
"\n")
273 self
.assertEqual(len(lines
), 3)
274 self
.assertEqual(lines
[0], b
"Authenticated: Yes")
275 self
.assertEqual(lines
[1], b
".")
276 self
.assertEqual(lines
[2], b
"")
278 # Check membership failure
280 proc
= Popen([self
.ntlm_auth_path
,
281 "--require-membership-of", self
.bad_group_sid
,
282 "--helper-protocol", "ntlm-server-1"],
283 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
284 buf
= "\n".join(ntlm_cmds
)
285 (out
, err
) = proc
.communicate(input=buf
.encode('utf-8'))
286 self
.assertEqual(proc
.returncode
, 0)
288 lines
= out
.split(b
"\n")
290 self
.assertEqual(len(lines
), 3)
291 self
.assertEqual(lines
[0], b
"Authenticated: No")
292 self
.assertEqual(lines
[1], b
".")
293 self
.assertEqual(lines
[2], b
"")
295 def test_ntlm_server_1_with_incorrect_password_winbind(self
):
296 """ ntlm_auth ntlm-server-1 with incorrect fixed password against
300 "LANMAN-Challenge: 0123456789abcdef",
301 "NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6",
302 "NT-Domain: %s" % self
.domain
,
303 "Username: %s" % self
.username
,
304 "Request-User-Session-Key: Yes",
307 proc
= Popen([self
.ntlm_auth_path
,
308 "--helper-protocol", "ntlm-server-1"],
309 stdout
=PIPE
, stdin
=PIPE
, stderr
=PIPE
)
310 buf
= "\n".join(ntlm_cmds
)
311 (out
, err
) = proc
.communicate(input=buf
.encode('utf-8'))
312 self
.assertEqual(proc
.returncode
, 0)
314 lines
= out
.split(b
"\n")
316 self
.assertEqual(len(lines
), 5)
317 self
.assertEqual(lines
[0], b
"Authenticated: No")
319 def test_diagnostics(self
):
320 """ ntlm_auth diagnostics """
321 cmd_line
= [self
.ntlm_auth_path
,
322 "--username", self
.username
,
323 "--password", self
.password
,
324 "--domain", self
.domain
,
327 self
.check_exit_code(cmd_line
, 0)
328 except BlackboxProcessError
as e
:
331 def test_diagnostics_lm(self
):
332 """ ntlm_auth diagnostics """
333 cmd_line
= [self
.ntlm_auth_path
,
334 "--username", self
.username
,
335 "--password", self
.password
,
336 "--domain", self
.domain
,
340 self
.check_exit_code(cmd_line
, 0)
341 except BlackboxProcessError
as e
: