Ejemplo n.º 1
0
    def test_webhooks(self):
        with contextlib.ExitStack() as stack:
            stack.enter_context(
                mock.patch("cowbird.services.impl.magpie.Magpie",
                           side_effect=utils.MockMagpieService))
            data = {
                "event":
                "created",
                "user_name":
                "test_user",
                "callback_url":
                "http://magpie.domain.ca/tmp/109e1d0d-e27c-4601-9d45-984c9b61ebff"
            }
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/users",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            utils.check_response_basic_info(resp)
            magpie = ServiceFactory().get_service("Magpie")
            assert len(magpie.json()["event_users"]) == 1
            assert magpie.json()["event_users"][0] == data["user_name"]

            data["event"] = "deleted"
            data.pop("callback_url")
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/users",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            assert len(magpie.json()["event_users"]) == 0

            data = {
                "event": "created",
                "service_name": "string",
                "resource_id": "string",
                "resource_full_name": "thredds/birdhouse/file.nc",
                "name": "read",
                "access": "allow",
                "scope": "recursive",
                "user": "******",
                "group": "string"
            }
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/permissions",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            magpie = ServiceFactory().get_service("Magpie")
            assert len(magpie.json()["event_perms"]) == 1
            assert magpie.json(
            )["event_perms"][0] == data["resource_full_name"]

            data["event"] = "deleted"
            resp = utils.test_request(self.app,
                                      "POST",
                                      "/webhooks/permissions",
                                      json=data)
            utils.check_response_basic_info(resp, 200, expected_method="POST")
            assert len(magpie.json()["event_perms"]) == 0
Ejemplo n.º 2
0
def test_response_metadata():
    """
    Validate that regardless of response type (success/error) and status-code, metadata details are added.

    note: test only locally to avoid remote server side-effects and because mock cannot be done remotely
    """

    def raise_request(*_, **__):
        raise TypeError()

    app = utils.get_test_magpie_app()
    # all paths below must be publicly accessible
    for code, method, path, kwargs in [
        (200, "GET", "/session", {}),
        # FIXME: sort out 400 vs 422 everywhere (https://github.com/Ouranosinc/Magpie/issues/359)
        # (400, "POST", "/signin", {"body": {}}),  # missing credentials
        (401, "GET", "/services", {}),  # anonymous unauthorized
        (404, "GET", "/random", {}),
        (405, "POST", "/users/{}".format("MAGPIE_LOGGED_USER"), {"body": {}}),
        (406, "GET", "/session", {"headers": {"Accept": "application/pdf"}}),
        # 409: need connection to test conflict, no route available without so (other tests validates them though)
        (422, "POST", "/signin", {"body": {"user_name": "!!!!"}}),  # invalid format
        (500, "GET", "/json", {}),  # see mock
    ]:
        with mock.patch("magpie.api.schemas.generate_api_schema", side_effect=raise_request):
            headers = {"Accept": CONTENT_TYPE_JSON, "Content-Type": CONTENT_TYPE_JSON}
            headers.update(kwargs.get("headers", {}))
            kwargs.pop("headers", None)
            resp = utils.test_request(app, method, path, expect_errors=True, headers=headers, **kwargs)
            # following util check validates all expected request metadata in response body
            utils.check_response_basic_info(resp, expected_code=code, expected_method=method)
Ejemplo n.º 3
0
def test_response_metadata():
    """
    Validate that regardless of response type (success/error) and status-code, metadata details are added.

    note: test only locally to avoid remote server side-effects and because mock cannot be done remotely
    """
    class MockService(object):
        def name(self):
            raise TypeError()

    app = utils.get_test_app()
    # all paths below must be publicly accessible
    for i, (code, method, path, kwargs) in enumerate(
        [
            (200, "GET", "", {}),
            (400, "GET", "/services/!!!!", {}),  # invalid format
            # (401, "GET", "/services", {}),  # anonymous unauthorized
            (404, "GET", "/random", {}),
            (405, "POST", "/json", {
                "body": {}
            }),
            (406, "GET", "/api", {
                "headers": {
                    "Accept": "application/pdf"
                }
            }),
            # 409: need connection to test conflict, no route available without so (other tests validates them though)
            # (422, "POST", "/services", {"body": {"name": 1}}),  # invalid field type  # FIXME: route impl required
            (500, "GET", "/services", {}),  # see mock
        ],
            start=1):
        with contextlib.ExitStack() as stack:
            if code == 500:
                stack.enter_context(
                    mock.patch("cowbird.services.impl.magpie.Magpie",
                               side_effect=MockService))
            headers = {
                "Accept": CONTENT_TYPE_JSON,
                "Content-Type": CONTENT_TYPE_JSON
            }
            headers.update(kwargs.get("headers", {}))
            kwargs.pop("headers", None)
            resp = utils.test_request(app,
                                      method,
                                      path,
                                      expect_errors=True,
                                      headers=headers,
                                      **kwargs)
            # following util check validates all expected request metadata in response body
            msg = "\n[Test: #{}, Code: {}]".format(i, code)
            utils.check_response_basic_info(resp,
                                            expected_code=code,
                                            expected_method=method,
                                            extra_message=msg)
Ejemplo n.º 4
0
    def test_magpie_prefix_direct_request(self):
        base_url = "http://localhost"
        for url in ["http://localhost", "http://localhost/magpie"]:
            app = utils.get_test_magpie_app({"magpie.url": url})

            path = "/version"
            resp = utils.test_request(app, "GET", path)
            utils.check_response_basic_info(resp)
            utils.check_val_equal(
                resp.request.url, base_url + path,
                "Proxied path should have been auto-resolved [URL: {}].".
                format(url))
Ejemplo n.º 5
0
    def test_magpie_prefix_request_with_multiple_route_url(self):
        """
        Test multiple request routing with fixed "MAGPIE_URL" within the API application.

        Signin with invalid credentials will call "/signin" followed by sub-request "/signin_internal" and finally
        "ZigguratSignInBadAuth". Both "/signin" and "ZigguratSignInBadAuth" use "get_multiformat_body".
        """
        from magpie.api.requests import get_value_multiformat_body_checked as real_multiform_post_checked
        base_url = "http://localhost"

        def mock_get_post(real_func, *args, **kwargs):
            if args[1] != "password":
                return real_func(*args, **kwargs)
            request, args = args[0], args[1:]
            utils.check_val_equal(
                request.url, base_url + _paths.pop(0),
                "Proxied path should have been auto-resolved [URL: {}].".
                format(url))
            return real_func(request, *args, **kwargs)

        for url in ["http://localhost", "http://localhost/magpie"]:
            # paths are reduced (pop in mock) each time a post to get the 'password' is called in 'login' module
            # this combination should happen twice, one in signin route and another on the redirected internal login
            _paths = ["/signin", "/signin_internal"]
            app = utils.get_test_magpie_app({"magpie.url": url})

            with mock.patch(
                    "magpie.api.requests.get_value_multiformat_body_checked",
                    side_effect=lambda *_, **__: mock_get_post(
                        real_multiform_post_checked, *_, **__)):
                data = {"user_name": "foo", "password": "******"}
                headers = {
                    "Content-Type": CONTENT_TYPE_JSON,
                    "Accept": CONTENT_TYPE_JSON
                }
                resp = utils.test_request(app,
                                          "POST",
                                          _paths[0],
                                          json=data,
                                          headers=headers,
                                          expect_errors=True)
                if LooseVersion(self.version) < LooseVersion("0.10.0"):
                    # user name doesn't exist
                    utils.check_response_basic_info(resp,
                                                    expected_code=406,
                                                    expected_method="POST")
                else:
                    # invalid username/password credentials
                    utils.check_response_basic_info(resp,
                                                    expected_code=401,
                                                    expected_method="POST")
Ejemplo n.º 6
0
 def test_homepage(self):
     resp = utils.test_request(self.app, "GET", "/")
     body = utils.check_response_basic_info(resp)
     utils.check_val_is_in("name", body)
     utils.check_val_is_in("title", body)
     utils.check_val_is_in("contact", body)
     utils.check_val_is_in("description", body)
     utils.check_val_is_in("documentation", body)
     utils.check_val_is_in("cowbird", body["name"])
Ejemplo n.º 7
0
 def check_api_resource_permissions(resource_permissions):
     for _r_id, _r_perms in resource_permissions:
         urp_path = "/users/{}/resources/{}/permissions".format(
             self.test_user_name, _r_id)
         urp_resp = utils.test_request(self, "GET", urp_path)
         urp_body = utils.check_response_basic_info(urp_resp)
         ur_perms = [
             perm.json() for perm in _r_perms
             if isinstance(perm, PermissionSet)
         ]
         for perm in ur_perms:
             perm["type"] = PermissionType.DIRECT.value
         permissions = urp_body["permissions"]
         for perm in permissions:
             perm.pop("reason",
                      None)  # >= 3.4, don't care for this test
         utils.check_all_equal(permissions, ur_perms, any_order=True)
Ejemplo n.º 8
0
def test_magpie_homepage():
    from magpie.constants import get_constant as real_get_constant  # pylint: disable=W0404,reimported

    def mock_get_constant(*args, **kwargs):
        if args[0] == "MAGPIE_UI_ENABLED":
            return False
        return real_get_constant(*args, **kwargs)

    with mock.patch("magpie.constants.get_constant", side_effect=mock_get_constant), \
            mock.patch("magpie.api.home.get_constant", side_effect=mock_get_constant):
        app = utils.get_test_magpie_app()
        resp = utils.test_request(app, "GET", "/")
        body = utils.check_response_basic_info(resp)
        utils.check_val_is_in("name", body)
        utils.check_val_is_in("title", body)
        utils.check_val_is_in("contact", body)
        utils.check_val_is_in("description", body)
        utils.check_val_is_in("documentation", body)
        utils.check_val_is_in("magpie", body["name"])
Ejemplo n.º 9
0
    def test_register_permissions_missing_group_create_new_entries(self):
        utils.TestSetup.create_TestService(
            self,
            override_service_name=self.test_perm_svc_name,
            override_service_type=ServiceAPI.service_type)
        utils.TestSetup.delete_TestGroup(
            self, override_group_name=self.test_perm_grp_name)
        session = get_db_session_from_settings(self.app.app.registry.settings)

        svc_perm = Permission.READ_MATCH
        res1_perm = Permission.READ
        res2_perm = Permission.WRITE
        res1_name = "test-resource"
        res2_name = "sub-test-resource"
        perm_config = {
            "permissions": [
                {
                    "service": self.test_perm_svc_name,
                    "permission": svc_perm.value,
                    "action": "create",
                    "group": self.test_perm_grp_name,
                },
                {
                    "service": self.test_perm_svc_name,
                    "resource": res1_name,
                    "permission": res1_perm.value,
                    "action": "create",
                    "group": self.test_perm_grp_name,
                },
                {
                    "service": self.test_perm_svc_name,
                    "resource": res1_name + "/" + res2_name,
                    "permission": res2_perm.value,
                    "action": "create",
                    "group": self.test_perm_grp_name,
                },
            ]
        }
        utils.check_no_raise(
            lambda: register.magpie_register_permissions_from_config(
                perm_config, db_session=session))

        # check that all service, resources, group are created correctly
        services = utils.TestSetup.get_RegisteredServicesList(self)
        utils.check_val_is_in(self.test_perm_svc_name,
                              [s["service_name"] for s in services])
        groups = utils.TestSetup.get_RegisteredGroupsList(self)
        utils.check_val_is_in(self.test_perm_grp_name, groups)
        resp = utils.test_request(
            self.app, "GET",
            "/services/{}/resources".format(self.test_perm_svc_name))
        body = utils.check_response_basic_info(resp)
        svc_res = body[self.test_perm_svc_name]["resources"]
        svc_res_id = body[self.test_perm_svc_name]["resource_id"]
        utils.check_val_is_in(res1_name,
                              [svc_res[r]["resource_name"] for r in svc_res])
        res1_id = [
            svc_res[r]["resource_id"] for r in svc_res
            if svc_res[r]["resource_name"] == res1_name
        ][0]
        res1_sub = svc_res[str(res1_id)]["children"]
        utils.check_val_is_in(res2_name,
                              [res1_sub[r]["resource_name"] for r in res1_sub])
        res2_id = [
            res1_sub[r]["resource_id"] for r in res1_sub
            if res1_sub[r]["resource_name"] == res2_name
        ][0]

        # check that all permissions are created correctly
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, svc_res_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_is_in(svc_perm.value, body["permission_names"])
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res1_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_is_in(res1_perm.value, body["permission_names"])
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res2_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_is_in(res2_perm.value, body["permission_names"])
Ejemplo n.º 10
0
    def test_register_permissions_existing_group_without_intermediate_entries(
            self):
        utils.TestSetup.create_TestService(
            self,
            override_service_name=self.test_perm_svc_name,
            override_service_type=ServiceAPI.service_type)
        utils.TestSetup.create_TestGroup(
            self, override_group_name=self.test_perm_grp_name)
        session = get_db_session_from_settings(self.app.app.registry.settings)

        res1_name = "test-resource"
        res2_name = "sub-test-resource"
        res3_name = "sub-sub-test-resource"
        res3_perm = Permission.WRITE_MATCH
        perm_config = {
            "permissions": [
                {
                    "service": self.test_perm_svc_name,  # exists
                    "resource": res1_name + "/" + res2_name + "/" +
                    res3_name,  # none exist, all created for perm
                    "permission": res3_perm.value,  # perm only to lowest child
                    "action": "create",
                    "group": self.test_perm_grp_name,
                },
            ]
        }
        utils.check_no_raise(
            lambda: register.magpie_register_permissions_from_config(
                perm_config, db_session=session))

        # check that all service, resources, group are created correctly
        services = utils.TestSetup.get_RegisteredServicesList(self)
        utils.check_val_is_in(self.test_perm_svc_name,
                              [s["service_name"] for s in services])
        groups = utils.TestSetup.get_RegisteredGroupsList(self)
        utils.check_val_is_in(self.test_perm_grp_name, groups)
        resp = utils.test_request(
            self.app, "GET",
            "/services/{}/resources".format(self.test_perm_svc_name))
        body = utils.check_response_basic_info(resp)
        svc_res = body[self.test_perm_svc_name]["resources"]
        svc_res_id = body[self.test_perm_svc_name]["resource_id"]
        utils.check_val_is_in(res1_name,
                              [svc_res[r]["resource_name"] for r in svc_res])
        res1_id = [
            svc_res[r]["resource_id"] for r in svc_res
            if svc_res[r]["resource_name"] == res1_name
        ][0]
        res1_sub = svc_res[str(res1_id)]["children"]
        utils.check_val_is_in(res2_name,
                              [res1_sub[r]["resource_name"] for r in res1_sub])
        res2_id = [
            res1_sub[r]["resource_id"] for r in res1_sub
            if res1_sub[r]["resource_name"] == res2_name
        ][0]
        res2_sub = res1_sub[str(res2_id)]["children"]
        utils.check_val_is_in(res3_name,
                              [res2_sub[r]["resource_name"] for r in res2_sub])
        res3_id = [
            res2_sub[r]["resource_id"] for r in res2_sub
            if res2_sub[r]["resource_name"] == res3_name
        ][0]

        # check that all permissions are created correctly (only for final item)
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, svc_res_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_equal(body["permission_names"], [])
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res1_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_equal(body["permission_names"], [])
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res2_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_equal(body["permission_names"], [])
        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res3_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_all_equal(body["permission_names"], [res3_perm.value])
Ejemplo n.º 11
0
def run_batch_update_user_command(test_app, expected_users,
                                  create_command_xargs, delete_command_xargs):
    """
    Tests batch user creation and deletion of the CLI utility.

    Because CLI utility employs requests that cannot be mocked if executed through sub-process, we call it directly.
    """
    test_admin_usr = get_constant("MAGPIE_TEST_ADMIN_USERNAME",
                                  raise_not_set=False,
                                  raise_missing=False)
    test_admin_pwd = get_constant("MAGPIE_TEST_ADMIN_PASSWORD",
                                  raise_not_set=False,
                                  raise_missing=False)
    if not test_admin_usr or not test_admin_pwd:
        test_admin_usr = get_constant("MAGPIE_ADMIN_USER")
        test_admin_pwd = get_constant("MAGPIE_ADMIN_PASSWORD")
    test_url = "http://localhost"

    def mock_request(*args, **kwargs):
        method, url, args = args[0], args[1], args[2:]
        path = url.replace(test_url, "")
        # because CLI utility does multiple login tests, we must force TestApp logout to forget session
        # otherwise, error is raised because of user session mismatch between previous login and new one requested
        if path.startswith("/signin"):
            utils.check_or_try_logout_user(test_app)
        return utils.test_request(test_app, method, path, *args, **kwargs)

    def run_command(operation_name, operation_args):
        with tempfile2.TemporaryDirectory() as tmpdir:
            with mock.patch("requests.Session.request",
                            side_effect=mock_request):
                with mock.patch("requests.request", side_effect=mock_request):
                    cmd = [
                        test_url, test_admin_usr, test_admin_pwd, "-o", tmpdir
                    ] + operation_args
                    assert batch_update_users.main(
                        cmd) == 0, "failed execution due to invalid arguments"
                    assert len(
                        os.listdir(tmpdir)
                    ) == 1, "utility should have produced 1 output file"
                    file = os.path.join(tmpdir, os.listdir(tmpdir)[0])
                    utils.check_val_is_in(operation_name, file)
                    assert os.path.isfile(file)
                    with open(file, "r") as fd:
                        file_text = fd.read()
                    assert all([test_user in file_text for test_user in expected_users]), \
                        "all users should have been processed and logged in output result file"

    # cleanup in case of previous failure
    _, test_admin_cookies = utils.check_or_try_login_user(
        test_app, username=test_admin_usr, password=test_admin_pwd)
    for user in expected_users:
        utils.TestSetup.delete_TestUser(
            test_app,
            override_user_name=user,  # noqa
            override_headers={},
            override_cookies=test_admin_cookies)
    utils.check_or_try_logout_user(test_app)

    # test user creation and validate that users were all created
    run_command("create", create_command_xargs)
    utils.check_or_try_logout_user(test_app)
    _, test_admin_cookies = utils.check_or_try_login_user(
        test_app, username=test_admin_usr, password=test_admin_pwd)
    resp = utils.test_request(test_app,
                              "GET",
                              "/users",
                              cookies=test_admin_cookies)
    body = utils.check_response_basic_info(resp)
    for user in expected_users:
        utils.check_val_is_in(user, body["user_names"])

    # test user deletion and validate users are all deleted
    run_command("delete", ["-d"] + delete_command_xargs)
    utils.check_or_try_logout_user(test_app)
    _, test_admin_cookies = utils.check_or_try_login_user(
        test_app, username=test_admin_usr, password=test_admin_pwd)
    resp = utils.test_request(test_app,
                              "GET",
                              "/users",
                              cookies=test_admin_cookies)
    body = utils.check_response_basic_info(resp)
    for user in expected_users:
        utils.check_val_not_in(user, body["user_names"])
Ejemplo n.º 12
0
    def test_register_permissions_multiple_resource_type_possible(self):
        """
        Verify that service that allows multiple resource-types children retrieves ``type`` field for their creation.
        """
        svc_type = ServiceTHREDDS.service_type
        svc_name = "unittest-service-thredds-register-children-resources"
        utils.TestSetup.create_TestService(self,
                                           override_service_name=svc_name,
                                           override_service_type=svc_type)
        utils.TestSetup.create_TestGroup(
            self, override_group_name=self.test_perm_grp_name)
        session = get_db_session_from_settings(self.app.app.registry.settings)

        res1_name = "test-resource"
        res2_name = "sub-test-resource"
        res3_name = "sub-sub-test-resource"
        res3_perm = "write-deny-recursive"
        res3_path = res1_name + "/" + res2_name + "/" + res3_name  # none exist, all created for final permission
        perm_config = {
            "permissions": [
                {
                    "service": svc_name,  # exists
                    "resource": res3_path,
                    "permission": res3_perm,  # perm only on lowest child
                    "type": Directory.
                    resource_type_name,  # without this, fails because cannot infer Directory/File
                    "action": "create",
                    "group": self.test_perm_grp_name,
                },
            ]
        }
        utils.check_no_raise(
            lambda: register.magpie_register_permissions_from_config(
                perm_config, db_session=session))

        # check that all service, resources, group are created correctly
        services = utils.TestSetup.get_RegisteredServicesList(self)
        utils.check_val_is_in(svc_name, [s["service_name"] for s in services])
        groups = utils.TestSetup.get_RegisteredGroupsList(self)
        utils.check_val_is_in(self.test_perm_grp_name, groups)
        resp = utils.test_request(self.app, "GET",
                                  "/services/{}/resources".format(svc_name))
        body = utils.check_response_basic_info(resp)
        svc_res = body[svc_name]["resources"]  # type: JSON
        utils.check_val_is_in(res1_name,
                              [svc_res[r]["resource_name"] for r in svc_res])
        res1_id = [
            svc_res[r]["resource_id"] for r in svc_res
            if svc_res[r]["resource_name"] == res1_name
        ][0]
        res1_sub = svc_res[str(res1_id)]["children"]  # type: JSON
        utils.check_val_is_in(res2_name,
                              [res1_sub[r]["resource_name"] for r in res1_sub])
        res2_id = [
            res1_sub[r]["resource_id"] for r in res1_sub
            if res1_sub[r]["resource_name"] == res2_name
        ][0]
        res2_sub = res1_sub[str(res2_id)]["children"]  # type: JSON
        utils.check_val_is_in(res3_name,
                              [res2_sub[r]["resource_name"] for r in res2_sub])
        res3_id = [
            res2_sub[r]["resource_id"] for r in res2_sub
            if res2_sub[r]["resource_name"] == res3_name
        ][0]

        path = "/groups/{}/resources/{}/permissions".format(
            self.test_perm_grp_name, res3_id)
        resp = utils.test_request(self.app, "GET", path)
        body = utils.check_response_basic_info(resp)
        utils.check_val_is_in(res3_perm, body["permission_names"])

        # validate that without the 'type', similar resource would not be created due to missing information
        res_missing_type_name = "missing-type"
        res_missing_type_path = res3_path.replace("/" + res3_name,
                                                  "/" + res_missing_type_name)
        missing_type_perm_config = copy.deepcopy(perm_config)  # type: JSON
        missing_type_perm_config["permissions"][0].pop("type")
        missing_type_perm_config["permissions"][0][
            "resource"] = res_missing_type_path
        utils.check_no_raise(
            lambda: register.magpie_register_permissions_from_config(
                missing_type_perm_config, db_session=session))
        resp = utils.test_request(self.app, "GET",
                                  "/resources/{}".format(res2_id))
        body = utils.check_response_basic_info(resp)
        res_children = body["resource"]["children"]
        res_found = [
            res for _, res in res_children.items()
            if res["resource_name"] == res_missing_type_name
        ]
        utils.check_val_equal(res_found, [])