Beispiel #1
0
def test_partial(rf, settings, partial_policy):
    from test_app.models import Post

    Post(name="test", is_private=False, timestamp=1).save()
    Post(name="test_past", is_private=False, timestamp=-1).save()
    Post(name="test_public", is_private=False, timestamp=1).save()
    Post(name="test_private", is_private=True, timestamp=1).save()
    Post(name="test_private_2", is_private=True, timestamp=1).save()

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model="test_app::Post")
    q = Post.objects.filter(authorize_filter)
    assert q.count() == 2

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    q = Post.objects.filter(authorize_filter)
    assert q.count() == 5

    q = Post.objects.authorize(request, action="get")
    assert q.count() == 5
Beispiel #2
0
def test_negated_matches_with_partial(rf):
    from test_app.models import Post

    Post(name="test", is_private=False, timestamp=1).save()
    Oso.load_str("""
        allow(1, _, post) if not post matches test_app::Post;
        allow(2, _, post) if not post matches test_app::User;
        allow(3, _, post) if not post.created_by matches test_app::User;
        allow(4, _, post) if not post.created_by matches test_app::Post;
        """)
    request = rf.get("/")

    request.user = 1
    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == (
        f"(AND: {str(TRUE_FILTER)}, (NOT (AND: {str(TRUE_FILTER)})))")
    authorized_posts = Post.objects.filter(authorize_filter)
    # For some reason, this only seems to be raised when stringifying.
    with pytest.raises(EmptyResultSet):
        str(authorized_posts.query)
    assert authorized_posts.count() == 0

    request.user = 2
    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == str(TRUE_FILTER)
    authorized_posts = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
    """
    assert str(authorized_posts.query) == " ".join(expected.split())
    assert authorized_posts.count() == 1

    request.user = 3
    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == (
        f"(AND: {str(TRUE_FILTER)}, (NOT (AND: {str(TRUE_FILTER)})))")
    authorized_posts = Post.objects.filter(authorize_filter)
    # For some reason, this only seems to be raised when stringifying.
    with pytest.raises(EmptyResultSet):
        str(authorized_posts.query)
    assert authorized_posts.count() == 0

    request.user = 4
    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == str(TRUE_FILTER)
    authorized_posts = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
    """
    assert str(authorized_posts.query) == " ".join(expected.split())
    assert authorized_posts.count() == 1
Beispiel #3
0
def test_partial(rf, partial_policy):
    from test_app.models import Post

    posts = [
        Post(name="test", is_private=False, timestamp=1).save(),
        Post(name="test_past", is_private=False, timestamp=-1).save(),
        Post(name="test_public", is_private=False, timestamp=1).save(),
        Post(name="test_private", is_private=True, timestamp=1).save(),
        Post(name="test_private_2", is_private=True, timestamp=1).save(),
        Post(name="test_option", is_private=False, timestamp=1,
             option=True).save(),
    ]

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    assert (
        str(authorize_filter) ==
        f"(AND: {str(TRUE_FILTER)}, ('is_private', False), ('timestamp__gt', 0), ('option', None))"
    )

    q = Post.objects.filter(authorize_filter)
    bool_cond = negated_condition('"test_app_post"."is_private"')
    expected = f"""
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
        WHERE ({bool_cond}
               AND "test_app_post"."timestamp" > 0
               AND "test_app_post"."option" IS NULL)
    """
    assert str(q.query) == " ".join(expected.split())
    assert q.count() == 2

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    assert str(authorize_filter) == str(TRUE_FILTER)

    q = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
    """
    assert str(q.query) == " ".join(expected.split())
    assert q.count() == len(posts)

    q = Post.objects.authorize(request, action="get")
    assert q.count() == len(posts)
Beispiel #4
0
def test_partial(rf, partial_policy):
    from test_app.models import Post

    posts = [
        Post(name="test", is_private=False, timestamp=1).save(),
        Post(name="test_past", is_private=False, timestamp=-1).save(),
        Post(name="test_public", is_private=False, timestamp=1).save(),
        Post(name="test_private", is_private=True, timestamp=1).save(),
        Post(name="test_private_2", is_private=True, timestamp=1).save(),
        Post(name="test_option", is_private=False, timestamp=1,
             option=True).save(),
    ]

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    assert (
        str(authorize_filter) ==
        "(AND: (NOT (AND: ('pk__in', []))), ('is_private', False), ('timestamp__gt', 0), ('option', None))"
    )

    q = Post.objects.filter(authorize_filter)
    assert (
        str(q.query) ==
        'SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",'
        +
        ' "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"'
        + ' FROM "test_app_post"' +
        ' WHERE (NOT "test_app_post"."is_private" AND "test_app_post"."timestamp" > 0 AND "test_app_post"."option" IS NULL)'
    )
    assert q.count() == 2

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    assert str(authorize_filter) == "(NOT (AND: ('pk__in', [])))"

    q = Post.objects.filter(authorize_filter)
    assert (
        str(q.query) ==
        'SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",'
        +
        ' "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"'
        + ' FROM "test_app_post"')
    assert q.count() == len(posts)

    q = Post.objects.authorize(request, action="get")
    assert q.count() == len(posts)
Beispiel #5
0
    def authorize(self, request, *, actor=None, action=None):
        """Return a new ``Queryset`` filtered to contain only authorized models.

        .. warning::

            This feature is currently in preview.

        :param actor: The actor making the request. Defaults to ``request.user``.
        :param action: The action to authorize the actor to perform. Defaults to
                        ``request.method``.
        """
        try:
            filter = authorize_model(request=request,
                                     model=self.model,
                                     actor=actor,
                                     action=action)
        except PermissionDenied:
            return self.none()

        # SELECT DISTINCT on inner query to support chaining methods on
        # returned QuerySet.
        if filter == TRUE_FILTER:
            return self.filter(filter)
        else:
            return self.filter(pk__in=self.filter(filter))
Beispiel #6
0
def test_partial_isa_with_path():
    from test_app.models import Post, User

    alice = User(name="alice")
    alice.save()
    not_alice = User(name="not alice")
    not_alice.save()

    Post(created_by=alice).save(),
    Post(created_by=not_alice).save(),
    Post(created_by=alice).save(),

    Oso.load_str("""
            allow(_, _, post: test_app::Post) if check(post.created_by);
            check(user: test_app::User) if user.name = "alice";
            check(post: test_app::Post) if post.is_private = false;
        """)

    authorize_filter = authorize_model(None, Post, actor="foo", action="bar")
    assert (str(authorize_filter) ==
            f"(AND: {str(TRUE_FILTER)}, ('created_by__name', 'alice'))")
    authorized_posts = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
        INNER JOIN "test_app_user" ON ("test_app_post"."created_by_id" = "test_app_user"."id")
        WHERE "test_app_user"."name" = alice
    """
    assert str(authorized_posts.query) == " ".join(expected.split())
    assert authorized_posts.count() == 2
Beispiel #7
0
def test_partial_subfield_isa():
    from test_app.models import Post, User

    alice = User(name="alice")
    alice.save()
    not_alice = User(name="not alice")
    not_alice.save()

    Post(created_by=alice).save(),
    Post(created_by=not_alice).save(),
    Post(created_by=alice).save(),

    Oso.load_str("""
            allow(_, _, post: test_app::Post) if check(post.created_by);
            check(user: test_app::User) if user.name = "alice";
            check(post: test_app::Post) if post.is_private = false;
        """)

    authorize_filter = authorize_model(None, Post, actor="foo", action="bar")
    assert (
        str(authorize_filter) == "(OR:" +
        " (AND: (NOT (AND: ('pk__in', []))), (NOT (AND: ('pk__in', []))), ('created_by__name', 'alice')),"
        + " ('pk__in', []))")
    authorized_posts = Post.objects.filter(authorize_filter)
    assert (
        str(authorized_posts.query) ==
        'SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",'
        +
        ' "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"'
        + ' FROM "test_app_post" LEFT OUTER JOIN "test_app_user"' +
        ' ON ("test_app_post"."created_by_id" = "test_app_user"."id") WHERE "test_app_user"."name" = alice'
    )
    assert authorized_posts.count() == 2
Beispiel #8
0
def test_rewrite_parameters():
    from test_app.models import Post

    Oso.load_str("""allow(_, _, resource) if g(resource.created_by);
           g(resource) if resource matches test_app::User;
        """)
    authorize_filter = authorize_model(None, Post, actor="foo", action="bar")
    assert str(authorize_filter) == str(TRUE_FILTER)
Beispiel #9
0
def test_partial(rf, settings, partial_policy):
    from test_app.models import Post

    posts = [
        Post(name="test", is_private=False, timestamp=1).save(),
        Post(name="test_past", is_private=False, timestamp=-1).save(),
        Post(name="test_public", is_private=False, timestamp=1).save(),
        Post(name="test_private", is_private=True, timestamp=1).save(),
        Post(name="test_private_2", is_private=True, timestamp=1).save(),
        Post(name="test_option", is_private=False, timestamp=1,
             option=True).save(),
    ]

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request,
                                       action="get",
                                       model="test_app::Post")
    assert (
        str(authorize_filter) ==
        "(AND: ('is_private', False), ('timestamp__gt', 0), ('option', None))")

    q = Post.objects.filter(authorize_filter)
    assert q.count() == 2

    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, action="get", model=Post)
    assert str(authorize_filter) == "(AND: )"

    q = Post.objects.filter(authorize_filter)
    assert q.count() == len(posts)

    q = Post.objects.authorize(request, action="get")
    assert q.count() == len(posts)
Beispiel #10
0
def test_partial_with_allow_all(rf):
    from test_app.models import Post

    Post(name="test", is_private=False, timestamp=1).save()
    Oso.load_str("allow(_, _, _);")
    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == str(TRUE_FILTER)
    authorized_posts = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
    """
    assert str(authorized_posts.query) == " ".join(expected.split())
    assert authorized_posts.count() == 1
Beispiel #11
0
def test_null_with_partial(rf):
    from test_app.models import Post

    Post(name="test", is_private=False, timestamp=1).save()
    Oso.load_str("allow(_, _, post: test_app::Post) if post.option = nil;")
    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, Post)
    assert (str(authorize_filter) ==
            "(AND: (NOT (AND: ('pk__in', []))), ('option', None))")
    authorized_posts = Post.objects.filter(authorize_filter)
    assert str(authorized_posts.query) == (
        'SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name", '
        +
        '"test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"'
        + ' FROM "test_app_post"' + ' WHERE "test_app_post"."option" IS NULL')
    assert authorized_posts.count() == 1
Beispiel #12
0
def test_null_with_partial(rf):
    from test_app.models import Post

    Post(name="test", is_private=False, timestamp=1).save()
    Oso.load_str("allow(_, _, post: test_app::Post) if post.option = nil;")
    request = rf.get("/")
    request.user = "******"

    authorize_filter = authorize_model(request, Post)
    assert str(authorize_filter) == "(AND: ('option', None))"
    authorized_posts = Post.objects.filter(authorize_filter)
    expected = """
        SELECT "test_app_post"."id", "test_app_post"."is_private", "test_app_post"."name",
               "test_app_post"."timestamp", "test_app_post"."option", "test_app_post"."created_by_id"
        FROM "test_app_post"
        WHERE "test_app_post"."option" IS NULL
    """
    assert str(authorized_posts.query) == " ".join(expected.split())
    assert authorized_posts.count() == 1
Beispiel #13
0
    def authorize(self, request, *, actor=None, action=None):
        """Return a new ``Queryset`` filtered to contain only authorized models.

        .. warning::

            This feature is currently in preview.

        :param actor: The actor making the request. Defaults to ``request.user``.
        :param action: The action to authorize the actor to perform. Defaults to
                        ``request.method``.
        """
        try:
            filter = authorize_model(
                request=request, model=self.model, actor=actor, action=action
            )
        except PermissionDenied:
            return self.none()

        return self.filter(filter)
Beispiel #14
0
def repos_index(request, org_name):
    if request.method == "GET":
        repo_filter = authorize_model(request, Repository, action="read")
        repos = Repository.objects.filter(repo_filter,
                                          organization__name=org_name)
        context = {"org_name": org_name, "repo_list": repos}
        return render(request, "repos/index.html", context)
    if request.method == "POST":
        try:
            name = request.POST["name"]
        except KeyError as e:
            messages.add_message(request, DANGER, "Missing field: %s" % str(e))
            return render(request, f"repos/new.html")
        else:
            if Repository.objects.filter(name=name).count() > 0:
                messages.add_message(request, DANGER,
                                     "Repository already exists: %s" % name)
                return render(request,
                              "repos/new.html",
                              context={"org_name": org_name})

            # create the repository
            repo = Repository(
                name=name,
                organization=Organization.objects.get(name=org_name))
            repo.save()
            # Create the base roles for each repository created
            # NOTE: better to do this lazily
            for (role_level, _) in RepositoryRoleLevel.choices:
                role = RepositoryRole(name=role_level, repository=repo)
                role.save()
                if role.name == RepositoryRoleLevel.ADMIN:
                    role.users.add(request.user)
                    role.save()
            messages.success(request,
                             'Repository "%s" created successfully' % name)
            print(org_name)
            return redirect(f"/orgs/{org_name}/repos/")
Beispiel #15
0
def orgs_index(request):
    if request.method == "GET":
        org_filter = authorize_model(request, Organization, action="read")
        orgs = Organization.objects.filter(org_filter)
        context = {"org_list": orgs}
        return render(request, "orgs/index.html", context)
Beispiel #16
0
def teams_index(request, org_name):
    if request.method == "GET":
        team_filter = authorize_model(request, Team, action="read")
        teams = Team.objects.filter(team_filter, organization__name=org_name)
        context = {"org_name": org_name, "team_list": teams}
        return render(request, "teams/index.html", context)