async def test_create_user(fake_user, udm_kwargs):
    user_data = fake_user()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.new()
        obj.policies = user_data.policies
        obj.superordinate = user_data.superordinate
        obj.position = user_data.position
        obj.options = user_data.options
        for k, v in attr.asdict(user_data.props).items():
            setattr(obj.props, k, v)
        assert obj.dn is None
        assert obj.uri == ""

        res = await obj.save()

        assert res is obj
        assert obj.dn not in (None, "")
        assert obj.uri not in (None, "")

        obj_new = await mod.get(obj.dn)
        assert obj_new.dn == obj.dn
        assert obj_new.position == obj.position
        assert obj_new.props.firstname == obj.props.firstname
        assert obj_new.props.lastname == obj.props.lastname
        assert obj_new.props.birthday == obj.props.birthday

        await obj.delete()
async def test_session_base_dn(base_dn, udm_kwargs):
    base_dn_via_ldap = base_dn

    async with UDM(**udm_kwargs) as udm:
        base_dn_via_http = await udm.session.base_dn

    assert base_dn_via_http == base_dn_via_ldap
async def test_saving_stale_obj_fails(user_created_via_http, udm_kwargs,
                                      random_name):
    # scenario: a different channel was used to delete or rename the obj on
    # the server directly after saving it, so that a reload() fails, then it
    # should not be possible to save() again
    dn, url, user = user_created_via_http()

    async def _func():
        pass

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.uri == url
        assert obj.props.firstname == user["properties"]["firstname"]
        # OK, got a valid object from LDAP, now modify it but skip the reload
        obj.props.firstname = random_name()
        obj.reload = _func
        await obj.save()
        obj.props.firstname = random_name()

        with warnings.catch_warnings(record=True) as caught_warnings:
            await obj.save()
        assert base_http.StaleObjectWarning in [
            w.category for w in caught_warnings
        ]
def test_session_warn_insecure_request():
    for i in range(4, 10):
        with warnings.catch_warnings(record=True) as w:
            UDM("A", "B", "http://foo.bar/baz")
            assert len(w) == 1
            assert issubclass(w[-1].category, base_http.InsecureRequestWarning)
            assert "unencrypted" in str(w[-1].message)
async def test_openapi_class(udm_kwargs):
    async with UDM(**udm_kwargs) as udm:
        for name in ("groups/group", "shares/share", "users/user"):
            mod = udm.get(name)
            kls = mod.session.openapi_class(name)
            assert inspect.isclass(kls)
            assert kls.__name__.endswith("Api")
async def test_move_user(new_cn, user_created_via_http, udm_kwargs):
    old_user_dn, old_user_url, old_user_data = user_created_via_http()
    cn_dn, cn_obj_url, cn_data = new_cn()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(old_user_dn)
        assert obj.dn == old_user_dn
        assert obj.uri == old_user_url
        assert obj.position == old_user_data["position"]
        assert obj.props.firstname == old_user_data["properties"]["firstname"]

        obj.position = cn_dn
        res = await obj.save()
        assert res is obj
        assert obj.dn != old_user_dn
        assert obj.dn == f"uid={obj.props.username},{cn_dn}"
        assert obj.uri != old_user_url
        from urllib.parse import unquote

        assert unquote(
            obj.uri) == old_user_url.rsplit("/", 1)[0] + "/" + obj.dn

        obj_new = await mod.get(obj.dn)
        assert obj_new.dn == obj.dn
        assert obj_new.uri == obj.uri
        assert obj_new.position == cn_dn
        assert obj.props.firstname == old_user_data["properties"]["firstname"]
async def test_move_multiple_objects(base_dn, new_cn, user_created_via_http,
                                     udm_kwargs):
    top_cn_dn, top_cn_obj_url, top_cn_data = new_cn()
    old_cn_dn, old_cn_obj_url, old_cn_data = new_cn(position=top_cn_dn)
    cn_name = old_cn_data["properties"]["name"]
    users = dict(
        (num, user_created_via_http(position=old_cn_dn)) for num in range(20))
    with patch.object(base_http, "MIN_FOLLOW_REDIRECT_SLEEP_TIME", 3.0):
        async with UDM(**udm_kwargs) as udm:
            mod_user = udm.get("users/user")
            for dn, url, data in users.values():
                user_obj = await mod_user.get(dn)
                assert user_obj.position == old_cn_dn

            mod_cn = udm.get("container/cn")
            cn_obj = await mod_cn.get(old_cn_dn)
            assert cn_obj.dn == old_cn_dn
            assert cn_obj.dn != base_dn

            cn_obj.position = base_dn
            await cn_obj.save()

            assert cn_obj.dn == f"cn={cn_name},{base_dn}"

            for dn, url, data in users.values():
                query = dn.split(",", 1)[0]
                async for obj in mod_user.search(query):
                    assert old_cn_dn not in obj.dn
                    assert obj.position == cn_obj.dn
                    assert obj.dn == f"uid={data['properties']['username']},{cn_obj.dn}"
async def test_reload_new_obj(udm_kwargs):
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.new()
        assert obj.dn is None
        assert obj.uri == ""
        with pytest.raises(NotYetSavedError):
            await obj.reload()
async def test_openapi_method(udm_kwargs):
    async with UDM(**udm_kwargs) as udm:
        for name in ("groups/group", "shares/share", "users/user"):
            mod = udm.get(name)
            kls = mod.session.openapi_class(name)
            name_snake_case = "_".join(s.lower() for s in name.split("/"))
            for meth in base_http.METHOD_NAMES.values():
                assert hasattr(kls, meth.format(name_snake_case))
async def test_bad_credentials(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()
    bad_kwargs = udm_kwargs.copy()
    bad_kwargs["password"] = f"A{udm_kwargs['password']}B"
    async with UDM(**bad_kwargs) as udm:
        mod = udm.get("users/user")
        with pytest.raises(APICommunicationError) as exc_info:
            await mod.get(dn)
        assert exc_info.value.status == 401
async def test_get_no_object(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()
    dn_parts = dn.split(",")
    wrong_dn = f"{dn_parts[0]}a,{','.join(dn_parts[1:])}"

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        with pytest.raises(NoObject):
            await mod.get(wrong_dn)
async def test_udm_obj_by_dn_good_dn(udm_kwargs, user_created_via_http):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        obj = await udm.obj_by_dn(dn)
    assert obj.dn == dn
    assert obj.uri == url
    assert obj.position == user["position"]
    assert obj.props.firstname == user["properties"]["firstname"]
    assert obj.props.lastname == user["properties"]["lastname"]
async def test_get_users_self_redirects_to_users_user(
        udm_kwargs, test_server_configuration):
    administrator_dn = test_server_configuration.user_dn

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/self")
        obj = await mod.get(administrator_dn)
    assert obj.dn == administrator_dn
    assert obj.props.username == "Administrator"
    assert obj._udm_module.name == "users/user"
def test_session_warn_min_client_tasks():
    for i in range(-10, 10):
        with warnings.catch_warnings(record=True) as w:
            udm = UDM("A", "B", "https://foo.bar/baz", max_client_tasks=i)
            assert udm.session.max_client_tasks >= 4
            assert (udm.session.openapi_client_config.connection_pool_maxsize
                    >= udm.session.max_client_tasks)
            if i < 4:
                assert len(w) == 1
                assert issubclass(w[-1].category, base_http.BadSettingsWarning)
                assert "max_client_tasks" in str(w[-1].message)
async def test_search_existing_user(user_created_via_http, udm_kwargs):
    dn, url, data = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        query = dn.split(",", 1)[0]
        async for obj in mod.search(query):
            assert obj.dn == dn
            assert obj.uri == url
            assert obj.position == data["position"]
            assert obj.props.firstname == data["properties"]["firstname"]
            assert obj.props.lastname == data["properties"]["lastname"]
async def test_delete_non_existent_user_is_ignored(user_created_via_http,
                                                   udm_kwargs):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj1 = await mod.get(dn)
        obj2 = await mod.get(dn)
        await obj1.delete()
        with pytest.raises(NoObject):
            await mod.get(dn)
        await obj2.delete()
async def test_move_error(base_dn, random_name, user_created_via_http,
                          udm_kwargs):
    old_user_dn, old_user_url, old_user_data = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(old_user_dn)
        assert obj.dn == old_user_dn
        assert obj.uri == old_user_url
        obj.position = f"cn={random_name},{base_dn}"
        with pytest.raises(MoveError):
            await obj.save()
async def test_new_user(base_dn, udm_kwargs):
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.new()
    assert obj.dn is None
    assert obj.uri == ""
    assert obj.position == f"cn=users,{base_dn}"
    assert obj.props.firstname is None
    assert obj.props.groups == []
    assert obj.props.primaryGroup == f"cn=Domain Users,cn=groups,{base_dn}"
    assert obj.props.shell == "/bin/bash"
async def test_get_user(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
    assert obj.dn == dn
    assert obj.uri == url
    assert obj.position == user["position"]
    assert obj.props.firstname == user["properties"]["firstname"]
    assert obj.props.lastname == user["properties"]["lastname"]
    assert obj.props.birthday == user["properties"]["birthday"]
async def test_search_at_dn(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        with pytest.raises(ValueError):
            [_ async for _ in mod.search(base=dn, scope=fake.pystr())]
        async for obj in mod.search(base=dn, scope="base"):
            assert obj.dn == dn
            assert obj.uri == url
            assert obj.position == user["position"]
            assert obj.props.firstname == user["properties"]["firstname"]
            assert obj.props.lastname == user["properties"]["lastname"]
async def test_saving_obj_with_bad_property_value(user_created_via_http,
                                                  udm_kwargs):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.uri == url
        assert obj.props.firstname == user["properties"]["firstname"]
        # OK, got a valid object from LDAP, now modify it but skip the reload
        obj.props.birthday = fake.pystr()
        with pytest.raises(ModifyError):
            await obj.save()
async def test_creating_obj_with_bad_property_value(fake_user, udm_kwargs):
    user_data = fake_user()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.new()
        obj.policies = user_data.policies
        obj.superordinate = user_data.superordinate
        obj.position = user_data.position
        obj.options = user_data.options
        for k, v in attr.asdict(user_data.props).items():
            setattr(obj.props, k, v)
        obj.props.birthday = fake.pystr()
        with pytest.raises(CreateError):
            await obj.save()
async def test_dn_property_encoder_user_group_obj(user_created_via_http,
                                                  udm_kwargs, base_dn):
    dn, url, user = user_created_via_http()

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.uri == url
        primary_group = obj.props.primaryGroup
        assert str(primary_group).startswith("cn=")
        assert str(primary_group).endswith(base_dn)
        assert hasattr(primary_group, "obj")
        primary_group_obj = await primary_group.obj
        assert isinstance(primary_group_obj, base_http.UdmObject)
        assert primary_group_obj.dn == str(primary_group)
        assert dn in primary_group_obj.props.users
async def test_reload_user(user_created_via_http, modify_user_via_http,
                           udm_kwargs, user_class, random_name):
    dn, url, user = user_created_via_http()

    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.uri == url
        assert obj.position == user["position"]
        assert obj.props.firstname == user["properties"]["firstname"]
        assert obj.props.lastname == user["properties"]["lastname"]
        assert obj.props.birthday == user["properties"]["birthday"]

        user_mod_data = user_class(
            dn="",
            options=None,
            policies=None,
            position=None,
            props={
                "firstname": random_name(),
                "lastname": random_name()
            },
            superordinate=None,
            uri="",
            uuid="",
        )
        modify_user_via_http(dn, user_mod_data)

        res = await obj.reload()
        assert res is obj
        assert obj.dn == dn
        assert obj.uri == url
        assert obj.position == user["position"]
        assert obj.props.firstname == user_mod_data.props["firstname"]
        assert obj.props.lastname == user_mod_data.props["lastname"]
        assert obj.props.birthday == user["properties"]["birthday"]

        obj_new = await mod.get(dn)
        assert obj_new.dn == obj.dn
        assert obj_new.uri == obj.uri
        assert obj_new.position == obj.position
        assert obj_new.props.firstname == obj.props.firstname
        assert obj_new.props.lastname == obj.props.lastname
        assert obj_new.props.birthday == obj.props.birthday
async def test_object_repr(udm_kwargs):
    async with UDM(**udm_kwargs) as udm:
        mod_name = "users/user"
        mod = udm.get(mod_name)
        mod_repr = repr(mod)
        assert mod_repr == f"UdmModule({mod_name!r})"
        meta_repr = repr(mod.meta)
        assert meta_repr.startswith("UdmModuleMetadata(")
        assert "supported_api_versions" in meta_repr
        async for obj in mod.search():
            obj_repr = repr(obj)
            assert obj_repr == f"UdmObject({mod_name!r}, {obj.dn!r})"
            props_repr = repr(obj.props)
            assert props_repr.startswith("UdmObjectProperties(")
            assert "username" in props_repr
            assert "firstname" in props_repr
            assert len(props_repr.split("\n")) > 10
            break
async def test_search_all_users(base_dn, ldap_connection, udm_kwargs):
    with ldap_connection(connection_kwargs={"read_only": True}) as conn:
        logger.info("Successful LDAP login.")
        conn.search(
            search_base=base_dn,
            search_filter="(univentionObjectType=users/user)",
            attributes=[NO_ATTRIBUTES],
        )
    dns_via_ldap = {result.entry_dn for result in conn.entries}

    dns_via_udm_http = set()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        async for obj in mod.search():
            dns_via_udm_http.add(obj.dn)

    assert any(dn.startswith("uid=Administrator") for dn in dns_via_udm_http)
    assert dns_via_ldap == dns_via_udm_http
async def test_to_dict_user(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.props.lastname == user["properties"]["lastname"]
        assert obj.props.birthday == user["properties"]["birthday"]
        obj.props.birthday = datetime.date(1987, 6, 1)
        dict_repr = obj.to_dict()
        for k in ("dn", "options", "policies", "position", "superordinate",
                  "uuid"):
            assert dict_repr[k] == getattr(obj, k)
        for k, v in dict_repr["props"].items():
            if k == "birthday":
                assert v == obj.props.birthday.strftime("%Y-%m-%d")
                continue
            assert v == getattr(obj.props, k)
async def test_delete_user(user_created_via_http, udm_kwargs):
    dn, url, user = user_created_via_http()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(dn)
        assert obj.dn == dn
        assert obj.props.firstname == user["properties"]["firstname"]

        res = await obj.delete()
        assert res is None
        assert obj.dn == dn

        with pytest.raises(DeletedError):
            await obj.reload()

        with pytest.raises(DeletedError):
            await obj.save()

        # nothing should happen
        await obj.delete()
Example #29
0
async def test_obj_by_dn(base_dn, ldap_connection, udm_kwargs):
    async def load_obj_by_dn(udm, result):
        dn = result.entry_dn
        object_type = result["univentionObjectType"].value
        uuid = result["entryUUID"].value

        obj = await udm.obj_by_dn(dn)
        assert obj.dn == dn
        assert obj._udm_module.name == object_type
        assert obj.uuid == uuid

    with ldap_connection(connection_kwargs={"read_only": True}) as conn:
        logger.info("Successful LDAP login.")
        conn.search(
            search_base=base_dn,
            search_filter="(&"
            "(univentionObjectType=*)"
            "(!(univentionObjectFlag=functional))"
            ")",
            attributes=[
                "univentionObjectType", "univentionObjectFlag", "entryUUID"
            ],
        )
        all_objs = {}
    async with UDM(**udm_kwargs) as udm:
        # test one object per udm module
        for result in conn.entries:
            object_type = result["univentionObjectType"].value
            if (object_type not in BAD_MODULE_NAMES
                    and "://" not in result.entry_dn):  # Bug #50175
                all_objs.setdefault(object_type, []).append(result)
        module_names = all_objs.keys()
        random.shuffle([str(m) for m in module_names])
        logger.info("Reading %d objects of different UDM module types...",
                    len(module_names))
        objs = await asyncio.gather(
            *(load_obj_by_dn(udm, random.choice(all_objs[module_name]))
              for module_name in module_names))
        with open("/tmp/objs", "a") as fp:
            for obj in objs:
                fp.write(f"{obj!r}\n")
async def test_modify_user(fake_user, user_created_via_http, udm_kwargs):
    old_user_dn, old_user_url, old_user_data = user_created_via_http()
    new_user_data = fake_user()
    async with UDM(**udm_kwargs) as udm:
        mod = udm.get("users/user")
        obj = await mod.get(old_user_dn)
        assert obj.dn == old_user_dn
        assert obj.uri == old_user_url
        assert obj.position == old_user_data["position"]
        assert obj.props.firstname == old_user_data["properties"]["firstname"]
        assert obj.props.lastname == old_user_data["properties"]["lastname"]
        assert obj.props.birthday == old_user_data["properties"]["birthday"]

        obj.policies = new_user_data.policies
        modify_props = attr.asdict(new_user_data.props)
        del modify_props["username"]  # not testing move here
        for k, v in modify_props.items():
            setattr(obj.props, k, v)
        res = await obj.save()
        assert res is obj
        assert obj.dn == old_user_dn
        assert obj.uri == old_user_url
        policies = {
            "policies_desktop": [],
            "policies_pwhistory": [],
            "policies_umc": [],
        }
        assert obj.policies == policies
        for k, v in modify_props.items():
            if k == "password":
                v = None
            assert getattr(obj.props, k) == v

        obj_new = await mod.get(old_user_dn)
        assert obj_new.dn == old_user_dn
        assert obj_new.uri == old_user_url
        assert obj_new.policies == policies
        for k, v in modify_props.items():
            if k == "password":
                v = None
            assert getattr(obj_new.props, k) == v