Both permission sets allow User:update :own, so users should be able to access their profile page. This makes the implementation consistent with the documentation and the logical permission model.
570 lines
19 KiB
Elixir
570 lines
19 KiB
Elixir
defmodule Mv.Authorization.PermissionSetsTest do
|
|
@moduledoc """
|
|
Tests for the PermissionSets module that defines hardcoded permission sets.
|
|
"""
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Mv.Authorization.PermissionSets
|
|
|
|
describe "all_permission_sets/0" do
|
|
test "returns all four permission sets" do
|
|
sets = PermissionSets.all_permission_sets()
|
|
|
|
assert length(sets) == 4
|
|
assert :own_data in sets
|
|
assert :read_only in sets
|
|
assert :normal_user in sets
|
|
assert :admin in sets
|
|
end
|
|
end
|
|
|
|
describe "get_permissions/1" do
|
|
test "returns map with :resources and :pages keys for :own_data" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
assert Map.has_key?(permissions, :resources)
|
|
assert Map.has_key?(permissions, :pages)
|
|
assert is_list(permissions.resources)
|
|
assert is_list(permissions.pages)
|
|
end
|
|
|
|
test "returns map with :resources and :pages keys for :read_only" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
assert Map.has_key?(permissions, :resources)
|
|
assert Map.has_key?(permissions, :pages)
|
|
assert is_list(permissions.resources)
|
|
assert is_list(permissions.pages)
|
|
end
|
|
|
|
test "returns map with :resources and :pages keys for :normal_user" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
assert Map.has_key?(permissions, :resources)
|
|
assert Map.has_key?(permissions, :pages)
|
|
assert is_list(permissions.resources)
|
|
assert is_list(permissions.pages)
|
|
end
|
|
|
|
test "returns map with :resources and :pages keys for :admin" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
assert Map.has_key?(permissions, :resources)
|
|
assert Map.has_key?(permissions, :pages)
|
|
assert is_list(permissions.resources)
|
|
assert is_list(permissions.pages)
|
|
end
|
|
|
|
test "each resource permission has required keys" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
Enum.each(permissions.resources, fn perm ->
|
|
assert Map.has_key?(perm, :resource)
|
|
assert Map.has_key?(perm, :action)
|
|
assert Map.has_key?(perm, :scope)
|
|
assert Map.has_key?(perm, :granted)
|
|
assert is_binary(perm.resource)
|
|
assert perm.action in [:read, :create, :update, :destroy]
|
|
assert perm.scope in [:own, :linked, :all]
|
|
assert is_boolean(perm.granted)
|
|
end)
|
|
end
|
|
|
|
test "pages lists are non-empty for all permission sets" do
|
|
for set <- [:own_data, :read_only, :normal_user, :admin] do
|
|
permissions = PermissionSets.get_permissions(set)
|
|
|
|
assert not Enum.empty?(permissions.pages),
|
|
"Permission set #{set} should have at least one page"
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "get_permissions/1 - :own_data permission content" do
|
|
test "allows User read/update with scope :own" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
user_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :read end)
|
|
|
|
user_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :update end)
|
|
|
|
assert user_read.scope == :own
|
|
assert user_read.granted == true
|
|
assert user_update.scope == :own
|
|
assert user_update.granted == true
|
|
end
|
|
|
|
test "allows Member read/update with scope :linked" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
member_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :read end)
|
|
|
|
member_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :update end)
|
|
|
|
assert member_read.scope == :linked
|
|
assert member_read.granted == true
|
|
assert member_update.scope == :linked
|
|
assert member_update.granted == true
|
|
end
|
|
|
|
test "allows CustomFieldValue read/update with scope :linked" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
cfv_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :read
|
|
end)
|
|
|
|
cfv_update =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :update
|
|
end)
|
|
|
|
assert cfv_read.scope == :linked
|
|
assert cfv_read.granted == true
|
|
assert cfv_update.scope == :linked
|
|
assert cfv_update.granted == true
|
|
end
|
|
|
|
test "allows CustomField read with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
cf_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :read
|
|
end)
|
|
|
|
assert cf_read.scope == :all
|
|
assert cf_read.granted == true
|
|
end
|
|
|
|
test "includes correct pages" do
|
|
permissions = PermissionSets.get_permissions(:own_data)
|
|
|
|
assert "/" in permissions.pages
|
|
assert "/profile" in permissions.pages
|
|
assert "/members/:id" in permissions.pages
|
|
end
|
|
end
|
|
|
|
describe "get_permissions/1 - :read_only permission content" do
|
|
test "allows User read/update with scope :own" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
user_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :read end)
|
|
|
|
user_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :update end)
|
|
|
|
assert user_read.scope == :own
|
|
assert user_read.granted == true
|
|
assert user_update.scope == :own
|
|
assert user_update.granted == true
|
|
end
|
|
|
|
test "allows Member read with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
member_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :read end)
|
|
|
|
assert member_read.scope == :all
|
|
assert member_read.granted == true
|
|
end
|
|
|
|
test "does NOT allow Member create/update/destroy" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
member_create =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :create end)
|
|
|
|
member_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :update end)
|
|
|
|
member_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "Member" && p.action == :destroy
|
|
end)
|
|
|
|
assert member_create == nil || member_create.granted == false
|
|
assert member_update == nil || member_update.granted == false
|
|
assert member_destroy == nil || member_destroy.granted == false
|
|
end
|
|
|
|
test "allows CustomFieldValue read with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
cfv_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :read
|
|
end)
|
|
|
|
assert cfv_read.scope == :all
|
|
assert cfv_read.granted == true
|
|
end
|
|
|
|
test "does NOT allow CustomFieldValue create/update/destroy" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
cfv_create =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :create
|
|
end)
|
|
|
|
cfv_update =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :update
|
|
end)
|
|
|
|
cfv_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :destroy
|
|
end)
|
|
|
|
assert cfv_create == nil || cfv_create.granted == false
|
|
assert cfv_update == nil || cfv_update.granted == false
|
|
assert cfv_destroy == nil || cfv_destroy.granted == false
|
|
end
|
|
|
|
test "allows CustomField read with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
cf_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :read
|
|
end)
|
|
|
|
assert cf_read.scope == :all
|
|
assert cf_read.granted == true
|
|
end
|
|
|
|
test "includes correct pages" do
|
|
permissions = PermissionSets.get_permissions(:read_only)
|
|
|
|
assert "/" in permissions.pages
|
|
assert "/profile" in permissions.pages
|
|
assert "/members" in permissions.pages
|
|
assert "/members/:id" in permissions.pages
|
|
assert "/custom_field_values" in permissions.pages
|
|
end
|
|
end
|
|
|
|
describe "get_permissions/1 - :normal_user permission content" do
|
|
test "allows User read/update with scope :own" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
user_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :read end)
|
|
|
|
user_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :update end)
|
|
|
|
assert user_read.scope == :own
|
|
assert user_read.granted == true
|
|
assert user_update.scope == :own
|
|
assert user_update.granted == true
|
|
end
|
|
|
|
test "allows Member read/create/update with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
member_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :read end)
|
|
|
|
member_create =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :create end)
|
|
|
|
member_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :update end)
|
|
|
|
assert member_read.scope == :all
|
|
assert member_read.granted == true
|
|
assert member_create.scope == :all
|
|
assert member_create.granted == true
|
|
assert member_update.scope == :all
|
|
assert member_update.granted == true
|
|
end
|
|
|
|
test "does NOT allow Member destroy (safety)" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
member_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "Member" && p.action == :destroy
|
|
end)
|
|
|
|
assert member_destroy == nil || member_destroy.granted == false
|
|
end
|
|
|
|
test "allows CustomFieldValue full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
cfv_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :read
|
|
end)
|
|
|
|
cfv_create =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :create
|
|
end)
|
|
|
|
cfv_update =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :update
|
|
end)
|
|
|
|
cfv_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :destroy
|
|
end)
|
|
|
|
assert cfv_read.scope == :all
|
|
assert cfv_read.granted == true
|
|
assert cfv_create.scope == :all
|
|
assert cfv_create.granted == true
|
|
assert cfv_update.scope == :all
|
|
assert cfv_update.granted == true
|
|
assert cfv_destroy.scope == :all
|
|
assert cfv_destroy.granted == true
|
|
end
|
|
|
|
test "allows CustomField read with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
cf_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :read
|
|
end)
|
|
|
|
assert cf_read.scope == :all
|
|
assert cf_read.granted == true
|
|
end
|
|
|
|
test "includes correct pages" do
|
|
permissions = PermissionSets.get_permissions(:normal_user)
|
|
|
|
assert "/" in permissions.pages
|
|
assert "/profile" in permissions.pages
|
|
assert "/members" in permissions.pages
|
|
assert "/members/new" in permissions.pages
|
|
assert "/members/:id" in permissions.pages
|
|
assert "/members/:id/edit" in permissions.pages
|
|
assert "/custom_field_values" in permissions.pages
|
|
assert "/custom_field_values/new" in permissions.pages
|
|
assert "/custom_field_values/:id/edit" in permissions.pages
|
|
end
|
|
end
|
|
|
|
describe "get_permissions/1 - :admin permission content" do
|
|
test "allows User full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
user_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :read end)
|
|
|
|
user_create =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :create end)
|
|
|
|
user_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :update end)
|
|
|
|
user_destroy =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "User" && p.action == :destroy end)
|
|
|
|
assert user_read.scope == :all
|
|
assert user_read.granted == true
|
|
assert user_create.scope == :all
|
|
assert user_create.granted == true
|
|
assert user_update.scope == :all
|
|
assert user_update.granted == true
|
|
assert user_destroy.scope == :all
|
|
assert user_destroy.granted == true
|
|
end
|
|
|
|
test "allows Member full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
member_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :read end)
|
|
|
|
member_create =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :create end)
|
|
|
|
member_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Member" && p.action == :update end)
|
|
|
|
member_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "Member" && p.action == :destroy
|
|
end)
|
|
|
|
assert member_read.scope == :all
|
|
assert member_read.granted == true
|
|
assert member_create.scope == :all
|
|
assert member_create.granted == true
|
|
assert member_update.scope == :all
|
|
assert member_update.granted == true
|
|
assert member_destroy.scope == :all
|
|
assert member_destroy.granted == true
|
|
end
|
|
|
|
test "allows CustomFieldValue full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
cfv_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :read
|
|
end)
|
|
|
|
cfv_create =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :create
|
|
end)
|
|
|
|
cfv_update =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :update
|
|
end)
|
|
|
|
cfv_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomFieldValue" && p.action == :destroy
|
|
end)
|
|
|
|
assert cfv_read.scope == :all
|
|
assert cfv_read.granted == true
|
|
assert cfv_create.scope == :all
|
|
assert cfv_create.granted == true
|
|
assert cfv_update.scope == :all
|
|
assert cfv_update.granted == true
|
|
assert cfv_destroy.scope == :all
|
|
assert cfv_destroy.granted == true
|
|
end
|
|
|
|
test "allows CustomField full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
cf_read =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :read
|
|
end)
|
|
|
|
cf_create =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :create
|
|
end)
|
|
|
|
cf_update =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :update
|
|
end)
|
|
|
|
cf_destroy =
|
|
Enum.find(permissions.resources, fn p ->
|
|
p.resource == "CustomField" && p.action == :destroy
|
|
end)
|
|
|
|
assert cf_read.scope == :all
|
|
assert cf_read.granted == true
|
|
assert cf_create.scope == :all
|
|
assert cf_create.granted == true
|
|
assert cf_update.scope == :all
|
|
assert cf_update.granted == true
|
|
assert cf_destroy.scope == :all
|
|
assert cf_destroy.granted == true
|
|
end
|
|
|
|
test "allows Role full CRUD with scope :all" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
role_read =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Role" && p.action == :read end)
|
|
|
|
role_create =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Role" && p.action == :create end)
|
|
|
|
role_update =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Role" && p.action == :update end)
|
|
|
|
role_destroy =
|
|
Enum.find(permissions.resources, fn p -> p.resource == "Role" && p.action == :destroy end)
|
|
|
|
assert role_read.scope == :all
|
|
assert role_read.granted == true
|
|
assert role_create.scope == :all
|
|
assert role_create.granted == true
|
|
assert role_update.scope == :all
|
|
assert role_update.granted == true
|
|
assert role_destroy.scope == :all
|
|
assert role_destroy.granted == true
|
|
end
|
|
|
|
test "has wildcard page permission" do
|
|
permissions = PermissionSets.get_permissions(:admin)
|
|
|
|
assert "*" in permissions.pages
|
|
end
|
|
end
|
|
|
|
describe "valid_permission_set?/1" do
|
|
test "returns true for valid permission set string" do
|
|
assert PermissionSets.valid_permission_set?("own_data") == true
|
|
assert PermissionSets.valid_permission_set?("read_only") == true
|
|
assert PermissionSets.valid_permission_set?("normal_user") == true
|
|
assert PermissionSets.valid_permission_set?("admin") == true
|
|
end
|
|
|
|
test "returns true for valid permission set atom" do
|
|
assert PermissionSets.valid_permission_set?(:own_data) == true
|
|
assert PermissionSets.valid_permission_set?(:read_only) == true
|
|
assert PermissionSets.valid_permission_set?(:normal_user) == true
|
|
assert PermissionSets.valid_permission_set?(:admin) == true
|
|
end
|
|
|
|
test "returns false for invalid permission set string" do
|
|
assert PermissionSets.valid_permission_set?("invalid") == false
|
|
assert PermissionSets.valid_permission_set?("") == false
|
|
assert PermissionSets.valid_permission_set?("admin_user") == false
|
|
end
|
|
|
|
test "returns false for invalid permission set atom" do
|
|
assert PermissionSets.valid_permission_set?(:invalid) == false
|
|
assert PermissionSets.valid_permission_set?(:unknown) == false
|
|
end
|
|
|
|
test "returns false for nil input" do
|
|
assert PermissionSets.valid_permission_set?(nil) == false
|
|
end
|
|
end
|
|
|
|
describe "permission_set_name_to_atom/1" do
|
|
test "returns {:ok, atom} for valid permission set name" do
|
|
assert PermissionSets.permission_set_name_to_atom("own_data") == {:ok, :own_data}
|
|
assert PermissionSets.permission_set_name_to_atom("read_only") == {:ok, :read_only}
|
|
assert PermissionSets.permission_set_name_to_atom("normal_user") == {:ok, :normal_user}
|
|
assert PermissionSets.permission_set_name_to_atom("admin") == {:ok, :admin}
|
|
end
|
|
|
|
test "returns {:error, :invalid_permission_set} for invalid permission set name" do
|
|
assert PermissionSets.permission_set_name_to_atom("invalid") ==
|
|
{:error, :invalid_permission_set}
|
|
|
|
assert PermissionSets.permission_set_name_to_atom("") == {:error, :invalid_permission_set}
|
|
|
|
assert PermissionSets.permission_set_name_to_atom("admin_user") ==
|
|
{:error, :invalid_permission_set}
|
|
end
|
|
|
|
test "handles non-existent atom gracefully" do
|
|
# String.to_existing_atom will raise ArgumentError for non-existent atoms
|
|
assert PermissionSets.permission_set_name_to_atom("nonexistent_atom_12345") ==
|
|
{:error, :invalid_permission_set}
|
|
end
|
|
end
|
|
end
|