Example #1
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 #2
0
async def coreapi_error_middleware(request, handler):
    """Implementation of:
    http://www.coreapi.org/specification/transport/#coercing-4xx-and-5xx-responses-to-errors
    """
    try:
        return await handler(request)
    except web.HTTPException as ex:
        return serialize(request, {
            "_type": "error",
            "_meta": {
                "title": ex.reason
            }
        }, ex.status)
Example #3
0
async def get_users(request: web.Request) -> web.Response:
    """Handlers for GET /users/, just describes that a POST is possible."""
    hostname = request.app["settings"]["hostname"]
    errors, users = await _get_users(request)
    last_element = users[-1] if users else None
    content = {
        "users": [
            coreapi.Document(url=f"{hostname}/users/{user}/",
                             content={"username": user}) for user in users
        ],
        "errors":
        errors,
    }

    register_user = await find_register_user_provider(request)
    if register_user:  # pragma: no cover  # Needs a running kisee.
        content["register_user"] = register_user

    if last_element:
        if request.rel_url.query:
            if not request.rel_url.query.get("after"):
                next_endpoint = f"{hostname}{request.rel_url}&after={last_element}"
            else:
                parsed_query = parse_qs(request.rel_url.raw_query_string)
                query = {
                    key: "".join(value)
                    for key, value in parsed_query.items()
                }
                query["after"] = last_element
                query_string = "?" + "&".join(
                    [f"{key}={value}" for key, value in query.items()])
                next_endpoint = f"{hostname}{request.path}{query_string}"
        else:
            next_endpoint = f"{hostname}{request.rel_url}?after={last_element}"
        content["next"] = coreapi.Link(url=next_endpoint)

    return serialize(
        request,
        coreapi.Document(
            url=f"{hostname}/users/",
            title="Users management interface",
            content=content,
        ),
        headers={"Vary": "Origin"},
    )
Example #4
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 #5
0
async def get_tokens(request: web.Request) -> web.Response:
    """Handlers for GET /token/, just describes that a POST is possible."""
    hostname = request.app["settings"]["hostname"]
    access_token, refresh_token = None, None
    identity_provider_input = request.rel_url.query.get("idp", None)
    if identity_provider_input:
        access_token, refresh_token = await handle_oauth_callback(
            identity_provider_input, request
        )

    idps = {}
    for idp_name, idp_conf in request.app["settings"]["idps"].items():
        fields: List[coreapi.Field] = []
        if idp_conf.get("input_fields"):
            fields = [
                coreapi.Field(name=field.get("name"), required=field.get("required"))
                for field in idp_conf["input_fields"]
            ]
        idps[f"identify_via_{idp_name}"] = coreapi.Link(
            action="post",
            title=idp_conf.get("title"),
            description=idp_conf.get("description"),
            fields=fields,
            url=f"/tokens/?idp={idp_name}",
        )

    return serialize(
        request,
        coreapi.Document(
            url=f"{hostname}/token",
            title="Request Token From Identity Provider",
            content={
                "access_token": access_token,
                "refresh_token": refresh_token,
                **idps,
            },
        ),
    )
Example #6
0
async def get_groups(request: web.Request) -> web.Response:
    """Handlers for GET /groups/"""
    hostname = request.app["settings"]["hostname"]
    errors, groups = await _get_groups(request)
    content = {
        "groups": [
            coreapi.Document(url=f"{hostname}/groups/{group}/",
                             content={"group": group}) for group in groups
        ],
        "create_group":
        coreapi.Link(
            action="post",
            title="Create a group",
            description="A method to create a group by a staff member",
            fields=[coreapi.Field(name="group", required=True)],
        ),
        "get_groups_of_user":
        coreapi.Link(
            action="get",
            title="Get groups of user",
            description="Get list of groups of a user",
            url=f"{hostname}/groups/{{?user}}",
        ),
        "errors":
        errors,
    }
    if groups:
        content["next"] = coreapi.Link(
            url=f"{hostname}/groups/?last_element={groups[-1]}")
    return serialize(
        request,
        coreapi.Document(
            url=f"{hostname}/groups/",
            title="Groups of Identity Manager",
            content=content,
        ),
        headers={"Vary": "Origin"},
    )
Example #7
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"},
    )