Example #1
0
async def post_groups(request: web.Request) -> web.Response:
    """Handler for POST /groups/"""
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    input_data = await request.json()
    if "group" not in input_data:
        raise web.HTTPBadRequest(reason="Missing group")

    group_name = input_data["group"]

    if not is_authorized_for_group_create(claims["groups"], group_name):
        raise web.HTTPForbidden(reason="Not authorized to create group")

    storage_backend = request.app["storage_backend"]
    staff_group_name = f"{group_name}.staff"

    if await storage_backend.group_exists(group_name):
        raise web.HTTPConflict(reason="Group already exists")

    await storage_backend.create_group(group_name)
    await storage_backend.create_group(staff_group_name)
    await storage_backend.add_member_to_group(claims["sub"], staff_group_name)

    location = f"/groups/{group_name}/"
    return web.Response(status=201, headers={"Location": location})
Example #2
0
async def post_group(request: web.Request) -> web.Response:
    """Handler for POST /groups/{group_id}/
    add a user to {group_id}
    """
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    input_data = await request.json()
    storage_backend = request.app["storage_backend"]
    group = request.match_info["group_uid"]

    if not is_authorized_for_group(claims["groups"], group):
        raise web.HTTPForbidden(reason="Not authorized to manage group")

    if not await storage_backend.group_exists(group):
        raise web.HTTPNotFound(reason="Group does not exist")

    if "username" not in input_data:
        raise web.HTTPBadRequest(reason="Missing username in request body")
    username = input_data["username"]
    if not await storage_backend.user_exists(username):
        await request.app["storage_backend"].create_user(username)
    if await storage_backend.is_user_in_group(username, group):
        raise web.HTTPBadRequest(reason="User already in group")

    await storage_backend.add_member_to_group(username, group)
    return web.Response(status=201)
Example #3
0
def test_enforce_authorization__not_valid_bearer_token():
    with pytest.raises(Unauthorized):
        assert enforce_authorization(
            {"Authorization": f"Bearer {WRONG_TOKEN}"},
            {
                "public_key": PUBLIC_KEY,
                "algorithm": ALGORITHM
            },
        )
Example #4
0
async def post_token(request: web.Request) -> web.Response:
    """Post to IDP to create a jwt token"""
    # Proceed as a refresh token handler if query string refresh is available
    if "refresh" in request.rel_url.query:
        if not request.headers.get("Authorization"):
            raise web.HTTPBadRequest(
                reason="Missing Authorization header for refreshing access token"
            )
        claims = utils.enforce_authorization(request.headers, request.app["settings"])
        if not claims.get("refresh_token", False):
            raise Unauthorized("Token is not a refresh token")
    else:
        claims = await authenticate_with_identity_provider(request)

    response_content: Dict[str, Any] = {
        "identify_to_kisee": coreapi.Link(
            action="post",
            title="Login via login/password pair",
            description="""
                POSTing to this endpoint will identify you by login/password.
            """,
            fields=[
                coreapi.Field(name="login", required=True),
                coreapi.Field(name="password", required=True),
            ],
            url="/tokens/?idp=kisee",
        )
    }

    if "sub" in claims:
        storage_backend = request.app["storage_backend"]
        if not await storage_backend.user_exists(claims["sub"]):
            await storage_backend.create_user(claims["sub"])

        claims["groups"] = await storage_backend.get_authorizations_for_user(
            claims["sub"]
        )
        access_token, refresh_token = generate_access_token_and_refresh_token_pairs(
            claims,
            request.app["settings"]["private_key"],
            algorithm=request.app["settings"]["algorithm"],
        )
        response_content["access_token"] = access_token
        response_content["refresh_token"] = refresh_token
    else:
        response_content["authorize_url"] = claims["authorize_url"]

    return serialize(
        request,
        coreapi.Document(
            url="/tokens/",
            title="Create a token with Identify Provider",
            content=response_content,
        ),
        headers={"Cache-Control": "no-store", "Pragma": "no-cache"},
        status=201,
    )
Example #5
0
def test_enforce_authorization__expired_token():
    expired_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJmb28iLCJleHAiOjE1NDE2OTI1NjAuNDU1Nzc5fQ.o3ZPwFmqJ3PLpxoZ854sHuu5ozD18J6kD7EdG2ospWSlovcgxGvSo65Hdgd8_RPHUDDJu4RZ4FwkyT1VTFRi_A"
    with pytest.raises(Unauthorized):
        assert enforce_authorization(
            {"Authorization": f"Bearer {expired_token}"},
            {
                "public_key": PUBLIC_KEY,
                "algorithm": ALGORITHM
            },
        )
Example #6
0
async def delete_user(request: web.Request) -> web.Response:
    """Handlers for DELETE /users/{username}
    Delete {username}
    """
    username = request.match_info["username"]
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    if not is_root(claims["groups"]):
        raise web.HTTPForbidden(reason="Do not have rights to delete user")
    await request.app["storage_backend"].delete_user(username)
    return web.Response(status=204)
Example #7
0
async def delete_group_member(request: web.Request) -> web.Response:
    """Delete group member of group"""
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    storage_backend = request.app["storage_backend"]
    group = request.match_info["group_uid"]
    username = request.match_info["username"]

    if not await storage_backend.group_exists(group):
        raise web.HTTPNotFound(reason="Group does not exist")
    if not is_authorized_for_group(claims["groups"], group):
        raise web.HTTPForbidden(reason="Not authorized to manage group")
    if not await storage_backend.is_user_in_group(username, group):
        raise web.HTTPNotFound(reason="User does not exist in group")
    await storage_backend.delete_member_in_group(username, group)
    return web.Response(status=204)
Example #8
0
async def get_user(request: web.Request) -> web.Response:
    """Handlers for GET /users/{username}
    List groups of {username}
    """
    hostname = request.app["settings"]["hostname"]
    username = request.match_info["username"]

    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    if not is_root(
            claims["groups"]) and not claims["sub"] == username:  # is user
        raise web.HTTPForbidden(reason="Do not have rights to view user info")

    last_element = request.rel_url.query.get("last_element", "")

    user = await request.app["storage_backend"].get_user(username)
    if not user:
        raise web.HTTPNotFound(reason="User does not exist")

    groups = await request.app["storage_backend"].get_groups_of_user(
        username, last_element)

    content = user
    content["patch"] = coreapi.Link(
        action="patch",
        title="Patch fields of user",
        description="A method to patch fields of user",
        fields=[coreapi.Field(name="is_banned")],
    )

    if groups:
        content["next"] = coreapi.Link(
            url=f"{hostname}/users/{username}?last_element={groups[-1]}")
        content["groups"] = [
            coreapi.Document(url=f"{hostname}/groups/{group}/",
                             content={"group": group}) for group in groups
        ]

    return serialize(
        request,
        coreapi.Document(url=f"{hostname}/users/{username}",
                         title="User interface",
                         content=content),
        headers={"Vary": "Origin"},
    )
Example #9
0
async def delete_group(request: web.Request) -> web.Response:
    """Handler for POST /groups/{group_id}/
    add a user to {group_id}
    """
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    storage_backend = request.app["storage_backend"]
    group = request.match_info["group_uid"]

    if not is_authorized_for_group(claims["groups"], "staff"):
        raise web.HTTPForbidden(reason="Not authorized to manage group")

    if not await storage_backend.group_exists(group):
        raise web.HTTPNotFound(reason="Group does not exist")

    await storage_backend.delete_group(group)
    await storage_backend.delete_group(f"{group}.staff")
    return web.Response(status=204)
Example #10
0
async def patch_user(request: web.Request) -> web.Response:
    """Handlers for PATCH /users/{username}
    Patch an user
    """
    username = request.match_info["username"]

    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    if not is_root(claims["groups"]):
        raise web.HTTPForbidden(reason="Do not have rights to patch")

    user = await request.app["storage_backend"].get_user(username)
    if not user:
        raise web.HTTPNotFound(reason="User does not exist")

    input_data = await request.json()
    if "username" in input_data:
        raise web.HTTPBadRequest(reason="can not patch username")
    if "is_banned" in input_data:
        ban = input_data["is_banned"]
        await request.app["storage_backend"].ban_user(username, ban)
    return web.Response(status=204)
Example #11
0
async def get_group(request: web.Request) -> web.Response:
    """Handler for GET /groups/{group_uid}"""
    hostname = request.app["settings"]["hostname"]
    claims = utils.enforce_authorization(request.headers,
                                         request.app["settings"])
    storage_backend = request.app["storage_backend"]
    group = request.match_info["group_uid"]

    if not is_authorized_for_group(claims["groups"], group):
        raise web.HTTPForbidden(reason="Not authorized to view group")

    if not await storage_backend.group_exists(group):
        raise web.HTTPNotFound(reason="Group does not exist")

    members = await storage_backend.get_members_of_group(group)
    return serialize(
        request,
        coreapi.Document(
            url=f"{hostname}/groups/{{group}}/",
            title=f"{group} group management interface",
            content={
                "members": [
                    coreapi.Document(url=f"{hostname}/users/{member}",
                                     content={"username": member})
                    for member in members
                ],
                "add_member":
                coreapi.Link(
                    action="post",
                    title="Add a member to group",
                    description="A method to add a member to group",
                    fields=[coreapi.Field(name="username", required=True)],
                ),
            },
        ),
        headers={"Vary": "Origin"},
    )
Example #12
0
def test_enforce_authorization__wrong_scheme():
    with pytest.raises(Unauthorized):
        assert enforce_authorization(
            {"Authorization": "not-expected-scheme token"}, {})
Example #13
0
def test_enforce_authorization__no_scheme_value_value_pair_in_header():
    with pytest.raises(Unauthorized):
        assert enforce_authorization({"Authorization": "some-weird-token"}, {})
Example #14
0
def test_enforce_authorization__missing_authorization_header():
    with pytest.raises(Unauthenticated):
        assert enforce_authorization({}, {})