2022-07-22 02:19:47 +12:00
|
|
|
defmodule Ash.Test.Policy.RbacTest do
|
2022-05-18 07:56:40 +12:00
|
|
|
@doc false
|
|
|
|
use ExUnit.Case
|
|
|
|
|
2022-12-20 21:12:40 +13:00
|
|
|
require Ash.Query
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
alias Ash.Test.Support.PolicyRbac.{File, Membership, Organization, User}
|
2022-05-18 07:56:40 +12:00
|
|
|
|
|
|
|
setup do
|
|
|
|
[
|
2024-03-28 09:06:40 +13:00
|
|
|
user: Ash.create!(Ash.Changeset.for_create(User, :create), authorize?: false),
|
|
|
|
org: Ash.create!(Ash.Changeset.for_create(Organization, :create), authorize?: false)
|
2022-05-18 07:56:40 +12:00
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
test "if the actor has no permissions, they can't see anything", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
create_file(org, "foo")
|
|
|
|
create_file(org, "bar")
|
|
|
|
create_file(org, "baz")
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert Ash.read!(File, actor: user) == []
|
2022-05-18 07:56:40 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
test "if the actor has permission to read a file, they can only read that file", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
file_with_access = create_file(org, "foo")
|
|
|
|
give_role(user, org, :viewer, :file, file_with_access.id)
|
|
|
|
create_file(org, "bar")
|
|
|
|
create_file(org, "baz")
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert [%{name: "foo"}] = Ash.read!(File, actor: user)
|
2022-05-18 07:56:40 +12:00
|
|
|
end
|
|
|
|
|
2022-12-20 21:12:40 +13:00
|
|
|
test "query params on relation are passed correctly to the policy", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
user = Map.put(user, :rel_check, true)
|
|
|
|
|
|
|
|
file_with_access = create_file(org, "foo")
|
|
|
|
give_role(user, org, :viewer, :file, file_with_access.id)
|
|
|
|
create_file(org, "bar")
|
|
|
|
create_file(org, "baz")
|
|
|
|
|
|
|
|
# select a forbidden field
|
|
|
|
query =
|
|
|
|
Organization
|
|
|
|
|> Ash.Query.filter(id == ^org.id)
|
|
|
|
|> Ash.Query.load(files: File |> Ash.Query.select([:forbidden]))
|
|
|
|
|
2024-09-03 06:11:09 +12:00
|
|
|
assert [%{files: []}] = Ash.read!(query, actor: user)
|
2022-12-20 21:12:40 +13:00
|
|
|
|
|
|
|
# specify no select (everything is selected)
|
|
|
|
query =
|
|
|
|
Organization
|
|
|
|
|> Ash.Query.filter(id == ^org.id)
|
|
|
|
|> Ash.Query.load([:files])
|
|
|
|
|
2024-09-03 06:11:09 +12:00
|
|
|
assert [%{files: []}] = Ash.read!(query, actor: user)
|
2022-12-20 21:12:40 +13:00
|
|
|
|
|
|
|
# select only an allowed field
|
|
|
|
query =
|
|
|
|
Organization
|
|
|
|
|> Ash.Query.filter(id == ^org.id)
|
|
|
|
|> Ash.Query.load(files: File |> Ash.Query.select([:id]))
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert [%Organization{files: [%File{id: id}]}] = Ash.read!(query, actor: user)
|
2022-12-20 21:12:40 +13:00
|
|
|
assert id == file_with_access.id
|
|
|
|
end
|
|
|
|
|
2022-05-18 07:56:40 +12:00
|
|
|
test "unauthorized if no policy is defined", %{user: user} do
|
|
|
|
assert_raise Ash.Error.Forbidden, fn ->
|
2024-03-28 09:06:40 +13:00
|
|
|
Ash.read!(User, actor: user) == []
|
2022-05-18 07:56:40 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-15 02:05:51 +12:00
|
|
|
test "if the action can be performed, the can utility should return true", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
file_with_access = create_file(org, "foo")
|
|
|
|
give_role(user, org, :viewer, :file, file_with_access.id)
|
2023-03-09 10:34:44 +13:00
|
|
|
file1 = create_file(org, "bar")
|
|
|
|
file2 = create_file(org, "baz")
|
2022-07-15 02:05:51 +12:00
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert Ash.can?({File, :read}, user)
|
|
|
|
refute Ash.can?({File, :read}, user, data: [file1, file2])
|
|
|
|
assert Ash.can?({File, :read}, user, data: file_with_access)
|
2024-05-29 23:31:18 +12:00
|
|
|
|
|
|
|
assert Ash.can?({File, :read, %{}}, user)
|
|
|
|
refute Ash.can?({File, :read, %{}}, user, data: [file1, file2])
|
|
|
|
assert Ash.can?({File, :read, %{}}, user, data: file_with_access)
|
2022-07-15 02:05:51 +12:00
|
|
|
end
|
|
|
|
|
2022-10-11 04:50:13 +13:00
|
|
|
test "if the query can be performed, the can utility should return true", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
file_with_access = create_file(org, "foo")
|
|
|
|
give_role(user, org, :viewer, :file, file_with_access.id)
|
|
|
|
create_file(org, "bar")
|
|
|
|
create_file(org, "baz")
|
|
|
|
|
|
|
|
query = Ash.Query.for_read(File, :read)
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert Ash.can?(query, user)
|
2022-10-11 04:50:13 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
test "if the changeset can be performed, the can utility should return true", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
changeset =
|
|
|
|
File
|
2024-03-28 09:06:40 +13:00
|
|
|
|> Ash.Changeset.for_create(:create, %{name: "bar"})
|
2022-10-11 04:50:13 +13:00
|
|
|
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert Ash.can?(changeset, user)
|
2023-03-09 10:34:44 +13:00
|
|
|
end
|
|
|
|
|
|
|
|
test "if the update can be performed with a filter, the can utility should return true", %{
|
|
|
|
user: user,
|
|
|
|
org: org
|
|
|
|
} do
|
|
|
|
file_with_access = create_file(org, "foo")
|
|
|
|
give_role(user, org, :admin, :file, file_with_access.id)
|
|
|
|
|
|
|
|
changeset = Ash.Changeset.for_update(file_with_access, :update, %{name: "bar"})
|
|
|
|
|
2024-03-28 09:06:40 +13:00
|
|
|
assert Ash.can?(changeset, user)
|
2022-10-11 04:50:13 +13:00
|
|
|
end
|
|
|
|
|
2022-05-18 07:56:40 +12:00
|
|
|
defp give_role(user, org, role, resource, resource_id) do
|
|
|
|
Membership
|
2024-03-28 09:06:40 +13:00
|
|
|
|> Ash.Changeset.for_create(:create, %{
|
|
|
|
role: role,
|
|
|
|
resource: resource,
|
|
|
|
resource_id: resource_id
|
|
|
|
})
|
2022-09-20 07:44:06 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:user, user, type: :append_and_remove)
|
|
|
|
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|
2024-03-28 09:06:40 +13:00
|
|
|
|> Ash.create!(authorize?: false)
|
2022-05-18 07:56:40 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
defp create_file(org, name) do
|
|
|
|
File
|
2024-03-28 09:06:40 +13:00
|
|
|
|> Ash.Changeset.for_create(:create, %{name: name})
|
2022-09-20 07:44:06 +12:00
|
|
|
|> Ash.Changeset.manage_relationship(:organization, org, type: :append_and_remove)
|
2024-03-28 09:06:40 +13:00
|
|
|
|> Ash.create!(authorize?: false)
|
2022-05-18 07:56:40 +12:00
|
|
|
end
|
|
|
|
end
|