|
Lines 1-12
Link Here
|
| 1 |
#!/usr/share/ucs-test/runner python |
1 |
#!/usr/share/ucs-test/runner python |
| 2 |
## -*- coding: utf-8 -*- |
2 |
## -*- coding: utf-8 -*- |
| 3 |
## desc: remove illegal characters from username (Bug 42313) |
3 |
## desc: test UsernameHandler with --dry-run (Bug 42465) |
| 4 |
## tags: [apptest,ucsschool,skip_in_multiserver,ucsschool_import] |
4 |
## tags: [apptest,ucsschool,skip_in_multiserver,ucsschool_import] |
| 5 |
## roles: [domaincontroller_master] |
5 |
## roles: [domaincontroller_master] |
| 6 |
## exposure: dangerous |
6 |
## exposure: dangerous |
| 7 |
## packages: |
7 |
## packages: |
| 8 |
## - ucs-school-import |
8 |
## - ucs-school-import |
| 9 |
## bugs: [42313] |
9 |
## bugs: [42465] |
| 10 |
|
10 |
|
| 11 |
import copy |
11 |
import copy |
| 12 |
import string |
12 |
import string |
|
Lines 18-25
Link Here
|
| 18 |
from univention.testing.ucs_samba import wait_for_drs_replication |
18 |
from univention.testing.ucs_samba import wait_for_drs_replication |
| 19 |
from univention.admin.uldap import getAdminConnection |
19 |
from univention.admin.uldap import getAdminConnection |
| 20 |
from univention.admin.uexceptions import noObject, ldapError |
20 |
from univention.admin.uexceptions import noObject, ldapError |
| 21 |
from ucsschool.importer.utils.username_handler import UsernameHandler |
|
|
| 22 |
from ucsschool.importer.exceptions import FormatError |
| 23 |
from essential.importusers import Person |
21 |
from essential.importusers import Person |
| 24 |
from essential.importusers_cli_v2 import CLI_Import_v2_Tester |
22 |
from essential.importusers_cli_v2 import CLI_Import_v2_Tester |
| 25 |
|
23 |
|
|
Lines 46-52
Link Here
|
| 46 |
self.log.error("DN %r -> %s", dn, exc) |
44 |
self.log.error("DN %r -> %s", dn, exc) |
| 47 |
super(Test, self).cleanup() |
45 |
super(Test, self).cleanup() |
| 48 |
|
46 |
|
| 49 |
def test(self): # formally test_create_with_illegal_chars_in_username() |
47 |
def test(self): |
| 50 |
""" |
48 |
""" |
| 51 |
Bug #42313: remove illegal characters from username |
49 |
Bug #42313: remove illegal characters from username |
| 52 |
* "Username must only contain numbers, letters and dots, and may not be 'admin'!" |
50 |
* "Username must only contain numbers, letters and dots, and may not be 'admin'!" |
|
Lines 62-204
Link Here
|
| 62 |
name = name.strip(".") |
60 |
name = name.strip(".") |
| 63 |
return name.translate(None, bad_chars) |
61 |
return name.translate(None, bad_chars) |
| 64 |
|
62 |
|
| 65 |
for role in ('student', 'teacher', 'teacher_and_staff'): |
63 |
random_puncts = list(string.punctuation) |
| 66 |
random_puncts = list(string.punctuation) |
64 |
random.shuffle(random_puncts) |
| 67 |
random.shuffle(random_puncts) |
65 |
lastname = uts.random_username(20) |
| 68 |
lastnames = ["{}{}{}".format(uts.random_username(5), x, uts.random_username(5)) for x in random_puncts[:4]] |
66 |
self.unique_basenames_to_remove.append(lastname) |
| 69 |
lastnames.append(".{}".format(uts.random_username())) |
67 |
self.log.info("Testing with dry_run=False and lastname=%r which will be shortened to %r...", lastname, lastname[:12]) |
| 70 |
lastnames.append(".{}.{}.".format(uts.random_username(4), uts.random_username(4))) |
|
|
| 71 |
lastnames.append("{}[{}]{}".format(uts.random_username(3), uts.random_username(3), uts.random_username(3))) |
| 72 |
lastnames.append(uts.random_username(40)) |
| 73 |
self.unique_basenames_to_remove.extend(lastnames) |
| 74 |
self.log.info('*** Importing new users with role %r and the following lastnames:\n%r', role, lastnames) |
| 75 |
|
68 |
|
| 76 |
config = copy.deepcopy(self.default_config) |
69 |
role = 'student' |
| 77 |
source_uid = 'sourceUID-%s' % (uts.random_string(),) |
70 |
record_uid = uts.random_name() |
| 78 |
config.update_entry('sourceUID', source_uid) |
71 |
person = Person(self.ou_A.name, role) |
| 79 |
config.update_entry('scheme:recordUID', '<record_uid>') |
72 |
source_uid = 'sourceUID-%s' % (uts.random_string(),) |
| 80 |
config.update_entry('user_role', role) |
73 |
person.update(record_uid=record_uid, source_uid=source_uid, lastname=lastname) |
| 81 |
config.update_entry('csv:mapping:recordUID', 'record_uid') |
|
|
| 82 |
config.update_entry('scheme:username:default', "<lastname>[ALWAYSCOUNTER]") |
| 83 |
|
74 |
|
| 84 |
persons = list() |
75 |
config = copy.deepcopy(self.default_config) |
| 85 |
names = dict() |
76 |
config.update_entry('sourceUID', source_uid) |
| 86 |
for lastname in lastnames: |
77 |
config.update_entry('scheme:recordUID', '<record_uid>') |
| 87 |
record_uid = uts.random_name() |
78 |
config.update_entry('user_role', role) |
| 88 |
person = Person(self.ou_A.name, role) |
79 |
config.update_entry('csv:mapping:recordUID', 'record_uid') |
| 89 |
person.update(record_uid=record_uid, source_uid=source_uid, lastname=lastname) |
80 |
config.update_entry('scheme:username:default', "<lastname>[ALWAYSCOUNTER]") |
| 90 |
persons.append(person) |
81 |
fn_csv = self.create_csv_file(person_list=[person], mapping=config['csv']['mapping']) |
| 91 |
names[person] = lastname |
82 |
config.update_entry('input:filename', fn_csv) |
| 92 |
fn_csv = self.create_csv_file(person_list=persons, mapping=config['csv']['mapping']) |
83 |
fn_config = self.create_config_json(config=config) |
| 93 |
config.update_entry('input:filename', fn_csv) |
|
|
| 94 |
fn_config = self.create_config_json(config=config) |
| 95 |
|
84 |
|
| 96 |
# save ldap state for later comparison |
85 |
self.save_ldap_status() |
| 97 |
self.save_ldap_status() |
86 |
self.run_import(['-c', fn_config, '-i', fn_csv]) |
| 98 |
# start import |
87 |
utils.wait_for_replication() |
| 99 |
self.run_import(['-c', fn_config, '-i', fn_csv]) |
88 |
self.check_new_and_removed_users(1, 0) |
| 100 |
utils.wait_for_replication() |
89 |
person.update(username=remove_bad_chars("{}1".format(lastname[:12]))) |
| 101 |
# check for new users in LDAP |
90 |
utils.verify_ldap_object(person.dn, expected_attr={'uid': [person.username]}, strict=False, should_exist=True) |
| 102 |
self.check_new_and_removed_users(len(persons), 0) |
91 |
wait_for_drs_replication('cn={}'.format(escape_filter_chars(person.username))) # wait for creation before deletion |
| 103 |
# check usernames |
|
|
| 104 |
for person, lastname in names.items(): |
| 105 |
person.update(username=remove_bad_chars("{}1".format(lastname[:12]))) |
| 106 |
utils.verify_ldap_object(person.dn, expected_attr={'uid': [person.username]}, strict=False, should_exist=True) |
| 107 |
wait_for_drs_replication('cn={}'.format(escape_filter_chars(person.username))) # wait for creation before deletion |
| 108 |
|
92 |
|
| 109 |
# delete users |
93 |
# delete user |
| 110 |
self.log.info('*** Deleting users with role %r and the following lastnames:\n%r', role, lastnames) |
94 |
self.log.info('*** Deleting user with lastname=%r', lastname) |
| 111 |
fn_csv = self.create_csv_file(person_list=[], mapping=config['csv']['mapping']) |
95 |
fn_csv = self.create_csv_file(person_list=[], mapping=config['csv']['mapping']) |
| 112 |
config.update_entry('input:filename', fn_csv) |
96 |
config.update_entry('input:filename', fn_csv) |
| 113 |
fn_config = self.create_config_json(config=config) |
97 |
fn_config = self.create_config_json(config=config) |
| 114 |
self.save_ldap_status() |
98 |
self.save_ldap_status() |
| 115 |
self.run_import(['-c', fn_config, '-i', fn_csv]) |
99 |
self.run_import(['-c', fn_config, '-i', fn_csv]) |
| 116 |
utils.wait_for_replication() |
100 |
utils.wait_for_replication() |
| 117 |
|
101 |
|
| 118 |
# recreate users, but move position of COUNTER variable |
102 |
# recreate user with dry_run |
| 119 |
self.log.info( |
103 |
self.log.info('*** Importing user with the same lastname with --dry_run') |
| 120 |
'*** Importing users with role %r and the same lastnames, but move position of COUNTER variable:\n%r', |
104 |
# Prevent 'The email address is already taken by another user. Please change the email address.' |
| 121 |
role, |
105 |
# because of slow s4 replication. Username is the same, so it doesn't change what's tested. |
| 122 |
lastnames) |
106 |
person.mail = '{}{}'.format(uts.random_username(4), person.mail) |
| 123 |
config.update_entry('scheme:username:default', "[ALWAYSCOUNTER]<lastname>") |
107 |
fn_csv = self.create_csv_file(person_list=[person], mapping=config['csv']['mapping']) |
| 124 |
for person in persons: |
108 |
config.update_entry('input:filename', fn_csv) |
| 125 |
# Prevent 'The email address is already taken by another user. Please change the email address.' |
109 |
fn_config = self.create_config_json(config=config) |
| 126 |
# because of slow s4 replication. Username is the same, so it doesn't change what's tested. |
110 |
self.save_ldap_status() |
| 127 |
person.mail = '{}{}'.format(uts.random_username(4), person.mail) |
111 |
self.run_import(['-c', fn_config, '-i', fn_csv, '--dry-run']) |
| 128 |
fn_csv = self.create_csv_file(person_list=persons, mapping=config['csv']['mapping']) |
112 |
utils.wait_for_replication() |
| 129 |
config.update_entry('input:filename', fn_csv) |
113 |
utils.verify_ldap_object(person.dn, should_exist=False) |
| 130 |
fn_config = self.create_config_json(config=config) |
114 |
person.update(username=remove_bad_chars("{}2".format(lastname[:12]))) |
| 131 |
self.save_ldap_status() |
115 |
utils.verify_ldap_object(person.dn, should_exist=False) |
| 132 |
self.run_import(['-c', fn_config, '-i', fn_csv]) |
|
|
| 133 |
utils.wait_for_replication() |
| 134 |
for person, lastname in names.items(): |
| 135 |
person.update(username=remove_bad_chars("2{}".format(lastname[:12]))) |
| 136 |
utils.verify_ldap_object(person.dn, expected_attr={'uid': [person.username]}, strict=False, should_exist=True) |
| 137 |
|
116 |
|
| 138 |
self.log.info('*** Starting unit test for UsernameHandler.format_username() (1/5)') |
117 |
lo, po = getAdminConnection() |
| 139 |
unh = UsernameHandler(15) # 20 - len("exam-") |
118 |
utils.verify_ldap_object( |
| 140 |
name12 = uts.random_username(12) # 15 - 3 |
119 |
"cn={},cn=unique-usernames,cn=ucsschool,cn=univention,{}".format(escape_dn_chars(lastname[:12]), lo.base), |
| 141 |
usernames = { |
120 |
expected_attr={'ucsschoolUsernameNextNumber': ['2']}, |
| 142 |
".abc.def.": "abc.def", |
121 |
strict=False, |
| 143 |
"...abc...def...": "abc...def", |
122 |
should_exist=True) |
| 144 |
"": None, |
|
|
| 145 |
"..[ALWAYSCOUNTER]..": None, |
| 146 |
"[ALWAYSCOUNTER]": None, |
| 147 |
"[FOObar]": "FOObar", |
| 148 |
"{}.[COUNTER2]".format(name12): name12, |
| 149 |
".": None, |
| 150 |
'M'*14 + '.' + 'A': 'M' * 14, |
| 151 |
} |
| 152 |
for input_name, expected in usernames.items(): |
| 153 |
try: |
| 154 |
out = unh.format_username(input_name) |
| 155 |
self.unique_basenames_to_remove.append(expected) |
| 156 |
if out != expected: |
| 157 |
self.fail("UsernameHandler.format_username(%r) returned %r, expected %r." % (input_name, out, expected)) |
| 158 |
except FormatError: |
| 159 |
if expected is not None: |
| 160 |
self.fail("UsernameHandler.format_username(%r) raise a FormatError, expected it to return %r." % (input_name, expected)) |
| 161 |
continue |
| 162 |
self.log.info('*** Starting unit test for UsernameHandler.format_username() (2/5)') |
| 163 |
for i in range(1000): |
| 164 |
name = uts.random_username(15) |
| 165 |
self.unique_basenames_to_remove.append(name) |
| 166 |
out = unh.format_username(name) |
| 167 |
if out != name: |
| 168 |
self.fail("UsernameHandler.format_username(%r) returned %r." % (name, out)) |
| 169 |
self.log.info('*** Starting unit test for UsernameHandler.format_username() (3/5)') |
| 170 |
for i in range(1000): |
| 171 |
name = uts.random_name(20) |
| 172 |
self.unique_basenames_to_remove.append(name) |
| 173 |
out = unh.format_username(name) |
| 174 |
if out.startswith(".") or out.endswith(".") or len(out) > 15: |
| 175 |
self.fail("UsernameHandler.format_username(%r) returned %r." % (name, out)) |
| 176 |
self.log.info('*** Starting unit test for UsernameHandler.format_username() (4/5)') |
| 177 |
for i in range(1000): |
| 178 |
name = uts.random_name_special_characters(20) |
| 179 |
name = name.translate(None, "[]") # those are reserved for counter vars |
| 180 |
self.unique_basenames_to_remove.append(name) |
| 181 |
out = unh.format_username(name) |
| 182 |
if out.startswith(".") or out.endswith(".") or len(out) > 15: |
| 183 |
self.fail("UsernameHandler.format_username(%r) returned %r." % (name, out)) |
| 184 |
self.log.info('*** Starting unit test for UsernameHandler.format_username() (5/5)') |
| 185 |
usernames = [ |
| 186 |
('Max[ALWAYSCOUNTER].Mustermann', 'Max1.Mustermann'), |
| 187 |
('Max[ALWAYSCOUNTER].Mustermann', 'Max2.Mustermann'), |
| 188 |
('Max[ALWAYSCOUNTER].Mustermann', 'Max3.Mustermann'), |
| 189 |
('Max[ALWAYSCOUNTER].Mustermann', 'Max4.Mustermann'), |
| 190 |
('Maria[ALWAYSCOUNTER].Musterfrau', 'Maria1.Musterfrau'), |
| 191 |
('Moritz[COUNTER2]', 'Moritz'), |
| 192 |
('Moritz[COUNTER2]', 'Moritz2') |
| 193 |
] |
| 194 |
self.unique_basenames_to_remove.extend(["Max.Mustermann", "Maria.Musterfrau", "Moritz"]) |
| 195 |
unh = UsernameHandler(20) |
| 196 |
for input_name, expected in usernames: |
| 197 |
out = unh.format_username(input_name) |
| 198 |
if out != expected: |
| 199 |
self.fail("UsernameHandler.format_username(%r) returned %r, expected %r." % (input_name, out, expected)) |
| 200 |
|
123 |
|
|
|
124 |
self.log.info('*** OK: Import with --dry_run didn\'t raise the counter.') |
| 201 |
|
125 |
|
|
|
126 |
|
| 202 |
def main(): |
127 |
def main(): |
| 203 |
tester = Test() |
128 |
tester = Test() |
| 204 |
try: |
129 |
try: |