def test_create_user(self): user_mod = self.udm.get('users/user') obj = user_mod.new() self.user_objects.append(obj) attrs = { 'firstname': random_username(), 'lastname': random_username(), 'username': random_username(), 'password': random_username(), } self._user0_attrs.update(attrs) print('Creating user with attrs: {!r}'.format(attrs)) for k, v in attrs.items(): setattr(obj.props, k, v) obj.save() print('Created {!r}.'.format(obj)) print('Verifying...') assert obj.props.password != attrs['password'], 'Password was not hased or object not reloaded!' utils.verify_ldap_object( obj.dn, expected_attr={ 'uid': [attrs['username']], 'sn': [attrs['lastname']], 'givenName': [attrs['firstname']], 'displayName': ['{} {}'.format(attrs['firstname'], attrs['lastname'])], }, strict=False, should_exist=True ) obj2 = user_mod.get_by_id(obj.props.username) assert obj2.dn == obj.dn
def test_udm_users_ldap_mspolicy(udm, ucr, module): # bugs: [52446] """Test mspolicy password functionality""" from univention.config_registry import handler_set handler_set(['password/quality/mspolicy=true']) attr = {'name': uts.random_username(), 'pwQualityCheck': 'TRUE'} pol_dn = udm.create_object('policies/pwhistory', wait_for_replication=True, check_for_drs_replication=True, wait_for=True, **attr) utils.wait_for_replication_and_postrun() name = "%s_test1" % (uts.random_username()) attr = { 'password': '******', 'username': name, 'lastname': 'test', 'policy_reference': pol_dn } dn = udm.create_object(module, wait_for_replication=True, check_for_drs_replication=True, wait_for=True, **attr) with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******') with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******' % (name, )) if module == 'users/user': with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******')
def test_modify_user(self): user_mod = self.udm.get('users/user') obj = user_mod.get(self.user_objects[0].dn) attrs = { 'firstname': random_username(), 'lastname': random_username(), 'description': random_string(), 'mailPrimaryAddress': '{}@{}'.format(random_string(), self.mail_domain.lower()), 'departmentNumber': random_string(), } print('Modifying {!r} with attrs: {!r}'.format(obj, attrs)) for k, v in attrs.items(): setattr(obj.props, k, v) obj.save() print('Verifying...') utils.verify_ldap_object( obj.dn, expected_attr={ 'sn': [attrs['lastname']], 'givenName': [attrs['firstname']], 'description': [attrs['description']], 'mailPrimaryAddress': [attrs['mailPrimaryAddress']], 'departmentNumber': [attrs['departmentNumber']], 'displayName': ['{} {}'.format(attrs['firstname'], attrs['lastname'])], }, strict=False, should_exist=True )
def azure_group_args(): name = "{} {}".format(uts.random_username(), uts.random_username()) return dict(description=uts.random_string(), displayName=name, mailEnabled=False, mailNickname=name.replace(" ", "_-_"), securityEnabled=True)
def test_remove_children_missing(ldap_base, schedule_delete_udm_obj, simple_udm): cn_mod = simple_udm.get("container/cn") cn_obj = cn_mod.new(ldap_base) cn_obj.props.name = random_username() cn_obj.save() schedule_delete_udm_obj(cn_obj.dn, "container/cn") cn_obj_dn = cn_obj.dn assert cn_mod.get(cn_obj_dn) users_mod = simple_udm.get("users/ldap") user_obj = users_mod.new() user_obj.position = cn_obj.dn user_obj.props.username = random_username() user_obj.props.password = random_username() user_obj.save() schedule_delete_udm_obj(user_obj.dn, "users/user") user_obj_dn = user_obj.dn user_obj2 = users_mod.get(user_obj_dn) assert user_obj2 assert user_obj2.position == cn_obj_dn with pytest.raises(DeleteError) as excinfo: cn_obj.delete() # default: remove_childs=False assert "Operation not allowed on non-leaf" in str(excinfo.value) assert cn_mod.get(cn_obj_dn) assert users_mod.get(user_obj_dn)
def test_remove_children(ldap_base, schedule_delete_udm_obj, simple_udm): cn_mod = simple_udm.get("container/cn") cn_obj = cn_mod.new(ldap_base) cn_obj.props.name = random_username() cn_obj.save() schedule_delete_udm_obj(cn_obj.dn, "container/cn") cn_obj_dn = cn_obj.dn assert cn_mod.get(cn_obj_dn) users_mod = simple_udm.get("users/ldap") user_obj = users_mod.new() user_obj.position = cn_obj.dn user_obj.props.username = random_username() user_obj.props.password = random_username() user_obj.save() schedule_delete_udm_obj(user_obj.dn, "users/user") user_obj_dn = user_obj.dn user_obj2 = users_mod.get(user_obj_dn) assert user_obj2 assert user_obj2.position == cn_obj_dn cn_obj.delete(remove_childs=True) with pytest.raises(NoObject): cn_mod.get(cn_obj_dn) with pytest.raises(NoObject): users_mod.get(user_obj_dn)
def test_dn_list_property_encoder(self): user_mod = self.udm.get('users/user') obj = user_mod.new() self.user_objects.append(obj) attrs = { 'firstname': random_username(), 'lastname': random_username(), 'username': random_username(), 'password': random_username(), } print('Creating user with attrs: {!r}'.format(attrs)) for k, v in attrs.items(): setattr(obj.props, k, v) obj.save() assert obj.props.secretary.objs == [] obj2 = user_mod.new() self.user_objects.append(obj2) attrs = { 'firstname': random_username(), 'lastname': random_username(), 'username': random_username(), 'password': random_username(), } print('Creating user with attrs: {!r}'.format(attrs)) for k, v in attrs.items(): setattr(obj2.props, k, v) obj2.save() obj.props.secretary.append(obj2.dn) obj.save() assert [o.dn for o in obj.props.secretary.objs] == [obj2.dn]
def create_school_admin(self, ou_name, username=None, schools=None, firstname=None, lastname=None, mailaddress=None, is_active=True, password='******', wait_for_replication=True): position = 'cn=admins,cn=users,%s' % (self.get_ou_base_dn(ou_name)) groups = ["cn=admins-%s,cn=ouadmins,cn=groups,%s" % (ou_name, self.LDAP_BASE)] if username is None: username = uts.random_username() if firstname is None: firstname = uts.random_string(length=10, numeric=False) if lastname is None: lastname = uts.random_string(length=10, numeric=False) if mailaddress is None: mailaddress = '' kwargs = { 'school': ou_name, 'schools': schools, 'username': username, 'firstname': firstname, 'lastname': lastname, 'email': mailaddress, 'password': password, 'disabled': not(is_active), 'options': ['samba', 'ucsschoolAdministrator', 'kerberos', 'posix', 'mail'], } udm = udm_test.UCSTestUDM() dn, school_admin = udm.create_user(position=position, groups=groups, **kwargs) if wait_for_replication: utils.wait_for_replication() return school_admin, dn
def test_modify_error(self): user_mod = self.udm.get('users/user') obj = user_mod.new() self.user_objects.append(obj) attrs = { 'firstname': random_username(), 'lastname': random_username(), 'username': random_username(), 'password': random_username(), } for k, v in attrs.items(): setattr(obj.props, k, v) assert obj.save() obj.props.username = '******' with self.assertRaises(ModifyError): obj.save()
def create_workgroup(self, ou_name, workgroup_name=None, description=None, users=None, wait_for_replication=True): """ Creates a new workgroup in specified ou <ou_name>. If no name for the workgroup is specified, a random name is used. <name> has to be of format "<OU>-<WGNAME>" or "<WGNAME>". Group members may also be specified a list of user DNs in <users>. """ if workgroup_name is None: workgroup_name = uts.random_username() if not workgroup_name.startswith('{}-'.format(ou_name)): workgroup_name = '{}-{}'.format(ou_name, workgroup_name) grp_dn = 'cn={},cn=schueler,cn=groups,ou={},{}'.format(workgroup_name, ou_name, self.LDAP_BASE) kwargs = { 'school': ou_name, 'name': workgroup_name, 'description': description, 'users': users or [], } print('*** Creating new WorkGroup "{}" with {}...'.format(workgroup_name, kwargs)) lo = self.open_ldap_connection() WorkGroup.invalidate_all_caches() WorkGroup.init_udm_module(lo) result = WorkGroup(**kwargs).create(lo) print('*** Result of WorkGroup(...).create(): {}'.format(result)) if wait_for_replication: utils.wait_for_replication() return workgroup_name, grp_dn
def azure_user_args(azure_handler, minimal=True): local_part_email = uts.random_username() domain = azure_handler.get_verified_domain_from_disk() res = dict(accountEnabled=True, displayName=uts.random_string(), immutableId=base64.b64encode(uts.random_string()), mailNickname=local_part_email, passwordProfile=dict(password=azure_handler.create_random_pw(), forceChangePasswordNextLogin=False), userPrincipalName="{0}@{1}".format(local_part_email, domain)) if not minimal: res.update( dict( city=uts.random_string(), country=random.choice( map(itemgetter(0), udm_syntax.Country.choices)), givenName=uts.random_string(), jobTitle=uts.random_string(), otherMails=[ "{}@{}".format(uts.random_string(), uts.random_string()), "{}@{}".format(uts.random_string(), uts.random_string()) ], mobile=uts.random_string(), postalCode=uts.random_string(), physicalDeliveryOfficeName=uts.random_string(), usageLocation=random.choice( map(itemgetter(0), udm_syntax.Country.choices)), streetAddress=uts.random_string(), surname=uts.random_string(), telephoneNumber=uts.random_string(), )) return res
def test_create_user_with_photo(self): user_mod = self.udm.get('users/user') obj = user_mod.new() username = random_username() obj.props.lastname = username obj.props.username = obj.props.lastname obj.props.password = random_string() jpg_content = open( '/usr/share/ucs-test/61_udm-users/example_user_jpeg_photo.jpg', 'rb').read() obj.props.jpegPhoto = jpg_content obj.save() try: obj = user_mod.get(obj.dn) assert obj.props.jpegPhoto.raw == jpg_content assert obj.props.jpegPhoto.content_type.mime_type == 'image/jpeg' assert obj.props.jpegPhoto.content_type.encoding == 'binary' obj_ = user_mod.get(obj.dn) obj_.props.jpegPhoto = obj.props.jpegPhoto obj_.save() obj_ = user_mod.get(obj.dn) assert obj_.props.jpegPhoto.raw == jpg_content assert obj_.props.jpegPhoto.content_type.mime_type == 'image/jpeg' assert obj_.props.jpegPhoto.content_type.encoding == 'binary' finally: obj.delete()
def test_username_matches_users_cn_can_be_created(udm, username): lastname = uts.random_username() user = udm.create_user(username=username, lastname=lastname, firstname='')[0] udm.verify_ldap_object(user, {'cn': [lastname]}) position = get_position(user) udm.create_user(username=lastname, position=position)
def create_user(self, wait_for_replication=True, check_for_drs_replication=True, wait_for=True, **kwargs): # :pylint: disable-msg=W0613 """ Creates a user via UDM CLI. Values for UDM properties can be passed via keyword arguments only and have to exactly match UDM property names (case-sensitive!). Some properties have default values: :param str position: 'cn=users,$ldap_base' :param str password: '******' :param str firstname: 'Foo Bar' :param str lastname: <random string> :param str username: <random string> If username is missing, a random user name will be used. :return: (dn, username) """ attr = self._set_module_default_attr( kwargs, (('position', 'cn=users,%s' % self.LDAP_BASE), ('password', 'univention'), ('username', uts.random_username()), ('lastname', uts.random_name()), ('firstname', uts.random_name()))) return (self.create_object('users/user', wait_for_replication, check_for_drs_replication, wait_for=wait_for, **attr), attr['username'])
def test_modification_of_username(self, udm, random_username, ucr): user, name = udm.create_user() username = random_username() assert name in user assert username not in user user = udm.modify_object('users/user', dn=user, username=username) assert name not in user assert username in user udm.verify_ldap_object(user, {'krb5PrincipalName': ['%s@%s' % (username, ucr['domainname'].upper())]})
def create_ldap_user(self, wait_for_replication=True, check_for_drs_replication=False, **kwargs): # :pylint: disable-msg=W0613 # check_for_drs_replication=False -> ldap users are not replicated to s4 attr = self._set_module_default_attr(kwargs, (('position', 'cn=users,%s' % self.LDAP_BASE), ('password', 'univention'), ('username', uts.random_username()), ('lastname', uts.random_name()), ('name', uts.random_name()))) return (self.create_object('users/ldap', wait_for_replication, check_for_drs_replication, **attr), attr['username'])
def test_prohibited_username_are_checked(self, udm, random_username): username = random_username() udm.create_object('settings/prohibited_username', name='forbidden', usernames=[username]) with pytest.raises(Exception): udm.create_user(username=username) user = udm.create_user()[0] with pytest.raises(Exception): udm.modify_object('user/user', dn=user, username=username)
def test_group_creation_set_single_letter_name_user(udm): """Add user with single letter name to groups/group during creation""" user = udm.create_user(name=uts.random_username(1)) group = udm.create_group(users=user[0])[0] utils.verify_ldap_object(group, { 'uniqueMember': [user[0]], 'memberUid': [user[1]] })
def create_global_user(self, username=None, password='******'): position = 'cn=users,%s' % (self.LDAP_BASE,) udm = udm_test.UCSTestUDM() if username is None: username = uts.random_username() kwargs = { 'username': username, 'password': password, } dn, global_user = udm.create_user(position=position, **kwargs) return global_user, dn
def create_domain_admin(self, ou_name, username=None, password='******'): position = 'cn=admins,cn=users,%s' % (self.get_ou_base_dn(ou_name)) groups = ["cn=Domain Admins,cn=groups,%s" % (self.LDAP_BASE,)] udm = udm_test.UCSTestUDM() if username is None: username = uts.random_username() kwargs = { 'school': ou_name, 'username': username, 'password': password, } dn, domain_admin = udm.create_user(position=position, groups=groups, **kwargs) return domain_admin, dn
def __init__(self, selection=None): super(NormalUser, self).__init__( user={ "username": tstrings.random_username().encode('UTF-8'), "firstname": tstrings.random_name().encode('UTF-8'), "lastname": tstrings.random_name().encode('UTF-8'), "description": random_bytestring(alpha=True, numeric=True), "street": random_bytestring(alpha=True, numeric=True), "city": random_bytestring(alpha=True, numeric=True), "postcode": random_bytestring(numeric=True), "profilepath": random_bytestring(alpha=True, numeric=True), "scriptpath": random_bytestring(alpha=True, numeric=True), "phone": random_bytestring(numeric=True), "homeTelephoneNumber": random_bytestring(numeric=True), "mobileTelephoneNumber": random_bytestring(numeric=True), "pagerTelephoneNumber": random_bytestring(numeric=True), "sambaUserWorkstations": random_bytestring(numeric=True), }, rename={"username": tstrings.random_username().encode('UTF-8')}, container=tstrings.random_name(), selection=selection, )
def random_line_staff(): """create random line to import random staff""" return '%s,%s,%s,%s%s.%s%s.%s,%s,%s\n' % ( uts.random_username(), uts.random_name(), uts.random_name(), uts.random_int(0, 2), uts.random_int(1, 8), uts.random_int(0, 0), uts.random_int(1, 9), uts.random_int(1980, 2014), uts.random_name(), random_email(), )
def random_line_stu_tea(school): """create random line to import random student/teacher/teacher and staff""" return '%s,%s,%s,%s%s.%s%s.%s,%s,%s,%s\n' % ( uts.random_username(), uts.random_name(), uts.random_name(), uts.random_int(1, 2), uts.random_int(1, 8), uts.random_int(0, 0), uts.random_int(1, 9), uts.random_int(1980, 2014), uts.random_name(), random_email(), "{}-{}".format(school, uts.random_string()), )
def test_lookup_with_pagination(udm): """Test serverctrls of ldap server""" pytest.skip('FIXME??? Bug #49638: git:63ba30a2040') from ldap.controls import SimplePagedResultsControl from ldap.controls.sss import SSSRequestControl name = uts.random_username() dns = [ udm.create_user(username=name + str(i), wait_for_replication=False, check_for_drs_replication=False, wait_for=False)[0] for i in range(1, 8) ] print(('Created users:', dns)) univention.admin.modules.update() lo = univention.uldap.getMachineConnection() res = {} page_size = 2 pctrl = SimplePagedResultsControl(True, size=page_size, cookie='') sctrl = SSSRequestControl(ordering_rules=['uid:caseIgnoreOrderingMatch']) users = univention.admin.modules.get('users/user') ctrls = [sctrl, pctrl] entries = [] while True: entries.append([ x.dn for x in users.lookup(None, lo, 'username=%s*' % (name, ), serverctrls=ctrls, response=res) ]) print(('Found', entries[-1])) for control in res['ctrls']: if control.controlType == SimplePagedResultsControl.controlType: pctrl.cookie = control.cookie if not pctrl.cookie: break assert len(entries[-1]) == page_size found = [] for entry in entries: found.extend(entry) assert sorted(found) == sorted(dns)
def test_secretary_reference_update(udm): """Create users/user""" # bugs: [31317,48956] user = udm.create_user()[0] sec = udm.create_user(secretary=user)[0] utils.verify_ldap_object(sec, {'secretary': [user]}) print('1. modrdn: change username', user) user = udm.modify_object('users/user', dn=user, username=uts.random_username()) utils.verify_ldap_object(sec, {'secretary': [user]}) print('2. move into container', user) cn = udm.create_object('container/cn', name='test') user = udm.move_object('users/user', dn=user, position=cn) utils.verify_ldap_object(sec, {'secretary': [user]}) print('3. rename container', user) cn_new = udm.modify_object('container/cn', dn=cn, name='test2') assert cn != cn_new udm._cleanup['users/user'].remove(user) user = user.replace(cn, cn_new) udm._cleanup['users/user'].append(user) cn = cn_new utils.verify_ldap_object(sec, {'secretary': [user]}) print('4. move container', user) cn_new = udm.create_object('container/cn', name='test3') cn_new = udm.move_object('container/cn', dn=cn, position=cn_new) udm._cleanup['users/user'].remove(user) user = user.replace(cn, cn_new) udm._cleanup['users/user'].append(user) cn = cn_new utils.verify_ldap_object(sec, {'secretary': [user]}) print('5. remove user', user) udm.remove_object('users/user', dn=user) utils.verify_ldap_object(sec, {'secretary': []})
def create_school_class(self, ou_name, class_name=None, description=None, users=None, wait_for_replication=True): if class_name is None: class_name = uts.random_username() if not class_name.startswith('{}-'.format(ou_name)): class_name = '{}-{}'.format(ou_name, class_name) grp_dn = 'cn={},cn=klassen,cn=schueler,cn=groups,ou={},{}'.format(class_name, ou_name, self.LDAP_BASE) kwargs = { 'school': ou_name, 'name': class_name, 'description': description, 'users': users or [], } print('*** Creating new school class "{}" with {}...'.format(class_name, kwargs)) lo = self.open_ldap_connection() SchoolClass.invalidate_all_caches() SchoolClass.init_udm_module(lo) result = SchoolClass(**kwargs).create(lo) print('*** Result of SchoolClass(...).create(): {}'.format(result)) if wait_for_replication: utils.wait_for_replication() return class_name, grp_dn
def test_udm_users_user_bcrypt_password(restart_slapd_after_test, udm, ucr): from univention.config_registry import handler_set """Test users/user and users/ldap bcrypt password handling""" # bugs: [52693] handler_set(['ldap/pw-bcrypt=true']) handler_set(['password/hashing/bcrypt=true']) utils.restart_slapd() for module in ['users/user', 'users/ldap']: lo = utils.get_ldap_connection() name = uts.random_username() attr = dict(password='******', username=name, lastname='test') dn = udm.create_object(module, wait_for_replication=True, check_for_drs_replication=True, wait_for=True, **attr) ldap_o = lo.search('uid={}'.format(name), attr=['userPassword', 'pwhistory'])[0] assert ldap_o[1]['userPassword'][0].startswith(b'{BCRYPT}'), ldap_o assert ldap_o[1]['pwhistory'][0].split()[0].startswith( b'{BCRYPT}'), ldap_o # authentication univention.admin.uldap.access(binddn=dn, bindpw='univention') with pytest.raises(univention.admin.uexceptions.authFail): univention.admin.uldap.access(binddn=dn, bindpw='univention1') # password change udm.modify_object(module, dn=dn, password='******') ldap_o = lo.search('uid={}'.format(name), attr=['userPassword', 'pwhistory'])[0] assert ldap_o[1]['userPassword'][0].startswith(b'{BCRYPT}'), ldap_o assert ldap_o[1]['pwhistory'][0].split()[0].startswith( b'{BCRYPT}'), ldap_o assert ldap_o[1]['pwhistory'][0].split()[1].startswith( b'{BCRYPT}'), ldap_o univention.admin.uldap.access(binddn=dn, bindpw='univention1') # password history # TODO how can we check univention.admin.uexceptions.pwalreadyused? with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******') # mixed password history handler_set(['password/hashing/bcrypt=false']) udm.stop_cli_server() udm.modify_object(module, dn=dn, password='******') ldap_o = lo.search('uid={}'.format(name), attr=['userPassword', 'pwhistory'])[0] assert not ldap_o[1]['userPassword'][0].startswith(b'{BCRYPT}'), ldap_o assert ldap_o[1]['pwhistory'][0].split()[0].startswith( b'{BCRYPT}'), ldap_o assert ldap_o[1]['pwhistory'][0].split()[1].startswith( b'{BCRYPT}'), ldap_o assert not ldap_o[1]['pwhistory'][0].split()[2].startswith( b'{BCRYPT}'), ldap_o with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******') with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******') with pytest.raises(udm_test.UCSTestUDM_ModifyUDMObjectFailed): udm.modify_object(module, dn=dn, password='******') # and back handler_set(['password/hashing/bcrypt=true']) udm.stop_cli_server() udm.modify_object(module, dn=dn, password='******') ldap_o = lo.search('uid={}'.format(name), attr=['userPassword', 'pwhistory'])[0] assert ldap_o[1]['userPassword'][0].startswith(b'{BCRYPT}'), ldap_o # disable univention.admin.uldap.access(binddn=dn, bindpw='univention4') udm.modify_object(module, dn=dn, disabled='1') with pytest.raises(univention.admin.uexceptions.authFail): univention.admin.uldap.access(binddn=dn, bindpw='univention4') udm.modify_object(module, dn=dn, disabled='0') univention.admin.uldap.access(binddn=dn, bindpw='univention4') # 2a variant and cost factor handler_set(['password/hashing/bcrypt/prefix=2a']) handler_set(['password/hashing/bcrypt/cost_factor=7']) udm.stop_cli_server() udm.modify_object(module, dn=dn, password='******') ldap_o = lo.search('uid={}'.format(name), attr=['userPassword', 'pwhistory'])[0] assert ldap_o[1]['userPassword'][0].startswith( b'{BCRYPT}$2a$07$'), ldap_o univention.admin.uldap.access(binddn=dn, bindpw='univention5')
def test_modlist_krb_principal(self, udm, random_username, ucr): username = random_username() self._test_modlist(udm, {'username': username}, { 'krb5PrincipalName': ['%s@%s' % (username, ucr['domainname'].upper())] })
class TestUsers(object): """ # TODO: test open() method: 2. if self.exists(): self._unmap_mail_forward() 3. self._load_groups(loadGroups) # TODO: test pre_create() / pre_modify() / pre_ready() method: primaryGroupWithoutSamba different password expiry interval values! is the locking of uidNumber still okay, what if limits are reached? what if pwdChangeNextLogin = 1 and password=foo at the same time? """ def utc_days_since_epoch(): return calendar.timegm(time.gmtime()) / 3600 / 24 @pytest.mark.parametrize( 'shadowLastChange,shadowMax,pwd_change_next_login,password_expiry', [ ('0', '', '1', []), ('0', '0', '1', ['1970-01-01']), ('0', '1', '1', ['1970-01-02']), ('0', str(utc_days_since_epoch() + 2), '1', (datetime.utcnow() + timedelta(days=2)).strftime('%Y-%m-%d')), ('', str(utc_days_since_epoch() + 2), [], []), ('', '', [], []), ('', str(utc_days_since_epoch() - 2), [], []), ('1', str(utc_days_since_epoch() - 2), '1', (datetime.utcnow() - timedelta(days=1)).strftime('%Y-%m-%d')), ('0', str(utc_days_since_epoch() - 2), '1', (datetime.utcnow() - timedelta(days=2)).strftime('%Y-%m-%d')), ]) def test_unmap_pwd_change_next_login_and_password_expiry( self, udm, lo, shadowLastChange, shadowMax, pwd_change_next_login, password_expiry): user = udm.create_user()[0] attr = lo.get(user) ml = [] if shadowLastChange is not None: ml.append(('shadowLastChange', attr.get('shadowLastChange'), shadowLastChange.encode('ASCII'))) if shadowMax is not None: ml.append(('shadowMax', attr.get('shadowMax'), shadowMax.encode('ASCII'))) if ml: lo.modify(user, ml) udm.verify_udm_object( "users/user", user, { "pwdChangeNextLogin": pwd_change_next_login, 'passwordexpiry': password_expiry }) @pytest.mark.parametrize('path', ['/test', '/test2/']) def test_unmap_automount_information(self, udm, path, random_name, lo, verify_udm_object): homeSharePath = random_name() host = random_name() share = udm.create_object('shares/share', name=random_name(), path=path, host=host) user = udm.create_user(homeShare=share, homeSharePath=homeSharePath)[0] udm.verify_udm_object("users/user", user, { "homeShare": share, "homeSharePath": homeSharePath }) udm.verify_ldap_object( user, { 'automountInformation': ['-rw %s:%s/%s' % (host, path.rstrip('/'), homeSharePath)] }) def test_unmap_user_certificate(self, udm, ucr): certificate_binary = subprocess.check_output([ 'openssl', 'x509', '-inform', 'pem', '-in', '/etc/univention/ssl/%(hostname)s/cert.pem' % ucr, '-outform', 'der', '-out', '-' ]) x509 = X509.load_cert_string(certificate_binary, X509.FORMAT_DER) certificateSerial = x509.get_serial_number() certificate = base64.b64encode(certificate_binary).encode('ASCII') certificate_ldap = { 'userCertificate': certificate, 'certificateIssuerCommonName': ucr['ssl/common'], 'certificateIssuerCountry': ucr['ssl/country'], 'certificateIssuerLocation': ucr['ssl/locality'], 'certificateIssuerMail': ucr['ssl/email'], 'certificateIssuerOrganisation': ucr['ssl/organization'], 'certificateIssuerOrganisationalUnit': ucr['ssl/organizationalunit'], 'certificateIssuerState': ucr['ssl/state'], 'certificateSerial': str(certificateSerial), 'certificateSubjectCommonName': '%(hostname)s.%(domainname)s' % ucr, 'certificateSubjectCountry': ucr['ssl/country'], 'certificateSubjectLocation': ucr['ssl/locality'], 'certificateSubjectMail': ucr['ssl/email'], 'certificateSubjectOrganisation': ucr['ssl/organization'], 'certificateSubjectOrganisationalUnit': ucr['ssl/organizationalunit'], 'certificateSubjectState': ucr['ssl/state'], 'certificateVersion': '2', } try: from dateutil import parser except ImportError: pass else: dates = subprocess.check_output( 'openssl x509 -startdate -enddate -noout < /etc/univention/ssl/%(hostname)s/cert.pem' % ucr, shell=True) dates = dict( x.split('=', 1) for x in dates.decode('UTF-8').splitlines()) certificate_ldap.update({ 'certificateDateNotAfter': parser.parse(dates['notAfter']).strftime('%Y-%m-%d'), 'certificateDateNotBefore': parser.parse(dates['notBefore']).strftime('%Y-%m-%d'), }) user = udm.create_user()[0] udm.modify_object('users/user', dn=user, append_option=['pki'], userCertificate=certificate) udm.verify_udm_object('users/user', user, certificate_ldap) def test_unmap_locked(self): pass def test_unmap_disabled(self): pass @pytest.mark.parametrize('samba_sid,samba_rid', [ ('S-1-5-21-1290176872-3541151870-1783641248-14678', '14678'), ]) def test_unmap_samba_rid(self, udm, lo, samba_sid, samba_rid): user = udm.create_user()[0] lo.modify(user, [('sambaSID', [None], samba_sid)]) udm.verify_udm_object('users/user', user, {'sambaRID': samba_rid}) def test_unmap_user_expiry(self): pass def test_unmap_user_password(self, udm, lo): user = udm.create_user(password='******')[0] password = lo.getAttr(user, 'userPassword')[0] udm.verify_udm_object('users/user', user, {'password': password}) def test_mail_primary_group_gets_lowercased(self): pass # TODO: implement create() + modify() def test_uid_gid_number_conflict_is_detected(self): pass def test_locking(self): """ locks (change und create): uidNumber, uid, mailPrimaryAddress locks confirmed after creation/modification locks released after removal locks funktionieren mit case-insensitive """ def test_prohibited_username_are_checked(self, udm, random_username): username = random_username() udm.create_object('settings/prohibited_username', name='forbidden', usernames=[username]) with pytest.raises(Exception): udm.create_user(username=username) user = udm.create_user()[0] with pytest.raises(Exception): udm.modify_object('user/user', dn=user, username=username) def test_modification_of_username(self, udm, random_username, ucr): user, name = udm.create_user() username = random_username() assert name in user assert username not in user user = udm.modify_object('users/user', dn=user, username=username) assert name not in user assert username in user udm.verify_ldap_object(user, { 'krb5PrincipalName': ['%s@%s' % (username, ucr['domainname'].upper())] }) def test_kerberos_values_are_set(self, udm): user = udm.create_user()[0] udm.verify_ldap_object(user, { 'krb5MaxLife': ['86400'], 'krb5MaxRenew': ['604800'], }) @pytest.mark.parametrize( 'privileges', [['SeMachineAccountPrivilege'], ['SeSecurityPrivilege'], ['SeTakeOwnershipPrivilege'], ['SeBackupPrivilege'], ['SeRestorePrivilege'], ['SeRemoteShutdownPrivilege'], ['SePrintOperatorPrivilege'], ['SeAddUsersPrivilege'], ['SeDiskOperatorPrivilege'], [ 'SeMachineAccountPrivilege', 'SeSecurityPrivilege', 'SeTakeOwnershipPrivilege', 'SeBackupPrivilege', 'SeRestorePrivilege', 'SeRemoteShutdownPrivilege', 'SePrintOperatorPrivilege', 'SeAddUsersPrivilege', 'SeDiskOperatorPrivilege', ]]) def test_modlist_samba_privileges(self, udm, privileges): self._test_modlist(udm, {'sambaPrivileges': privileges}, { 'univentionSambaPrivilegeList': privileges, 'objectClass': ['univentionSambaPrivileges'] }) @pytest.mark.parametrize('privileges', [ pytest.mark.xfail( ['SeMachineAccountPrivilege', 'foobar'], reason='https://forge.univention.org/bugzilla/show_bug.cgi?id=46020' ), ['foobar'], ]) def test_modlist_samba_privileges_invalid(self, udm, privileges): with pytest.raises(Exception): udm.create_user(sambaPrivileges=privileges) user = udm.create_user()[0] with pytest.raises(Exception): udm.modify_object('users/user', dn=user, sambaPrivileges=privileges) _modlist_cn_username = random_username() @pytest.mark.parametrize('form,props,cn', [ ('<firstname> <lastname>', { 'firstname': 'X', 'lastname': 'Y' }, 'X Y'), ('<username> <firstname> <lastname>', { 'username': _modlist_cn_username, 'firstname': 'X', 'lastname': 'Y' }, '%s X Y' % (_modlist_cn_username, )), ]) def test_modlist_cn(self, restart_s4connector_if_present, udm, ucr, form, props, cn): try: with UCSTestConfigRegistry(): handler_set( ['directory/manager/usercn/attributes=%s' % (form, )]) # restart udm cli and connector to apply new setting udm.stop_cli_server() restart_s4connector_if_present() self._test_modlist(udm, props, {'cn': [cn]}) finally: udm.stop_cli_server() restart_s4connector_if_present() def _test_modlist(self, udm, props, attrs, **kwargs): if kwargs.get('create', True): user = udm.create_user(**props)[0] udm.verify_ldap_object(user, attrs, strict=False) udm.remove_object('users/user', dn=user) wait_for_connector_replication() if kwargs.get('modify', True): user = udm.create_user()[0] wait_for_connector_replication() user = udm.modify_object('users/user', dn=user, **props) udm.verify_ldap_object(user, attrs, strict=False) @pytest.mark.parametrize( 'props,gecos', [ ({ 'firstname': 'X', 'lastname': 'Y' }, 'X Y'), ({ 'firstname': ' X ', 'lastname': ' Y ' }, 'X Y'), # FIXME: current result looks broken! ({ 'firstname': 'H\xc3\xe4\xc3\xe4lo', 'lastname': 'W\xc3\xb6\xc3\xb6rld' }, 'HAaeAaelo Woeoerld'), # FIXME: current result looks broken! ]) def test_modlist_gecos(self, udm, props, gecos): # TODO: test UCR variable overwrite of '<firstname> <lastname><:umlauts,strip>' # TODO: missing is a check where only lastname or only firstname changes self._test_modlist(udm, props, {'gecos': [gecos]}) @pytest.mark.parametrize( 'props,displayName', [ ({ 'firstname': 'X', 'lastname': 'Y' }, 'X Y'), ({ 'firstname': ' X ', 'lastname': ' Y ' }, 'X Y'), #({'firstname': ' H\xc3\xe4\xc3\xe4lo', 'lastname': 'W\xc3\xb6\xc3\xb6rld '}, 'Hlo W\xc3\xb6\xc3\xb6rld'), # FIXME: pytest crashes! ]) def test_modlist_display_name(self, udm, props, displayName): # TODO: test UCR variable overwrite of '<firstname> <lastname><:strip>' self._test_modlist(udm, props, {'displayName': [displayName]}) def test_modlist_krb_principal(self, udm, random_username, ucr): username = random_username() self._test_modlist(udm, {'username': username}, { 'krb5PrincipalName': ['%s@%s' % (username, ucr['domainname'].upper())] }) def test_lock_unlock_preserves_password(self, udm, lo): user = udm.create_user(password='******')[0] wait_for_connector_replication() password = lo.getAttr(user, 'userPassword')[0] assert password.startswith('{crypt}') udm.modify_object('users/user', dn=user, disabled='1') wait_for_connector_replication() udm.verify_ldap_object( user, {'userPassword': [password.replace('{crypt}', '{crypt}!')]}) udm.modify_object('users/user', dn=user, disabled='0') wait_for_connector_replication() udm.verify_ldap_object(user, {'userPassword': [password]}) def test_disable_enable_preserves_password(self, udm, lo): user = udm.create_user(password='******')[0] wait_for_connector_replication() password = lo.getAttr(user, 'userPassword')[0] udm.modify_object('users/user', dn=user, disabled='1') wait_for_connector_replication() udm.verify_ldap_object( user, {'userPassword': [password.replace('{crypt}', '{crypt}!')]}) udm.modify_object('users/user', dn=user, disabled='0') wait_for_connector_replication() udm.verify_ldap_object(user, {'userPassword': [password]}) @pytest.mark.parametrize('password', [ '{KINIT}', '{SASL}', '{LANMAN}', '{crypt}$6$foo', '{foo}bar', '{SASL}!', '{LANMAN}!', '{crypt}$6$foo!', '{foo}bar!', ]) def test_invalid_password(self, password, udm): with pytest.raises(Exception): udm.create_user(password=password) @pytest.mark.parametrize('disabled,flag,x', [ ('1', '254', {}), ('0', '126', { 'modify': False }), ('none', '126', { 'modify': False }), ('posix', '254', {}), ('windows', '254', {}), ('windows_posix', '254', {}), ('kerberos', '254', {}), ('windows_kerberos', '254', {}), ('posix_kerberos', '254', {}), ('all', '254', {}), ]) def test_modlist_krb5_kdc_flags(self, disabled, flag, x, udm): self._test_modlist(udm, {'disabled': disabled}, {'krb5KDCFlags': [flag]}, **x) def test_modlist_krb5_key(self, udm): pass def test_modlist_krb5_key_version_number(self, udm): user = udm.create_user()[0] udm.verify_ldap_object(user, {'krb5KeyVersionNumber': ['1']}) udm.modify_object('users/user', dn=user, password='******') udm.verify_ldap_object(user, {'krb5KeyVersionNumber': ['2']}) udm.modify_object('users/user', dn=user, password='******') udm.verify_ldap_object(user, {'krb5KeyVersionNumber': ['3']}) def test_modlist_check_password_history(self, udm): pass def test_modlist_check_password_complexity(self, udm): pass def test_modlist_samba_nt_password(self, udm): user = udm.create_user()[0] udm.verify_ldap_object( user, {'sambaNTPassword': ['CAA1239D44DA7EDF926BCE39F5C65D0F']}) udm.modify_object('users/user', dn=user, password='******') udm.verify_ldap_object( user, {'sambaNTPassword': ['1471C3248018E4C973F304762AD312C0']}) udm.modify_object('users/user', dn=user, password='******') udm.verify_ldap_object( user, {'sambaNTPassword': ['5F84B8886B7B0DA26E0A175FEE92A389']}) def test_modlist_samba_lm_password(self, udm): pass def test_modlist_samba_password_history(self, udm): pass @pytest.mark.parametrize('expiry_interval', [ (None), (7), ]) def test_modlist_shadow_max_and_last_change(self, expiry_interval, udm): today = int(time.time()) / 3600 / 24 kw = dict(expiryInterval=expiry_interval ) if expiry_interval is not None else {} pwhistory = udm.create_object('policies/pwhistory', name='pw-test', **kw) cn = udm.create_object('container/cn', name='testusers', policy_reference=pwhistory) shadow_max_expiry = [str(expiry_interval) ] if expiry_interval is not None else [] shadow_max_expiry_1 = [str(expiry_interval) ] if expiry_interval is not None else ['1'] user1 = udm.create_user(position=cn)[0] udm.verify_ldap_object( user1, { 'shadowMax': shadow_max_expiry, 'shadowLastChange': [str(today)] if expiry_interval else [] }) user2 = udm.create_user(position=cn, pwdChangeNextLogin='******')[0] # FIXME?: the following was possible in UCS 4.2 # udm.verify_ldap_object(user2, {'shadowMax': shadow_max_expiry, 'shadowLastChange': [str(today)]}) user3 = udm.create_user(position=cn, pwdChangeNextLogin='******')[0] udm.verify_ldap_object( user3, { 'shadowMax': shadow_max_expiry_1, 'shadowLastChange': [ str(today - expiry_interval - 1) if expiry_interval else str(today - 2) ] }) udm.modify_object('users/user', dn=user1, password='******') udm.verify_ldap_object( user1, { 'shadowMax': shadow_max_expiry, 'shadowLastChange': [str(today)] if expiry_interval else [] }) udm.modify_object('users/user', dn=user2, password='******', pwdChangeNextLogin='******') udm.verify_ldap_object( user2, { 'shadowMax': shadow_max_expiry_1, 'shadowLastChange': [ str(today - expiry_interval - 1) if expiry_interval else str(today - 2) ] }) # Bug #46067: udm.modify_object('users/user', dn=user3, password='******', pwdChangeNextLogin='******') #udm.verify_ldap_object(user3, {'shadowMax': shadow_max_expiry_1, 'shadowLastChange': [str(today - expiry_interval - 1)]}) def test_modlist_samba_pwd_last_set(self, udm, lo): self._test_modlist(udm, {'pwdChangeNextLogin': '******'}, {'sambaPwdLastSet': ['0']}) self._test_modlist(udm, { 'password': '******', 'pwdChangeNextLogin': '******' }, {'sambaPwdLastSet': ['0']}) prior = int(time.time()) user = udm.create_user()[0] after = int(time.time()) last_set = int(lo.get(user)['sambaPwdLastSet'][0]) assert prior <= last_set <= after def test_modlist_krb_password_end(self, udm): expiry_interval = 7 pwhistory = udm.create_object('policies/pwhistory', name='pw-test', expiryInterval=expiry_interval) cn = udm.create_object('container/cn', name='testusers', policy_reference=pwhistory) expiry = int(time.time()) password_end = time.strftime("%Y%m%d000000Z", time.gmtime(expiry)) #password_end_policy = time.strftime("%Y%m%d000000Z", time.gmtime(expiry + expiry_interval * 3600 * 24)) self._test_modlist(udm, {'pwdChangeNextLogin': '******'}, {'krb5PasswordEnd': [password_end]}) self._test_modlist(udm, { 'pwdChangeNextLogin': '******', 'password': '******' }, {'krb5PasswordEnd': []}) self._test_modlist(udm, { 'pwdChangeNextLogin': '******', 'position': cn }, {'krb5PasswordEnd': [password_end]}) # FIXME: correct would be: self._test_modlist(udm, {'pwdChangeNextLogin': '******', 'password': '******', 'position': cn}, {'krb5PasswordEnd': [password_end_policy]}) self._test_modlist(udm, { 'pwdChangeNextLogin': '******', 'password': '******', 'position': cn }, {'krb5PasswordEnd': []}) def test_user_password_is_cryped(self, udm, lo): user = udm.create_user(password='******')[0] password = lo.getAttr(user, 'userPassword')[0] assert password.startswith('{crypt}') udm.modify_object('users/user', dn=user, password='******') password2 = lo.getAttr(user, 'userPassword')[0] assert password2.startswith('{crypt}') assert password2 != password def test_modlist_samba_bad_pw_count(self, udm, lo): user = udm.create_user()[0] locktime = time.strftime("%Y%m%d%H%M%SZ", time.gmtime()) old = lo.get(user) subprocess.call([ 'python', '-m', 'univention.lib.account', 'lock', '--dn', user, '--lock-time', locktime ]) lo.modify(user, [('sambaBadPasswordCount', '0', '20')]) new = lo.get(user) print((locktime, old, new)) udm.modify_object('users/user', dn=user, locked='0') try: udm.modify_object('users/user', dn=user, locked='0') except UCSTestUDM_NoModification: # ignore this, maybe the connector already unlocked the user # in this case sambaBadPasswordCount should be correctly # set to 0 by the connector pass udm.verify_ldap_object(user, {'sambaBadPasswordCount': ['0']}) @pytest.mark.xfail(reason='Not migrated since Bug #39817') @pytest.mark.parametrize('props,flags', [ ({ 'locked': 'none', 'description': 'asdf' }, ['[U ]']), ({ 'locked': 'all' }, ['[UL ]']), ({ 'disabled': 'all' }, ['[UD ]']), ({ 'disabled': 'none', 'description': 'asdf' }, ['[U ]']), ({ 'locked': 'all', 'disabled': 'all' }, ['[UDL ]']), ({ 'locked': 'none', 'disabled': 'none', 'description': 'asdf' }, ['[U ]']), ]) def test_modlist_sambaAcctFlags(self, udm, props, flags): self._test_modlist(udm, props, {'sambaAcctFlags': flags}) @pytest.mark.parametrize('userexpiry,kick_off,x', [ ('2018-01-01', [str(int(time.mktime(time.strptime('2018-01-01', "%Y-%m-%d"))))], {}), ('', [], { 'modify': False }), ]) def test_modlist_samba_kickoff_time(self, userexpiry, kick_off, x, udm): self._test_modlist(udm, {'userexpiry': userexpiry}, {'sambaKickoffTime': kick_off}, **x) @pytest.mark.parametrize('userexpiry,valid_end,x', [ ('2018-01-01', ['20180101000000Z'], {}), ('', [], { 'modify': False }), ]) def test_modlist_krb5_valid_end(self, udm, userexpiry, valid_end, x): self._test_modlist(udm, {'userexpiry': userexpiry}, {'krb5ValidEnd': valid_end}, **x) @pytest.mark.parametrize('disabled,userexpiry,shadow_expire', [ ('none', '2018-01-01', [ str( int( time.mktime(time.strptime('2018-01-01', "%Y-%m-%d")) / 3600 / 24 + 1)) ]), ('all', '2018-01-01', [ str( int( time.mktime(time.strptime('2018-01-01', "%Y-%m-%d")) / 3600 / 24 + 1)) ]), ('posix', '2018-01-01', [ str( int( time.mktime(time.strptime('2018-01-01', "%Y-%m-%d")) / 3600 / 24 + 1)) ]), ('posix_kerberos', '2018-01-01', [ str( int( time.mktime(time.strptime('2018-01-01', "%Y-%m-%d")) / 3600 / 24 + 1)) ]), ('windows_posix', '2018-01-01', [ str( int( time.mktime(time.strptime('2018-01-01', "%Y-%m-%d")) / 3600 / 24 + 1)) ]), ('kerberos', '', []), ('all', '', ['1']), ('posix', '', ['1']), ('posix_kerberos', '', ['1']), ('windows_posix', '', ['1']), ]) def test_modlist_shadow_expire(self, disabled, userexpiry, shadow_expire, udm): self._test_modlist(udm, { 'disabled': disabled, 'userexpiry': userexpiry }, {'shadowExpire': shadow_expire}) def test_modlist_mail_forward(self, udm): pass @pytest.mark.parametrize('birthday', [ ['2009-213'], ['2009-05'], ['2009-05-13'], ['2009-W21'], ['2009-W21-4'], ]) def test_modlist_univention_person_birthday(self, udm, birthday): self._test_modlist(udm, {'birthday': birthday[0]}, { 'univentionBirthday': birthday, 'objectClass': ['univentionPerson'] }) def test_modlist_univention_person(self, udm): self._test_modlist(udm, { 'umcProperty': ['foo bar'], 'birthday': '2009-05-13' }, { 'univentionBirthday': ['2009-05-13'], 'univentionUMCProperty': ['foo=bar'], 'objectClass': ['univentionPerson'] }) self._test_modlist(udm, {'umcProperty': ['foo bar']}, { 'univentionUMCProperty': ['foo=bar'], 'objectClass': ['univentionPerson'] }) def test_modlist_home_share(self, udm): pass def test_modlist_samba_sid(self, udm): pass
def username(): return uts.random_username()