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
Example #2
0
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
		)
Example #4
0
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)
Example #5
0
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)
Example #6
0
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)
Example #7
0
    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]
Example #8
0
	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()
Example #10
0
	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
Example #11
0
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'])
Example #15
0
	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())]})
Example #16
0
    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'])
Example #17
0
	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)
Example #18
0
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]]
    })
Example #19
0
	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
Example #20
0
	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
Example #21
0
 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,
     )
Example #22
0
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(),
    )
Example #23
0
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()),
    )
Example #24
0
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)
Example #25
0
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': []})
Example #26
0
	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
Example #27
0
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')
Example #28
0
 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())]
     })
Example #29
0
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()