def test_that_existing_permissions_are_added(app, client):

    security = FastAPISecurity()

    permission = security.user_permission("users:list")  # noqa

    @app.get("/users/me")
    def get_user_info(user: User = Depends(security.authenticated_user_or_401)):
        return user.without_access_token()

    security.init_oauth2_through_jwks(dummy_jwks_uri, audiences=[dummy_audience])

    access_token = make_access_token(
        sub="test-subject",
        permissions=["users:list"],
    )

    with aioresponses() as mock:
        mock.get(dummy_jwks_uri, payload=dummy_jwks_response_data)

        resp = client.get(
            "/users/me", headers={"Authorization": f"Bearer {access_token}"}
        )
        assert resp.status_code == 200
        data = resp.json()["auth"]
        del data["expires_at"]
        del data["issued_at"]
        assert data == {
            "audience": ["https://some-resource"],
            "auth_method": "oauth2",
            "issuer": "https://identity-provider/",
            "permissions": ["users:list"],
            "scopes": [],
            "subject": "test-subject",
        }
Exemple #2
0
def test_that_user_must_have_all_permissions(app, client):

    security = FastAPISecurity()

    can_list = security.user_permission("users:list")  # noqa
    can_view = security.user_permission("users:view")  # noqa

    @app.get("/users")
    def get_user_list(user: User = Depends(security.user_holding(can_list, can_view))):
        return [user]

    security.init_oauth2_through_jwks(dummy_jwks_uri, audiences=[dummy_audience])

    bad_token = make_access_token(sub="test-user", permissions=["users:list"])
    valid_token = make_access_token(
        sub="JaneDoe",
        permissions=["users:list", "users:view"],
    )

    with aioresponses() as mock:
        mock.get(dummy_jwks_uri, payload=dummy_jwks_response_data)

        resp = client.get("/users", headers={"Authorization": f"Bearer {bad_token}"})
        assert resp.status_code == 403
        assert resp.json() == {"detail": "Missing required permission users:view"}

        resp = client.get("/users", headers={"Authorization": f"Bearer {valid_token}"})
        assert resp.status_code == 200
        (user1,) = resp.json()
        assert user1["auth"]["subject"] == "JaneDoe"
Exemple #3
0
def test_that_missing_permission_results_in_403(app, client):

    security = FastAPISecurity()

    can_list = security.user_permission("users:list")  # noqa

    @app.get("/users")
    def get_user_list(user: User = Depends(security.user_holding(can_list))):
        return [user]

    security.init_oauth2_through_jwks(dummy_jwks_uri, audiences=[dummy_audience])

    access_token = make_access_token(sub="test-user", permissions=[])

    with aioresponses() as mock:
        mock.get(dummy_jwks_uri, payload=dummy_jwks_response_data)

        resp = client.get("/users", headers={"Authorization": f"Bearer {access_token}"})
        assert resp.status_code == 403
        assert resp.json() == {"detail": "Missing required permission users:list"}
def test_that_explicit_permission_overrides_are_applied(app, client):
    cred = HTTPBasicCredentials(username="******", password="******")

    security = FastAPISecurity()

    create_product_perm = security.user_permission("products:create")

    security.init_basic_auth([cred])
    security.add_permission_overrides({"johndoe": ["products:create"]})

    @app.post("/products")
    def create_product(
        user: User = Depends(security.user_holding(create_product_perm)),
    ):
        return {"ok": True}

    resp = client.post("/products", auth=("johndoe", "123"))

    assert resp.status_code == 200
    assert resp.json() == {"ok": True}
Exemple #5
0
def test_that_assigned_permission_result_in_200(app, client):

    security = FastAPISecurity()

    can_list = security.user_permission("users:list")  # noqa

    @app.get("/users")
    def get_user_list(user: User = Depends(security.user_holding(can_list))):
        return [user]

    security.init_oauth2_through_jwks(dummy_jwks_uri, audiences=[dummy_audience])

    access_token = make_access_token(sub="test-user", permissions=["users:list"])

    with aioresponses() as mock:
        mock.get(dummy_jwks_uri, payload=dummy_jwks_response_data)

        resp = client.get("/users", headers={"Authorization": f"Bearer {access_token}"})
        assert resp.status_code == 200
        (user1,) = resp.json()
        assert user1["auth"]["subject"] == "test-user"
def test_that_permission_overrides_can_be_an_exhaustable_iterator(app, client):
    cred = HTTPBasicCredentials(username="******", password="******")

    security = FastAPISecurity()

    create_product_perm = security.user_permission("products:create")

    security.init_basic_auth([cred])

    overrides = iter(["products:create"])
    security.add_permission_overrides({"johndoe": overrides})

    @app.post("/products")
    def create_product(
        user: User = Depends(security.user_holding(create_product_perm)),
    ):
        return {"ok": True}

    # NOTE: Before v0.3.1, the second iteration would give a HTTP403, as the overrides
    #       iterator had been exhausted on the first try.
    for _ in range(2):
        resp = client.post("/products", auth=("johndoe", "123"))
        assert resp.status_code == 200
        assert resp.json() == {"ok": True}
Exemple #7
0
if settings.oidc_discovery_url:
    security.init_oauth2_through_oidc(
        settings.oidc_discovery_url,
        audiences=settings.oauth2_audiences,
    )
elif settings.oauth2_jwks_url:
    security.init_oauth2_through_jwks(
        settings.oauth2_jwks_url,
        audiences=settings.oauth2_audiences,
    )

security.add_permission_overrides(settings.permission_overrides or {})

logger = logging.getLogger(__name__)

create_product_perm = security.user_permission("products:create")


@app.get("/users/me")
async def get_user_details(user: User = Depends(security.user_with_info)):
    """Return user details, regardless of whether user is authenticated or not"""
    return user.without_access_token()


@app.get("/users/me/permissions", response_model=List[str])
def get_user_permissions(user: User = Depends(
    security.authenticated_user_or_401)):
    """Return user permissions or HTTP401 if not authenticated"""
    return user.permissions