예제 #1
0
async def test_identity_is_email(client):
    # Tests that login sets the user_email and logout removes it
    login_url = client.app.router["auth_login"].url_for()
    logout_url = client.app.router["auth_logout"].url_for()
    session_url = "/session"
    async with NewUser() as user:
        resp = await client.get(session_url)
        session = await resp.json()
        assert session.get("AIOHTTP_SECURITY") == None

        # login
        await client.post(login_url,
                          json={
                              "email": user["email"],
                              "password": user["raw_password"]
                          })
        resp = await client.get(session_url)
        session = await resp.json()
        assert session.get("AIOHTTP_SECURITY") == user["email"]

        # logout
        await client.post(logout_url)
        resp = await client.get(session_url)
        session = await resp.json()
        assert session.get("AIOHTTP_SECURITY") == None
async def test_add_new_project_from_model_instance(
    view,
    client,
    mocker,
):
    view["label"] = view.pop("display_name")
    viewer = ViewerInfo(**view)
    assert viewer.dict() == view

    mock_func = mocker.patch(
        "simcore_service_webserver.director_v2_api.create_or_update_pipeline",
        return_value=None,
    )

    async with NewUser(app=client.app) as user_db:
        try:
            # preparation
            await auto_add_user_to_groups(client.app, user_db["id"])
            user_db = await get_user(client.app, user_db["id"])

            # this part is under test  ---
            user = UserInfo(
                id=user_db["id"],
                name=user_db["name"],
                primary_gid=user_db["primary_gid"],
                email=user_db["email"],
            )

            project_id = "e3ee7dfc-25c3-11eb-9fae-02420a01b846"
            file_picker_id = "4c69c0ce-00e4-4bd5-9cf0-59b67b3a9343"
            viewer_id = "fc718e5a-bf07-4abe-b526-d9cafd34830c"

            project: Project = create_viewer_project_model(
                project_id,
                file_picker_id,
                viewer_id,
                owner=user,
                download_link="http://httpbin.org/image/jpeg",
                viewer_info=viewer,
            )

            await add_new_project(client.app, project, user)

            # checks start here   ---
            assert mock_func.called

            # internally validates project injected in db
            project_db = await get_project_for_user(
                client.app,
                str(project.uuid),
                user.id,
                include_state=False,
                include_templates=False,
            )
            assert set(
                project_db["workbench"].keys()) == {file_picker_id, viewer_id}

        finally:
            # tear-down: delete before user gets deleted
            await delete_all_projects(client.app)
async def test_registration_with_expired_confirmation(
    client: TestClient,
    cfg: LoginOptions,
    db: AsyncpgStorage,
    mocker,
):
    mocker.patch(
        "simcore_service_webserver.login.settings.get_plugin_settings",
        return_value=LoginSettings(
            LOGIN_REGISTRATION_CONFIRMATION_REQUIRED=True,
            LOGIN_REGISTRATION_INVITATION_REQUIRED=True,
        ),
    )

    url = client.app.router["auth_register"].url_for()

    async with NewUser({"status":
                        UserStatus.CONFIRMATION_PENDING.name}) as user:
        confirmation = await db.create_confirmation(
            user, ConfirmationAction.REGISTRATION.name)
        r = await client.post(
            url,
            json={
                "email": user["email"],
                "password": user["raw_password"],
                "confirm": user["raw_password"],
            },
        )
        await db.delete_confirmation(confirmation)

    await assert_error(r, web.HTTPConflict, cfg.MSG_EMAIL_EXISTS)
예제 #4
0
async def standard_groups(
        client, logged_user: Dict) -> AsyncIterator[List[Dict[str, str]]]:
    # create a separate admin account to create some standard groups for the logged user
    sparc_group = {
        "gid": "5",  # this will be replaced
        "label": "SPARC",
        "description": "Stimulating Peripheral Activity to Relieve Conditions",
        "thumbnail":
        "https://commonfund.nih.gov/sites/default/files/sparc-image-homepage500px.png",
        "inclusionRules": {
            "email": r"@(sparc)+\.(io|com)$"
        },
    }
    team_black_group = {
        "gid": "5",  # this will be replaced
        "label": "team Black",
        "description": "THE incredible black team",
        "thumbnail": None,
        "inclusionRules": {
            "email": r"@(black)+\.(io|com)$"
        },
    }
    async with NewUser({
            "name": f"{logged_user['name']}_admin",
            "role": "USER"
    }, client.app) as admin_user:
        # creates two groups
        sparc_group = await create_user_group(client.app, admin_user["id"],
                                              sparc_group)
        team_black_group = await create_user_group(client.app,
                                                   admin_user["id"],
                                                   team_black_group)

        # adds logged_user  to sparc group
        await add_user_in_group(
            client.app,
            admin_user["id"],
            sparc_group["gid"],
            new_user_id=logged_user["id"],
        )

        # adds logged_user  to team-black group
        await add_user_in_group(
            client.app,
            admin_user["id"],
            team_black_group["gid"],
            new_user_email=logged_user["email"],
        )

        _, standard_groups, _ = await list_user_groups(client.app,
                                                       logged_user["id"])
        yield standard_groups
        # clean groups
        await delete_user_group(client.app, admin_user["id"],
                                sparc_group["gid"])
        await delete_user_group(client.app, admin_user["id"],
                                team_black_group["gid"])
예제 #5
0
async def test_reset_and_confirm(client: TestClient, cfg: LoginOptions,
                                 capsys):
    async with NewUser(app=client.app) as user:
        reset_url = client.app.router["auth_reset_password"].url_for()
        rp = await client.post(
            reset_url,
            json={
                "email": user["email"],
            },
        )
        assert rp.url.path == reset_url.path
        await assert_status(rp, web.HTTPOk, cfg.MSG_EMAIL_SENT.format(**user))

        out, err = capsys.readouterr()
        confirmation_url = parse_link(out)
        code = URL(confirmation_url).parts[-1]

        # emulates user click on email url
        rp = await client.get(confirmation_url)
        assert rp.status == 200
        assert (rp.url.path_qs == URL(cfg.LOGIN_REDIRECT).with_fragment(
            "reset-password?code=%s" % code).path_qs)

        # api/specs/webserver/v0/components/schemas/auth.yaml#/ResetPasswordForm
        reset_allowed_url = client.app.router[
            "auth_reset_password_allowed"].url_for(code=code)
        new_password = get_random_string(5, 10)
        rp = await client.post(
            reset_allowed_url,
            json={
                "password": new_password,
                "confirm": new_password,
            },
        )
        payload = await rp.json()
        assert rp.status == 200, payload
        assert rp.url.path == reset_allowed_url.path
        await assert_status(rp, web.HTTPOk, cfg.MSG_PASSWORD_CHANGED)
        # TODO: multiple flash messages

        # Try new password
        logout_url = client.app.router["auth_logout"].url_for()
        rp = await client.post(logout_url)
        assert rp.url.path == logout_url.path
        await assert_status(rp, web.HTTPUnauthorized, "Unauthorized")

        login_url = client.app.router["auth_login"].url_for()
        rp = await client.post(
            login_url,
            json={
                "email": user["email"],
                "password": new_password,
            },
        )
        assert rp.url.path == login_url.path
        await assert_status(rp, web.HTTPOk, cfg.MSG_LOGGED_IN)
예제 #6
0
async def test_change_to_existing_email(client):
    url = client.app.router["auth_change_email"].url_for()

    async with LoggedUser(client) as user:
        async with NewUser() as other:
            rsp = await client.post(url, json={
                "email": other["email"],
            })
            await assert_status(rsp, web.HTTPUnprocessableEntity,
                                "This email cannot be used")
예제 #7
0
async def test_proxy_login(client, cookie_enabled, expected):

    restricted_url = client.app.router["get_my_profile"].url_for()
    assert str(restricted_url) == "/v0/me"

    def build_proxy_session_cookie(identity: str):
        # NOTE: Creates proxy session for authenticated uses in the api-server.
        # Will be used as temporary solution until common authentication
        # service is in place
        #
        import json
        import base64
        import time
        from cryptography import fernet

        # Based on aiohttp_session and aiohttp_security

        # HACK to get secret for testing purposes
        cfg = client.app[APP_CONFIG_KEY]["session"]
        secret_key_bytes = cfg["secret_key"].encode("utf-8")

        while len(secret_key_bytes) < 32:
            secret_key_bytes += secret_key_bytes
        secret_key = secret_key_bytes[:32]

        if isinstance(secret_key, str):
            pass
        elif isinstance(secret_key, (bytes, bytearray)):
            secret_key = base64.urlsafe_b64encode(secret_key)
        _fernet = fernet.Fernet(secret_key)

        # builds session cookie
        cookie_name = "osparc.WEBAPI_SESSION"
        cookie_data = json.dumps({
            "created": int(time.time()),  # now
            "session": {
                "AIOHTTP_SECURITY": identity
            },
            "path": "/",
            # extras? e.g. expiration
        }).encode("utf-8")
        encrypted_cookie_data = _fernet.encrypt(cookie_data).decode("utf-8")

        return {cookie_name: encrypted_cookie_data}

    # ---
    async with NewUser() as user:
        cookies = (build_proxy_session_cookie(
            identity=user["email"]) if cookie_enabled else {})

        resp = await client.get(restricted_url, cookies=cookies)
        data, error = await assert_status(resp, expected)

        if not error:
            assert data["login"] == user["email"]
예제 #8
0
async def test_login_inactive_user(client):
    url = client.app.router["auth_login"].url_for()
    r = await client.get(url)
    assert cfg.MSG_ACTIVATION_REQUIRED not in await r.text()

    async with NewUser({"status": UserStatus.CONFIRMATION_PENDING.name}) as user:
        r = await client.post(
            url, json={"email": user["email"], "password": user["raw_password"]}
        )
    assert r.status == web.HTTPUnauthorized.status_code
    assert r.url_obj.path == url.path
    assert cfg.MSG_ACTIVATION_REQUIRED in await r.text()
예제 #9
0
async def test_registration_with_existing_email(client: TestClient, cfg: LoginOptions):
    url = client.app.router["auth_register"].url_for()
    async with NewUser(app=client.app) as user:
        r = await client.post(
            url,
            json={
                "email": user["email"],
                "password": user["raw_password"],
                "confirm": user["raw_password"],
            },
        )
    await assert_error(r, web.HTTPConflict, cfg.MSG_EMAIL_EXISTS)
예제 #10
0
async def test_banned_user(client, capsys, cfg):
    reset_url = client.app.router["auth_reset_password"].url_for()

    async with NewUser({"status": UserStatus.BANNED.name}) as user:
        rp = await client.post(reset_url, json={
            "email": user["email"],
        })

    assert rp.url_obj.path == reset_url.path
    await assert_status(rp, web.HTTPOk, cfg.MSG_EMAIL_SENT.format(**user))

    out, err = capsys.readouterr()
    assert parse_test_marks(out)["reason"] == cfg.MSG_USER_BANNED
예제 #11
0
async def test_login_successfully(client: TestClient, login_options: LoginOptions):
    url = client.app.router["auth_login"].url_for()

    async with NewUser(app=client.app) as user:
        r = await client.post(
            f"{url}", json={"email": user["email"], "password": user["raw_password"]}
        )
    assert r.status == 200
    data, error = unwrap_envelope(await r.json())

    assert not error
    assert data
    assert login_options.MSG_LOGGED_IN in data["message"]
예제 #12
0
async def test_login_with_wrong_password(client):
    url = client.app.router["auth_login"].url_for()
    r = await client.get(url)
    payload = await r.json()

    assert cfg.MSG_WRONG_PASSWORD not in await r.text(), str(payload)

    async with NewUser() as user:
        r = await client.post(url, json={"email": user["email"], "password": "******",})
        payload = await r.json()
    assert r.status == web.HTTPUnauthorized.status_code, str(payload)
    assert r.url_obj.path == url.path
    assert cfg.MSG_WRONG_PASSWORD in await r.text()
예제 #13
0
async def test_login_banned_user(client: TestClient, login_options: LoginOptions):
    url = client.app.router["auth_login"].url_for()
    r = await client.post(f"{url}")
    assert login_options.MSG_USER_BANNED not in await r.text()

    async with NewUser({"status": UserStatus.BANNED.name}, app=client.app) as user:
        r = await client.post(
            f"{url}", json={"email": user["email"], "password": user["raw_password"]}
        )
        payload = await r.json()

    assert r.status == web.HTTPUnauthorized.status_code, str(payload)
    assert r.url_obj.path == url.path
    assert login_options.MSG_USER_BANNED in payload["error"]["errors"][0]["message"]
예제 #14
0
async def test_inactive_user(client, capsys, cfg):
    reset_url = client.app.router["auth_reset_password"].url_for()

    async with NewUser({"status":
                        UserStatus.CONFIRMATION_PENDING.name}) as user:
        rp = await client.post(reset_url, json={
            "email": user["email"],
        })

    assert rp.url_obj.path == reset_url.path
    await assert_status(rp, web.HTTPOk, cfg.MSG_EMAIL_SENT.format(**user))

    out, err = capsys.readouterr()
    assert parse_test_marks(out)["reason"] == cfg.MSG_ACTIVATION_REQUIRED
예제 #15
0
async def test_proxy_login(
    client: TestClient, cookie_enabled: bool, expected: web.HTTPException
):

    restricted_url = client.app.router["get_my_profile"].url_for()
    assert str(restricted_url) == "/v0/me"

    def _build_proxy_session_cookie(identity: str):
        # NOTE: Creates proxy session for authenticated uses in the api-server.
        # Will be used as temporary solution until common authentication
        # service is in place
        #

        # Based on aiohttp_session and aiohttp_security
        # HACK to get secret for testing purposes
        session_settings = get_plugin_settings(client.app)
        _fernet = fernet.Fernet(session_settings.SESSION_SECRET_KEY.get_secret_value())

        # builds session cookie
        cookie_name = "osparc.WEBAPI_SESSION"
        cookie_data = json.dumps(
            {
                "created": int(time.time()),  # now
                "session": {"AIOHTTP_SECURITY": identity},
                "path": "/",
                # extras? e.g. expiration
            }
        ).encode("utf-8")
        encrypted_cookie_data = _fernet.encrypt(cookie_data).decode("utf-8")

        return {cookie_name: encrypted_cookie_data}

    # ---
    async with NewUser(app=client.app) as user:
        cookies = (
            _build_proxy_session_cookie(identity=user["email"])
            if cookie_enabled
            else {}
        )

        resp = await client.get(restricted_url, cookies=cookies)
        data, error = await assert_status(resp, expected)

        if not error:
            assert data["login"] == user["email"]
예제 #16
0
async def test_too_often(client, capsys, cfg):
    reset_url = client.app.router["auth_reset_password"].url_for()

    cfg = client.app[APP_LOGIN_CONFIG]
    db = cfg.STORAGE

    async with NewUser() as user:
        confirmation = await db.create_confirmation(
            user, ConfirmationAction.RESET_PASSWORD.name)
        rp = await client.post(reset_url, json={
            "email": user["email"],
        })
        await db.delete_confirmation(confirmation)

    assert rp.url_obj.path == reset_url.path
    await assert_status(rp, web.HTTPOk, cfg.MSG_EMAIL_SENT.format(**user))

    out, err = capsys.readouterr()
    assert parse_test_marks(out)["reason"] == cfg.MSG_OFTEN_RESET_PASSWORD
예제 #17
0
async def test_too_often(client: TestClient, cfg: LoginOptions,
                         db: AsyncpgStorage, capsys):
    reset_url = client.app.router["auth_reset_password"].url_for()

    async with NewUser(app=client.app) as user:
        confirmation = await db.create_confirmation(
            user, ConfirmationAction.RESET_PASSWORD.name)
        rp = await client.post(
            reset_url,
            json={
                "email": user["email"],
            },
        )
        await db.delete_confirmation(confirmation)

    assert rp.url.path == reset_url.path
    await assert_status(rp, web.HTTPOk, cfg.MSG_EMAIL_SENT.format(**user))

    out, err = capsys.readouterr()
    assert parse_test_marks(out)["reason"] == cfg.MSG_OFTEN_RESET_PASSWORD
예제 #18
0
async def test_registration_with_expired_confirmation(client, monkeypatch):
    monkeypatch.setitem(cfg, "REGISTRATION_CONFIRMATION_REQUIRED", True)
    monkeypatch.setitem(cfg, "REGISTRATION_CONFIRMATION_LIFETIME", -1)

    db = get_storage(client.app)
    url = client.app.router["auth_register"].url_for()

    async with NewUser({"status":
                        UserStatus.CONFIRMATION_PENDING.name}) as user:
        confirmation = await db.create_confirmation(
            user, ConfirmationAction.REGISTRATION.name)
        r = await client.post(
            url,
            json={
                "email": user["email"],
                "password": user["raw_password"],
                "confirm": user["raw_password"],
            },
        )
        await db.delete_confirmation(confirmation)

    await assert_error(r, web.HTTPConflict, cfg.MSG_EMAIL_EXISTS)
예제 #19
0
async def test_login_with_wrong_password(
    client: TestClient, login_options: LoginOptions
):
    url = client.app.router["auth_login"].url_for()

    r = await client.post(f"{url}")
    payload = await r.json()

    assert login_options.MSG_WRONG_PASSWORD not in await r.text(), str(payload)

    async with NewUser(app=client.app) as user:
        r = await client.post(
            f"{url}",
            json={
                "email": user["email"],
                "password": "******",
            },
        )
        payload = await r.json()
    assert r.status == web.HTTPUnauthorized.status_code, str(payload)
    assert r.url_obj.path == url.path
    assert login_options.MSG_WRONG_PASSWORD in await r.text()
예제 #20
0
async def second_user(client: TestClient) -> Callable[..., Dict[str, Any]]:
    async with NewUser({
            "name": "Second User",
            "role": "USER"
    }, client.app) as user:
        yield user
예제 #21
0
async def second_user(
    client: TestClient,
) -> AsyncIterable[Dict[str, Any]]:
    async with NewUser({"name": "Second User", "role": "USER"}, client.app) as user:
        yield user