tests/ntlm_auth: Port ntlm_auth tests to python: ntlm_auth ntlm-server-1 with plainte...
[metze/samba/wip.git] / python / samba / tests / ntlm_auth.py
1 # Unix SMB/CIFS implementation.
2 #
3 # Copyright (C) Samuel Cabrero <scabrero@suse.de> 2018
4 #
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.
9 #
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.
14 #
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/>.
17 #
18
19 import os
20 from subprocess import Popen, PIPE
21 from samba.tests.ntlm_auth_base import NTLMAuthTestCase
22 from samba.compat import get_string
23
24 class NTLMAuthHelpersTests(NTLMAuthTestCase):
25
26     def setUp(self):
27         super(NTLMAuthHelpersTests, self).setUp()
28         self.username = os.environ["DC_USERNAME"]
29         self.password = os.environ["DC_PASSWORD"]
30         self.domain = os.environ["DOMAIN"]
31         out = get_string(self.check_output("wbinfo -n %s" % self.username))
32         self.group_sid = out.split(" ")[0]
33         self.assertTrue(self.group_sid.startswith("S-1-5-21-"))
34         self.bad_group_sid = self.group_sid[:-2]
35
36     def test_specified_domain(self):
37         """ ntlm_auth with specified domain """
38
39         username = "foo"
40         password = "secret"
41         domain = "FOO"
42
43         ret = self.run_helper(client_username=username,
44                               client_password=password,
45                               client_domain=domain,
46                               server_username=username,
47                               server_password=password,
48                               server_domain=domain,
49                               server_use_winbind=False)
50         self.assertTrue(ret)
51
52         username = "foo"
53         password = "secret"
54         domain = "fOo"
55
56         ret = self.run_helper(client_username=username,
57                               client_password=password,
58                               client_domain=domain,
59                               server_username=username,
60                               server_password=password,
61                               server_domain=domain,
62                               server_use_winbind=False)
63         self.assertTrue(ret)
64
65     def test_agaist_winbind(self):
66         """ ntlm_auth against winbindd """
67
68         ret = self.run_helper(client_username=self.username,
69                               client_password=self.password,
70                               client_domain=self.domain,
71                               server_use_winbind=True)
72         self.assertTrue(ret)
73
74     def test_ntlmssp_gss_spnego(self):
75         """ ntlm_auth with NTLMSSP client and gss-spnego server """
76
77         username = "foo"
78         password = "secret"
79         domain = "fOo"
80
81         ret = self.run_helper(client_username=username,
82                               client_password=password,
83                               client_domain=domain,
84                               server_username=username,
85                               server_password=password,
86                               server_domain=domain,
87                               client_helper="ntlmssp-client-1",
88                               server_helper="gss-spnego",
89                               server_use_winbind=False)
90         self.assertTrue(ret)
91
92     def test_gss_spnego(self):
93         """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server """
94
95         username = "foo"
96         password = "secret"
97         domain = "fOo"
98
99         ret = self.run_helper(client_username=username,
100                               client_password=password,
101                               client_domain=domain,
102                               server_username=username,
103                               server_password=password,
104                               server_domain=domain,
105                               client_helper="gss-spnego-client",
106                               server_helper="gss-spnego",
107                               server_use_winbind=False)
108         self.assertTrue(ret)
109
110     def test_gss_spnego_winbind(self):
111         """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server
112         against winbind """
113
114         ret = self.run_helper(client_username=self.username,
115                               client_password=self.password,
116                               client_domain=self.domain,
117                               client_helper="gss-spnego-client",
118                               server_helper="gss-spnego",
119                               server_use_winbind=True)
120         self.assertTrue(ret)
121
122     def test_ntlmssp_gss_spnego_cached_creds(self):
123         """ ntlm_auth with NTLMSSP client and gss-spnego server against
124         winbind with cached credentials """
125
126         param = "--ccache-save=%s%s%s%%%s" % (self.domain,
127                                               self.winbind_separator,
128                                               self.username,
129                                               self.password)
130         cache_cmd = ["wbinfo",
131                      param]
132         self.check_exit_code(cache_cmd, 0)
133
134         ret = self.run_helper(client_username=self.username,
135                               client_password=self.password,
136                               client_domain=self.domain,
137                               client_use_cached_creds=True,
138                               client_helper="ntlmssp-client-1",
139                               server_helper="gss-spnego",
140                               server_use_winbind=True)
141         self.assertTrue(ret)
142
143     def test_require_membership(self):
144         """ ntlm_auth against winbindd with require-membership-of """
145
146         ret = self.run_helper(client_username=self.username,
147                               client_password=self.password,
148                               client_domain=self.domain,
149                               require_membership=self.group_sid,
150                               server_use_winbind=True)
151         self.assertTrue(ret)
152
153         ret = self.run_helper(client_username=self.username,
154                               client_password=self.password,
155                               client_domain=self.domain,
156                               require_membership=self.bad_group_sid,
157                               server_use_winbind=True)
158         self.assertFalse(ret)
159
160     def test_require_membership_gss_spnego(self):
161         """ ntlm_auth with NTLMSSP gss-spnego-client and gss-spnego server
162         against winbind with require-membership-of """
163
164         ret = self.run_helper(client_username=self.username,
165                               client_password=self.password,
166                               client_domain=self.domain,
167                               require_membership=self.group_sid,
168                               client_helper="gss-spnego-client",
169                               server_helper="gss-spnego",
170                               server_use_winbind=True)
171         self.assertTrue(ret)
172
173         ret = self.run_helper(client_username=self.username,
174                               client_password=self.password,
175                               client_domain=self.domain,
176                               require_membership=self.bad_group_sid,
177                               client_helper="gss-spnego-client",
178                               server_helper="gss-spnego",
179                               server_use_winbind=True)
180         self.assertFalse(ret)
181
182     def test_plaintext_with_membership(self):
183         """ ntlm_auth plaintext authentication with require-membership-of """
184
185         proc = Popen([self.ntlm_auth_path,
186                       "--require-membership-of", self.group_sid,
187                       "--helper-protocol", "squid-2.5-basic"],
188                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
189         creds = "%s%s%s %s\n" % (self.domain, self.winbind_separator,
190                                  self.username,
191                                  self.password)
192         (out, err) = proc.communicate(input=creds.encode('utf-8'))
193         self.assertEqual(proc.returncode, 0)
194         self.assertTrue(out.startswith(b"OK\n"))
195
196         # Check membership failure
197         proc = Popen([self.ntlm_auth_path,
198                       "--require-membership-of", self.bad_group_sid,
199                       "--helper-protocol", "squid-2.5-basic"],
200                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
201         creds = "%s%s%s %s\n" % (self.domain,
202                                  self.winbind_separator,
203                                  self.username,
204                                  self.password)
205         (out, err) = proc.communicate(input=creds.encode('utf-8'))
206         self.assertEqual(proc.returncode, 0)
207         self.assertTrue(out.startswith(b"ERR\n"))
208
209     def test_ntlm_server_1_with_fixed_password(self):
210         """ ntlm_auth ntlm-server-1 with fixed password """
211
212         ntlm_cmds = [
213             "LANMAN-Challenge: 0123456789abcdef",
214             "NT-Response: 25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6",
215             "NT-Domain: TEST",
216             "Username: testuser",
217             "Request-User-Session-Key: Yes",
218             ".\n" ]
219
220         proc = Popen([self.ntlm_auth_path,
221                       "--password", "SecREt01",
222                       "--helper-protocol", "ntlm-server-1"],
223                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
224         buf = "\n".join(ntlm_cmds)
225         (out, err) = proc.communicate(input=buf.encode('utf-8'))
226         self.assertEqual(proc.returncode, 0)
227
228         lines = out.split(b"\n")
229
230         self.assertEqual(len(lines), 4)
231         self.assertEquals(lines[0], b"Authenticated: Yes")
232         self.assertEquals(
233             lines[1], b"User-Session-Key: 3F373EA8E4AF954F14FAA506F8EEBDC4")
234         self.assertEquals(lines[2], b".")
235         self.assertEquals(lines[3], b"")
236
237         # Break the password with a leading A on the challenge
238         ntlm_cmds[0] = "LANMAN-Challenge: A123456789abcdef"
239
240         proc = Popen([self.ntlm_auth_path,
241                       "--password", "SecREt01",
242                       "--helper-protocol", "ntlm-server-1"],
243                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
244         buf = "\n".join(ntlm_cmds)
245         (out, err) = proc.communicate(input=buf.encode('utf-8'))
246         self.assertEqual(proc.returncode, 0)
247
248         lines = out.split(b"\n")
249         self.assertEqual(len(lines), 5)
250         self.assertEquals(lines[0], b"Authenticated: No")
251
252     def test_ntlm_server_1_with_plaintext_winbind(self):
253         """ ntlm_auth ntlm-server-1 with plaintext password against winbind """
254
255         ntlm_cmds = [
256             "Password: %s" % self.password,
257             "NT-Domain: %s" % self.domain,
258             "Username: %s" % self.username,
259             "Request-User-Session-Key: Yes",
260             ".\n" ]
261
262         proc = Popen([self.ntlm_auth_path,
263                       "--require-membership-of", self.group_sid,
264                       "--helper-protocol", "ntlm-server-1"],
265                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
266         buf = "\n".join(ntlm_cmds)
267         (out, err) = proc.communicate(input=buf.encode('utf-8'))
268         self.assertEqual(proc.returncode, 0)
269
270         lines = out.split(b"\n")
271
272         self.assertEqual(len(lines), 3)
273         self.assertEquals(lines[0], b"Authenticated: Yes")
274         self.assertEquals(lines[1], b".")
275         self.assertEquals(lines[2], b"")
276
277         # Check membership failure
278
279         proc = Popen([self.ntlm_auth_path,
280                       "--require-membership-of", self.bad_group_sid,
281                       "--helper-protocol", "ntlm-server-1"],
282                       stdout=PIPE, stdin=PIPE, stderr=PIPE)
283         buf = "\n".join(ntlm_cmds)
284         (out, err) = proc.communicate(input=buf.encode('utf-8'))
285         self.assertEqual(proc.returncode, 0)
286
287         lines = out.split(b"\n")
288
289         self.assertEqual(len(lines), 3)
290         self.assertEquals(lines[0], b"Authenticated: No")
291         self.assertEquals(lines[1], b".")
292         self.assertEquals(lines[2], b"")