示例#1
0
    def test_auth_test(self):
        c = AppConfig()
        c.update_server_config(authentication__type="test")
        c.update_server_config(
            multi_dataset__dataroot=dict(
                a1=dict(dataroot=self.dataset_dataroot, base_url="auth"),
                a2=dict(dataroot=self.dataset_dataroot, base_url="no-auth"),
            )
        )

        # specialize the configs
        c.add_dataroot_config("a1", app__authentication_enable=True, user_annotations__enable=True)
        c.add_dataroot_config("a2", app__authentication_enable=False, user_annotations__enable=False)

        c.complete_config()

        with test_server(app_config=c) as server:
            session = requests.Session()

            # auth datasets
            config = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/userinfo").json()

            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(config["config"]["authentication"]["requires_client_login"])
            self.assertTrue(config["config"]["parameters"]["annotations"])

            login_uri = config["config"]["authentication"]["login"]
            logout_uri = config["config"]["authentication"]["logout"]

            self.assertEqual(login_uri, "/login?dataset=auth/pbmc3k.cxg")
            self.assertEqual(logout_uri, "/logout?dataset=auth/pbmc3k.cxg")

            r = session.get(f"{server}/{login_uri}")
            # check that the login redirect worked
            self.assertEqual(r.history[0].status_code, 302)
            self.assertEqual(r.url, f"{server}/auth/pbmc3k.cxg/")

            config = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertTrue(userinfo["userinfo"]["is_authenticated"])
            self.assertEqual(userinfo["userinfo"]["username"], "test_account")
            self.assertTrue(config["config"]["parameters"]["annotations"])

            r = session.get(f"{server}/{logout_uri}")
            # check that the logout redirect worked
            self.assertEqual(r.history[0].status_code, 302)
            self.assertEqual(r.url, f"{server}/auth/pbmc3k.cxg/")
            config = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/auth/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(config["config"]["parameters"]["annotations"])

            # no-auth datasets
            config = session.get(f"{server}/no-auth/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/no-auth/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertIsNone(userinfo)
            self.assertFalse(config["config"]["parameters"]["annotations"])
示例#2
0
    def test_get_api_base_url_works(self):

        # test the api_base_url feature, and that it can contain a path
        config = AppConfig()
        backend_port = find_available_port("localhost", 10000)
        config.update_server_config(
            app__flask_secret_key="secret",
            app__api_base_url=
            f"http://localhost:{backend_port}/additional/path",
            multi_dataset__dataroot=f"{PROJECT_ROOT}/example-dataset",
        )

        config.complete_config()

        with test_server(["-p", str(backend_port)],
                         app_config=config) as server:
            session = requests.Session()
            self.assertEqual(server, f"http://localhost:{backend_port}")
            response = session.get(
                f"{server}/additional/path/d/pbmc3k.h5ad/api/v0.2/config")
            self.assertEqual(response.status_code, 200)
            data_config = response.json()
            self.assertEqual(data_config["config"]["displayNames"]["dataset"],
                             "pbmc3k")

            # test the health check at the correct url
            response = session.get(f"{server}/additional/path/health")
            assert response.json()["status"] == "pass"
示例#3
0
    def test_mulitdatasets_work_e2e(self):
        # test that multi dataroots work end to end
        self.config.update_server_config(
            multi_dataset__dataroot=dict(
                s1=dict(dataroot=f"{PROJECT_ROOT}/example-dataset", base_url="set1/1/2"),
                s2=dict(dataroot=f"{FIXTURES_ROOT}", base_url="set2"),
                s3=dict(dataroot=f"{FIXTURES_ROOT}", base_url="set3"),
            )
        )

        # Change this default to test if the dataroot overrides below work.
        self.config.update_default_dataset_config(app__about_legal_tos="tos_default.html")

        # specialize the configs for set1
        self.config.add_dataroot_config(
            "s1", user_annotations__enable=False, diffexp__enable=True, app__about_legal_tos="tos_set1.html"
        )

        # specialize the configs for set2
        self.config.add_dataroot_config(
            "s2", user_annotations__enable=True, diffexp__enable=False, app__about_legal_tos="tos_set2.html"
        )

        # no specializations for set3 (they get the default dataset config)
        self.config.complete_config()

        with test_server(app_config=self.config) as server:
            session = requests.Session()

            response = session.get(f"{server}/set1/1/2/pbmc3k.h5ad/api/v0.2/config")
            data_config = response.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is False
            assert data_config["config"]["parameters"]["disable-diffexp"] is False
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_set1.html"

            response = session.get(f"{server}/set2/pbmc3k.cxg/api/v0.2/config")
            data_config = response.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is True
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_set2.html"

            response = session.get(f"{server}/set3/pbmc3k.cxg/api/v0.2/config")
            data_config = response.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is True
            assert data_config["config"]["parameters"]["disable-diffexp"] is False
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_default.html"

            response = session.get(f"{server}/health")
            assert response.json()["status"] == "pass"

            # access a dataset (no slash)
            response = session.get(f"{server}/set2/pbmc3k.cxg")
            self.assertEqual(response.status_code, 200)

            # access a dataset (with slash)
            response = session.get(f"{server}/set2/pbmc3k.cxg/")
            self.assertEqual(response.status_code, 200)
示例#4
0
    def test_environment_variable(self):
        configfile = self.custom_external_config(
            environment=[
                dict(name="DATAPATH",
                     path=["server", "single_dataset", "datapath"],
                     required=True),
                dict(name="DIFFEXP",
                     path=["dataset", "diffexp", "enable"],
                     required=True),
            ],
            config_file_name="environment_external_config.yaml",
        )

        env = os.environ
        env["DATAPATH"] = f"{FIXTURES_ROOT}/pbmc3k.cxg"
        env["DIFFEXP"] = "False"
        with test_server(command_line_args=["-c", configfile],
                         env=env) as server:
            session = requests.Session()
            response = session.get(f"{server}/api/v0.2/config")
            data_config = response.json()
            self.assertEqual(data_config["config"]["displayNames"]["dataset"],
                             "pbmc3k")
            self.assertTrue(
                data_config["config"]["parameters"]["disable-diffexp"])

        env["DATAPATH"] = f"{FIXTURES_ROOT}/a95c59b4-7f5d-4b80-ad53-a694834ca18b.h5ad"
        env["DIFFEXP"] = "True"
        with test_server(command_line_args=["-c", configfile],
                         env=env) as server:
            session = requests.Session()
            response = session.get(f"{server}/api/v0.2/config")
            data_config = response.json()
            self.assertEqual(data_config["config"]["displayNames"]["dataset"],
                             "a95c59b4-7f5d-4b80-ad53-a694834ca18b")
            self.assertFalse(
                data_config["config"]["parameters"]["disable-diffexp"])
示例#5
0
    def test_auth_none(self):
        c = AppConfig()
        c.update_server_config(
            authentication__type=None, multi_dataset__dataroot=self.dataset_dataroot
        )
        c.update_default_dataset_config(user_annotations__enable=False)

        c.complete_config()

        with test_server(app_config=c) as server:
            session = requests.Session()
            config = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertNotIn("authentication", config["config"])
            self.assertIsNone(userinfo)
示例#6
0
    def test_auth_session(self):
        c = AppConfig()
        c.update_server_config(
            authentication__type="session", multi_dataset__dataroot=self.dataset_dataroot
        )
        c.update_default_dataset_config(user_annotations__enable=True)
        c.complete_config()

        with test_server(app_config=c) as server:
            session = requests.Session()
            config = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()

            self.assertFalse(config["config"]["authentication"]["requires_client_login"])
            self.assertTrue(userinfo["userinfo"]["is_authenticated"])
            self.assertEqual(userinfo["userinfo"]["username"], "anonymous")
示例#7
0
    def test_auth_test_single(self):
        app_config = AppConfig()
        app_config.update_server_config(app__flask_secret_key="secret")
        app_config.update_server_config(
            authentication__type="test",
            single_dataset__datapath=f"{self.dataset_dataroot}/pbmc3k.cxg")
        app_config.update_server_config(
            authentication__insecure_test_environment=True)

        app_config.complete_config()

        with test_server(app_config=app_config) as server:
            session = requests.Session()
            config = session.get(f"{server}/api/v0.2/config").json()
            userinfo = session.get(f"{server}/api/v0.2/userinfo").json()
            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(
                config["config"]["authentication"]["requires_client_login"])
            self.assertTrue(config["config"]["parameters"]["annotations"])

            login_uri = config["config"]["authentication"]["login"]
            logout_uri = config["config"]["authentication"]["logout"]

            self.assertEqual(login_uri, "/login")
            self.assertEqual(logout_uri, "/logout")

            response = session.get(f"{server}/{login_uri}")
            # check that the login redirect worked
            self.assertEqual(response.history[0].status_code, 302)
            self.assertEqual(response.url, f"{server}/")

            config = session.get(f"{server}/api/v0.2/config").json()
            userinfo = session.get(f"{server}/api/v0.2/userinfo").json()
            self.assertTrue(userinfo["userinfo"]["is_authenticated"])
            self.assertEqual(userinfo["userinfo"]["username"], "test_account")
            self.assertTrue(config["config"]["parameters"]["annotations"])

            response = session.get(f"{server}/{logout_uri}")
            # check that the logout redirect worked
            self.assertEqual(response.history[0].status_code, 302)
            self.assertEqual(response.url, f"{server}/")
            config = session.get(f"{server}/api/v0.2/config").json()
            userinfo = session.get(f"{server}/api/v0.2/userinfo").json()
            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(config["config"]["parameters"]["annotations"])
示例#8
0
    def auth_flow(self, app_config, cookie_key=None):

        app_config.update_server_config(
            app__api_base_url="local",
            authentication__type="oauth",
            authentication__params_oauth__oauth_api_base_url=f"http://*****:*****@email.com")
            self.assertTrue(config["config"]["parameters"]["annotations"])

            if cookie_key:
                cookie = session.cookies.get(cookie_key)
                token = json.loads(base64.b64decode(cookie))
                access_token_before = token.get("access_token")
                id_token_before = token.get("id_token")

                # let the token expire
                time.sleep(TOKEN_EXPIRES + 1)

                # check that refresh works
                session.get(login_uri)
                userinfo = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
                self.assertTrue(userinfo["userinfo"]["is_authenticated"])
                self.assertEqual(userinfo["userinfo"]["username"], "fake_user")

                cookie = session.cookies.get(cookie_key)
                token = json.loads(base64.b64decode(cookie))
                access_token_after = token.get("access_token")
                id_token_after = token.get("id_token")

                self.assertNotEqual(access_token_before, access_token_after)
                self.assertNotEqual(id_token_before, id_token_after)

                # invalid cookie is rejected
                session.cookies.set(cookie_key, "TEST_" + cookie)
                self.assertTrue(cookie_key in session.cookies)
                response = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo")
                # this is not an error, the invalid cookie is just ignored.
                self.assertEqual(response.status_code, 200)
                userinfo = response.json()
                self.assertFalse(userinfo["userinfo"]["is_authenticated"])
                self.assertIsNone(userinfo["userinfo"]["username"])

                # invalid id_token is rejected
                test_token = token
                test_token["id_token"] = "TEST_" + id_token_after
                encoded_cookie = base64.b64encode(json.dumps(test_token).encode()).decode()
                session.cookies.set(cookie_key, encoded_cookie)
                response = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo")
                # this is not an error, the invalid id_token is just ignored.
                self.assertEqual(response.status_code, 200)
                userinfo = response.json()
                self.assertFalse(userinfo["userinfo"]["is_authenticated"])
                self.assertIsNone(userinfo["userinfo"]["username"])

            r = session.get(logout_uri)
            # check that the logout redirect worked
            self.assertEqual(r.history[0].status_code, 302)
            self.assertEqual(r.url, f"{server}/d/pbmc3k.cxg/")
            config = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(config["config"]["parameters"]["annotations"])
示例#9
0
    def test_multi_dataset(self):

        c = AppConfig()
        # test for illegal url_dataroots
        for illegal in ("../b", "!$*", "\\n", "", "(bad)"):
            c.update_server_config(
                multi_dataset__dataroot={"tag": {"base_url": illegal, "dataroot": "{PROJECT_ROOT}/example-dataset"}}
            )
            with self.assertRaises(ConfigurationError):
                c.complete_config()

        # test for legal url_dataroots
        for legal in ("d", "this.is-okay_", "a/b"):
            c.update_server_config(
                multi_dataset__dataroot={"tag": {"base_url": legal, "dataroot": "{PROJECT_ROOT}/example-dataset"}}
            )
            c.complete_config()

        # test that multi dataroots work end to end
        c.update_server_config(
            multi_dataset__dataroot=dict(
                s1=dict(dataroot=f"{PROJECT_ROOT}/example-dataset", base_url="set1/1/2"),
                s2=dict(dataroot=f"{PROJECT_ROOT}/server/test/test_datasets", base_url="set2"),
                s3=dict(dataroot=f"{PROJECT_ROOT}/server/test/test_datasets", base_url="set3"),
            )
        )

        # Change this default to test if the dataroot overrides below work.
        c.update_default_dataset_config(app__about_legal_tos="tos_default.html")

        # specialize the configs for set1
        c.add_dataroot_config(
            "s1", user_annotations__enable=False, diffexp__enable=True, app__about_legal_tos="tos_set1.html"
        )

        # specialize the configs for set2
        c.add_dataroot_config(
            "s2", user_annotations__enable=True, diffexp__enable=False, app__about_legal_tos="tos_set2.html"
        )

        # no specializations for set3 (they get the default dataset config)
        c.complete_config()

        with test_server(app_config=c) as server:
            session = requests.Session()

            r = session.get(f"{server}/set1/1/2/pbmc3k.h5ad/api/v0.2/config")
            data_config = r.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is False
            assert data_config["config"]["parameters"]["disable-diffexp"] is False
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_set1.html"

            r = session.get(f"{server}/set2/pbmc3k.cxg/api/v0.2/config")
            data_config = r.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is True
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_set2.html"

            r = session.get(f"{server}/set3/pbmc3k.cxg/api/v0.2/config")
            data_config = r.json()
            assert data_config["config"]["displayNames"]["dataset"] == "pbmc3k"
            assert data_config["config"]["parameters"]["annotations"] is True
            assert data_config["config"]["parameters"]["disable-diffexp"] is False
            assert data_config["config"]["parameters"]["about_legal_tos"] == "tos_default.html"

            r = session.get(f"{server}/health")
            assert r.json()["status"] == "pass"
示例#10
0
    def auth_flow(self, app_config, cookie_key=None):

        with test_server(app_config=app_config) as server:
            session = requests.Session()

            # auth datasets
            config = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()

            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(
                config["config"]["authentication"]["requires_client_login"])
            self.assertTrue(config["config"]["parameters"]["annotations"])

            login_uri = config["config"]["authentication"]["login"]
            logout_uri = config["config"]["authentication"]["logout"]

            self.assertEqual(login_uri, "/login?dataset=d/pbmc3k.cxg/")
            self.assertEqual(logout_uri, "/logout")

            r = session.get(f"{server}/{login_uri}")
            # check that the login redirect worked
            self.assertEqual(r.history[0].status_code, 302)
            self.assertEqual(r.url, f"{server}/d/pbmc3k.cxg/")
            config = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertTrue(userinfo["userinfo"]["is_authenticated"])
            self.assertEqual(userinfo["userinfo"]["username"], "fake_user")
            self.assertTrue(config["config"]["parameters"]["annotations"])

            if cookie_key:
                cookie = session.cookies.get(cookie_key)
                token = json.loads(base64.b64decode(cookie))
                access_token_before = token.get("access_token")
                expires_at_before = token.get("expires_at")

                # let the token expire
                time.sleep(TOKEN_EXPIRES + 1)

                # check that refresh works
                session.get(f"{server}/{login_uri}")
                userinfo = session.get(
                    f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
                self.assertTrue(userinfo["userinfo"]["is_authenticated"])
                self.assertEqual(userinfo["userinfo"]["username"], "fake_user")

                cookie = session.cookies.get(cookie_key)
                token = json.loads(base64.b64decode(cookie))
                access_token_after = token.get("access_token")
                expires_at_after = token.get("expires_at")

                self.assertNotEqual(access_token_before, access_token_after)
                self.assertTrue(
                    expires_at_after - expires_at_before > TOKEN_EXPIRES)

            r = session.get(f"{server}/{logout_uri}")
            # check that the logout redirect worked
            self.assertEqual(r.history[0].status_code, 302)
            self.assertEqual(r.url, f"{server}")
            config = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/config").json()
            userinfo = session.get(
                f"{server}/d/pbmc3k.cxg/api/v0.2/userinfo").json()
            self.assertFalse(userinfo["userinfo"]["is_authenticated"])
            self.assertIsNone(userinfo["userinfo"]["username"])
            self.assertTrue(config["config"]["parameters"]["annotations"])