ce81b736e86fdca96d21a2255aec17ed3bc2fff9
[jra/samba-autobuild/.git] / auth / credentials / tests / bind.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 # This is unit with tests for LDAP access checks
4
5 import optparse
6 import sys
7 import base64
8 import copy
9
10 sys.path.insert(0, "bin/python")
11 import samba
12 from samba.tests.subunitrun import SubunitOptions, TestProgram
13
14 import samba.getopt as options
15
16 from ldb import SCOPE_BASE, SCOPE_SUBTREE, LdbError, ERR_INVALID_CREDENTIALS
17
18 from samba import gensec
19 import samba.tests
20 from samba.tests import delete_force
21 from samba.credentials import Credentials
22
23 def create_credential(lp, other):
24     c = Credentials()
25     c.guess(lp)
26     c.set_gensec_features(other.get_gensec_features())
27     return c
28
29 parser = optparse.OptionParser("bind [options] <host>")
30 sambaopts = options.SambaOptions(parser)
31 parser.add_option_group(sambaopts)
32
33 # use command line creds if available
34 credopts = options.CredentialsOptions(parser)
35 parser.add_option_group(credopts)
36 subunitopts = SubunitOptions(parser)
37 parser.add_option_group(subunitopts)
38 opts, args = parser.parse_args()
39
40 if len(args) < 1:
41     parser.print_usage()
42     sys.exit(1)
43
44 host = args[0]
45 lp = sambaopts.get_loadparm()
46 creds = credopts.get_credentials(lp)
47 creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
48
49 creds_machine = create_credential(lp, creds)
50 creds_virtual = create_credential(lp, creds)
51 creds_user1 = create_credential(lp, creds)
52 creds_user2 = create_credential(lp, creds)
53 creds_user3 = create_credential(lp, creds)
54 creds_user4 = create_credential(lp, creds)
55 creds_user5 = create_credential(lp, creds)
56 creds_user6 = create_credential(lp, creds)
57 creds_user7 = create_credential(lp, creds)
58
59 class BindTests(samba.tests.TestCase):
60
61     info_dc = None
62
63     def setUp(self):
64         super(BindTests, self).setUp()
65         # fetch rootDSEs
66
67         self.ldb = samba.tests.connect_samdb(host, credentials=creds, lp=lp, ldap_only=True)
68
69         if self.info_dc is None:
70             res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
71             self.assertEqual(len(res), 1)
72             BindTests.info_dc = res[0]
73         # cache some of RootDSE props
74         self.schema_dn = self.info_dc["schemaNamingContext"][0]
75         self.domain_dn = self.info_dc["defaultNamingContext"][0]
76         self.config_dn = self.info_dc["configurationNamingContext"][0]
77         self.realm = self.info_dc["ldapServiceName"][0].split(b'@')[1].decode('utf-8')
78         self.computer_dn = "CN=centos53,CN=Computers,%s" % self.domain_dn
79         self.virtual_user_dn = "CN=frednurk@%s,CN=Computers,%s" % (self.realm, self.domain_dn)
80         self.password = "P@ssw0rd"
81         self.username = "BindTestUser"
82
83     def tearDown(self):
84         delete_force(self.ldb, self.virtual_user_dn)
85         super(BindTests, self).tearDown()
86
87     def test_virtual_email_account_style_bind(self):
88         # create a user in the style often deployed for authentication
89         # of virtual email account at a hosting provider
90         #
91         # The userPrincipalName must not match the samAccountName for
92         # this test to detect when the LDAP DN is being double-parsed
93         # but must be in the user@realm style to allow the account to
94         # be created
95         try:
96             self.ldb.add_ldif("""
97 dn: """ + self.virtual_user_dn + """
98 cn: frednurk@""" + self.realm + """
99 displayName: Fred Nurk
100 sAMAccountName: frednurk@""" + self.realm + """
101 userPrincipalName: frednurk@NOT.""" + self.realm + """
102 countryCode: 0
103 objectClass: computer
104 objectClass: organizationalPerson
105 objectClass: person
106 objectClass: top
107 objectClass: user
108 """)
109         except LdbError as e:
110             (num, msg) = e.args
111             self.fail(f"Failed to create e-mail user: {msg}")
112
113         self.addCleanup(delete_force, self.ldb, self.virtual_user_dn)
114         try:
115             self.ldb.modify_ldif("""
116 dn: """ + self.virtual_user_dn + """
117 changetype: modify
118 replace: unicodePwd
119 unicodePwd:: """ + base64.b64encode(u"\"P@ssw0rd\"".encode('utf-16-le')).decode('utf8') + """
120 """)
121         except LdbError as e:
122             (num, msg) = e.args
123             self.fail(f"Failed to set password on e-mail user: {msg}")
124
125         self.ldb.enable_account('distinguishedName=%s' % self.virtual_user_dn)
126
127         # do a simple bind and search with the machine account
128         creds_virtual.set_bind_dn(self.virtual_user_dn)
129         creds_virtual.set_password(self.password)
130         print("BindTest with: " + creds_virtual.get_bind_dn())
131         try:
132             ldb_virtual = samba.tests.connect_samdb(host, credentials=creds_virtual,
133                                                     lp=lp, ldap_only=True)
134         except LdbError as e:
135             (num, msg) = e.args
136             if num != ERR_INVALID_CREDENTIALS:
137                 raise
138             self.fail(msg)
139
140         res = ldb_virtual.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
141
142     def test_computer_account_bind(self):
143         # create a computer acocount for the test
144         delete_force(self.ldb, self.computer_dn)
145         self.ldb.add_ldif("""
146 dn: """ + self.computer_dn + """
147 cn: CENTOS53
148 displayName: CENTOS53$
149 name: CENTOS53
150 sAMAccountName: CENTOS53$
151 countryCode: 0
152 objectClass: computer
153 objectClass: organizationalPerson
154 objectClass: person
155 objectClass: top
156 objectClass: user
157 codePage: 0
158 userAccountControl: 4096
159 dNSHostName: centos53.alabala.test
160 operatingSystemVersion: 5.2 (3790)
161 operatingSystem: Windows Server 2003
162 """)
163         self.ldb.modify_ldif("""
164 dn: """ + self.computer_dn + """
165 changetype: modify
166 replace: unicodePwd
167 unicodePwd:: """ + base64.b64encode(u"\"P@ssw0rd\"".encode('utf-16-le')).decode('utf8') + """
168 """)
169
170         # do a simple bind and search with the machine account
171         creds_machine.set_bind_dn(self.computer_dn)
172         creds_machine.set_password(self.password)
173         print("BindTest with: " + creds_machine.get_bind_dn())
174         ldb_machine = samba.tests.connect_samdb(host, credentials=creds_machine,
175                                                 lp=lp, ldap_only=True)
176         res = ldb_machine.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
177
178     def test_user_account_bind(self):
179         # create user
180         self.ldb.newuser(username=self.username, password=self.password)
181         ldb_res = self.ldb.search(base=self.domain_dn,
182                                   scope=SCOPE_SUBTREE,
183                                   expression="(samAccountName=%s)" % self.username,
184                                   attrs=["objectSid"])
185         self.assertEqual(len(ldb_res), 1)
186         user_dn = ldb_res[0]["dn"]
187         self.addCleanup(delete_force, self.ldb, user_dn)
188
189         # do a simple bind and search with the user account in format user@realm
190         creds_user1.set_bind_dn(self.username + "@" + creds.get_realm())
191         creds_user1.set_password(self.password)
192         print("BindTest with: " + creds_user1.get_bind_dn())
193         ldb_user1 = samba.tests.connect_samdb(host, credentials=creds_user1,
194                                               lp=lp, ldap_only=True)
195         res = ldb_user1.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
196
197         # do a simple bind and search with the user account in format domain\user
198         creds_user2.set_bind_dn(creds.get_domain() + "\\" + self.username)
199         creds_user2.set_password(self.password)
200         print("BindTest with: " + creds_user2.get_bind_dn())
201         ldb_user2 = samba.tests.connect_samdb(host, credentials=creds_user2,
202                                               lp=lp, ldap_only=True)
203         res = ldb_user2.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
204
205         # do a simple bind and search with the user account DN
206         creds_user3.set_bind_dn(str(user_dn))
207         creds_user3.set_password(self.password)
208         print("BindTest with: " + creds_user3.get_bind_dn())
209         ldb_user3 = samba.tests.connect_samdb(host, credentials=creds_user3,
210                                               lp=lp, ldap_only=True)
211         res = ldb_user3.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
212
213         # do a simple bind and search with the user account SID
214         creds_user5.set_bind_dn(self.ldb.schema_format_value("objectSid", ldb_res[0]["objectSid"][0]).decode('utf8'))
215         creds_user5.set_password(self.password)
216         print("BindTest with: " + creds_user5.get_bind_dn())
217         ldb_user5 = samba.tests.connect_samdb(host, credentials=creds_user5,
218                                               lp=lp, ldap_only=True)
219         res = ldb_user5.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
220
221         # do a simple bind and search with the canonical name
222         creds_user6.set_bind_dn(user_dn.canonical_str())
223         creds_user6.set_password(self.password)
224         print("BindTest with: " + creds_user6.get_bind_dn())
225         ldb_user6 = samba.tests.connect_samdb(host, credentials=creds_user6,
226                                               lp=lp, ldap_only=True)
227         res = ldb_user6.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
228
229         # do a simple bind and search with the extended canonical name
230         creds_user7.set_bind_dn(user_dn.canonical_ex_str())
231         creds_user7.set_password(self.password)
232         print("BindTest with: " + creds_user7.get_bind_dn())
233         ldb_user7 = samba.tests.connect_samdb(host, credentials=creds_user7,
234                                               lp=lp, ldap_only=True)
235         res = ldb_user7.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
236
237     def test_user_account_bind_no_domain(self):
238         # create user
239         self.ldb.newuser(username=self.username, password=self.password)
240         ldb_res = self.ldb.search(base=self.domain_dn,
241                                   scope=SCOPE_SUBTREE,
242                                   expression="(samAccountName=%s)" % self.username)
243         self.assertEqual(len(ldb_res), 1)
244         user_dn = ldb_res[0]["dn"]
245         self.addCleanup(delete_force, self.ldb, user_dn)
246
247         creds_user4.set_username(self.username)
248         creds_user4.set_password(self.password)
249         creds_user4.set_domain('')
250         creds_user4.set_workstation('')
251         print("BindTest (no domain) with: " + self.username)
252         try:
253             ldb_user4 = samba.tests.connect_samdb(host, credentials=creds_user4,
254                                                   lp=lp, ldap_only=True)
255         except:
256             self.fail("Failed to connect without the domain set")
257
258         res = ldb_user4.search(base="", expression="", scope=SCOPE_BASE, attrs=["*"])
259
260
261 TestProgram(module=__name__, opts=subunitopts)