From 3aef154c007f5ae35680022d44e4b45f062c009d Mon Sep 17 00:00:00 2001 From: William Michaels Date: Tue, 5 Apr 2022 16:41:44 -0500 Subject: [PATCH 1/3] wip: POC built in helper processing --- c_src/casbin_nif.cpp | 2 +- config/test.exs | 4 +- lib/casbinex.ex | 92 ++++++++++++++++++++++++++---------------- lib/casbinex/base.ex | 73 +++++++++++++++++++++++++++++++++ test/casbinex_test.exs | 92 ++++++++++++++++++++++++------------------ 5 files changed, 187 insertions(+), 76 deletions(-) create mode 100644 lib/casbinex/base.ex diff --git a/c_src/casbin_nif.cpp b/c_src/casbin_nif.cpp index 2c74748..fdd7795 100644 --- a/c_src/casbin_nif.cpp +++ b/c_src/casbin_nif.cpp @@ -363,4 +363,4 @@ ErlNifFunc casbinex_nif_funcs[] = {"getFilteredPolicy", 2, GetFilteredPolicy}, }; -ERL_NIF_INIT(Elixir.Casbinex, casbinex_nif_funcs, 0, 0, 0, 0); +ERL_NIF_INIT(Elixir.Casbinex.Base, casbinex_nif_funcs, 0, 0, 0, 0); diff --git a/config/test.exs b/config/test.exs index f4f3249..e792f24 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,5 +1,5 @@ use Mix.Config config :casbinex, - model_path: 'test/data/rbac_model.conf', - pg_connection: 'test/data/rbac_policy.csv' #postgresql://:@/ + model_path: "test/data/rbac_model.conf", + pg_connection: "test/data/rbac_policy.csv" #postgresql://:@/ diff --git a/lib/casbinex.ex b/lib/casbinex.ex index eb6d20a..6888268 100644 --- a/lib/casbinex.ex +++ b/lib/casbinex.ex @@ -3,71 +3,95 @@ defmodule Casbinex do Documentation for `Casbinex`. """ - @on_load :load_nifs + alias Casbinex.Base - app = Mix.Project.config[:app] - def load_nifs do - path = :filename.join(:code.priv_dir(unquote(app)), 'casbinex_nif') - :ok = :erlang.load_nif(path, 0) + defp listToCharlists(list) do + list |> Enum.map(&to_charlist(&1)) end - def createEnforcer(_modelpath, _policypath) do - raise "NIF createEnforcerdd/2 not implemented" + defp listToStrings(list) do + list |> Enum.map(&List.to_string(&1)) + end + + defp listsToStrings(list) do + list |> Enum.map(&listToStrings(&1)) + end + + def createEnforcer(modelpath, policypath) do + Base.createEnforcer(String.to_charlist(modelpath), String.to_charlist(policypath)) end def destroyEnforcer() do - raise "NIF destroyEnforcer/0 not implemented" + Base.destroyEnforcer() + end + + def enforce(sub, obj, act) do + Base.enforce(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) + end + + def addPolicy(sub, obj, act) do + Base.addPolicy(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) + end + + def removePolicy(sub, obj, act) do + Base.removePolicy(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) end - def enforce(_sub, _obj, _act) do - raise "NIF enforce/3 not implemented" + def addGroupingPolicy(user, group) do + Base.addGroupingPolicy(String.to_charlist(user), String.to_charlist(group)) end - def addPolicy(_sub, _obj, _act) do - raise "NIF addPolicy/3 not implemented" + def getUsersForRole(role) do + case Base.getUsersForRole(String.to_charlist(role)) do + {:error, message} -> {:error, message} + list -> listToStrings(list) + end end - def removePolicy(_sub, _obj, _act) do - raise "NIF removePolicy/3 not implemented" + def getRolesForUser(user) do + Base.getRolesForUser(String.to_charlist(user)) + |> listToStrings end - def addGroupingPolicy(_user, _group) do - raise "NIF addGroupingPolicy/2 not implemented" + def deleteRole(role) do + Base.deleteRole(String.to_charlist(role)) end - def getUsersForRole(_role) do - raise "NIF getUsersForRole/1 not implemented" + def deleteRoleForUser(user, role) do + Base.deleteRoleForUser(String.to_charlist(user), String.to_charlist(role)) end - def getRolesForUser(_user) do - raise "NIF getRolesForUser/1 not implemented" + def deleteRolesForUser(user) do + Base.deleteRolesForUser(String.to_charlist(user)) end - def deleteRole(_role) do - raise "NIF deleteRole/1 not implemented" + def addRoleForUser(user, role) do + Base.addRoleForUser(String.to_charlist(user), String.to_charlist(role)) end - def deleteRoleForUser(_user, _role) do - raise "NIF deleteRoleForUser/2 not implemented" + def addRolesForUser(user, roles) when is_list(roles) do + Base.addRolesForUser(String.to_charlist(user), listToCharlists(roles)) end - def deleteRolesForUser(_user) do - raise "NIF deleteRolesForUser/1 not implemented" + def addRolesForUser(user, roles) do + Base.addRoleForUser(String.to_charlist(user), String.to_charlist(roles)) end - def addRoleForUser(_user, _role) do - raise "NIF addRoleForUser/2 not implemented" + def getFilteredPolicy(fieldindex, fields) when is_list(fields) do + Base.getFilteredPolicy(fieldindex, listToCharlists(fields)) + |> listsToStrings end - def addRolesForUser(_user, _role) do - raise "NIF addRolesForUser/2 not implemented" + def getFilteredPolicy(fieldindex, field) do + Base.getFilteredPolicy(fieldindex, [String.to_charlist(field)]) + |> listsToStrings end - def getFilteredPolicy(_field_index, _fields) do - raise "NIF getFilteredPolicy/2 not implemented" + def removeFilteredPolicy(fieldindex, fields) when is_list(fields) do + Base.removeFilteredPolicy(fieldindex, listToCharlists(fields)) end - def removeFilteredPolicy(_field_index, _fields) do - raise "NIF removeFilteredPolicy/2 not implemented" + def removeFilteredPolicy(fieldindex, field) do + Base.removeFilteredPolicy(fieldindex, [String.to_charlist(field)]) end end diff --git a/lib/casbinex/base.ex b/lib/casbinex/base.ex new file mode 100644 index 0000000..b51faba --- /dev/null +++ b/lib/casbinex/base.ex @@ -0,0 +1,73 @@ +defmodule Casbinex.Base do + @moduledoc """ + Documentation for `Casbinex`. + """ + + @on_load :load_nifs + + app = Mix.Project.config[:app] + def load_nifs do + path = :filename.join(:code.priv_dir(unquote(app)), 'casbinex_nif') + :ok = :erlang.load_nif(path, 0) + end + + def createEnforcer(_modelpath, _policypath) do + raise "NIF createEnforcerdd/2 not implemented" + end + + def destroyEnforcer() do + raise "NIF destroyEnforcer/0 not implemented" + end + + def enforce(_sub, _obj, _act) do + raise "NIF enforce/3 not implemented" + end + + def addPolicy(_sub, _obj, _act) do + raise "NIF addPolicy/3 not implemented" + end + + def removePolicy(_sub, _obj, _act) do + raise "NIF removePolicy/3 not implemented" + end + + def addGroupingPolicy(_user, _group) do + raise "NIF addGroupingPolicy/2 not implemented" + end + + def getUsersForRole(_role) do + raise "NIF getUsersForRole/1 not implemented" + end + + def getRolesForUser(_user) do + raise "NIF getRolesForUser/1 not implemented" + end + + def deleteRole(_role) do + raise "NIF deleteRole/1 not implemented" + end + + def deleteRoleForUser(_user, _role) do + raise "NIF deleteRoleForUser/2 not implemented" + end + + def deleteRolesForUser(_user) do + raise "NIF deleteRolesForUser/1 not implemented" + end + + def addRoleForUser(_user, _role) do + raise "NIF addRoleForUser/2 not implemented" + end + + def addRolesForUser(_user, _role) do + raise "NIF addRolesForUser/2 not implemented" + end + + def getFilteredPolicy(_field_index, _fields) do + raise "NIF getFilteredPolicy/2 not implemented" + end + + def removeFilteredPolicy(_field_index, _fields) do + raise "NIF removeFilteredPolicy/2 not implemented" + end +end diff --git a/test/casbinex_test.exs b/test/casbinex_test.exs index 8e2d3d0..e3d7bb9 100644 --- a/test/casbinex_test.exs +++ b/test/casbinex_test.exs @@ -9,8 +9,8 @@ defmodule CasbinexTest do test "enforces user policies correctly" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.enforce('alice', 'data1', 'read') - assert :false == Casbinex.enforce('attacker', 'data1', 'read') + assert :true == Casbinex.enforce("alice", "data1", "read") + assert :false == Casbinex.enforce("attacker", "data1", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -19,8 +19,8 @@ defmodule CasbinexTest do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) # alice is in the data2_admin group - assert :true == Casbinex.enforce('alice', 'data2', 'write') - assert :false == Casbinex.enforce('attacker', 'data2', 'read') + assert :true == Casbinex.enforce("alice", "data2", "write") + assert :false == Casbinex.enforce("attacker", "data2", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -29,15 +29,15 @@ defmodule CasbinexTest do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) # alice is in the data2_admin group - assert ['alice'] == Casbinex.getUsersForRole('data2_admin') + assert ["alice"] == Casbinex.getUsersForRole("data2_admin") #add bob to the group - assert :true == Casbinex.addGroupingPolicy('bob', 'data2_admin') - assert ['bob', 'alice'] == Casbinex.getUsersForRole('data2_admin') + assert :true == Casbinex.addGroupingPolicy("bob", "data2_admin") + assert ["bob", "alice"] == Casbinex.getUsersForRole("data2_admin") #delete the group - assert :true == Casbinex.deleteRole('data2_admin') - assert {:error, _} = Casbinex.getUsersForRole('data2_admin') + assert :true == Casbinex.deleteRole("data2_admin") + assert {:error, _} = Casbinex.getUsersForRole("data2_admin") assert :ok == Casbinex.destroyEnforcer(); end @@ -45,7 +45,7 @@ defmodule CasbinexTest do test "get a list of roles for the user" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert ['data2_admin'] == Casbinex.getRolesForUser('alice') + assert ["data2_admin"] == Casbinex.getRolesForUser("alice") assert :ok == Casbinex.destroyEnforcer(); end @@ -53,9 +53,9 @@ defmodule CasbinexTest do test "can add new policies" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.addPolicy('bill', 'data1', 'read') - assert :true == Casbinex.enforce('bill', 'data1', 'read') - assert :false == Casbinex.enforce('bill', 'data1', 'write') + assert :true == Casbinex.addPolicy("bill", "data1", "read") + assert :true == Casbinex.enforce("bill", "data1", "read") + assert :false == Casbinex.enforce("bill", "data1", "write") assert :ok == Casbinex.destroyEnforcer(); end @@ -63,9 +63,9 @@ defmodule CasbinexTest do test "can remove policies" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.enforce('alice', 'data1', 'read') - assert :true == Casbinex.removePolicy('alice', 'data1', 'read') - assert :false == Casbinex.enforce('alice', 'data1', 'read') + assert :true == Casbinex.enforce("alice", "data1", "read") + assert :true == Casbinex.removePolicy("alice", "data1", "read") + assert :false == Casbinex.enforce("alice", "data1", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -73,9 +73,9 @@ defmodule CasbinexTest do test "can remove user from all groups" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.enforce('alice', 'data2', 'read') - assert :true == Casbinex.deleteRolesForUser('alice') - assert :false == Casbinex.enforce('alice', 'data2', 'read') + assert :true == Casbinex.enforce("alice", "data2", "read") + assert :true == Casbinex.deleteRolesForUser("alice") + assert :false == Casbinex.enforce("alice", "data2", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -83,9 +83,9 @@ defmodule CasbinexTest do test "can remove role for user" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.enforce('alice', 'data2', 'read') - assert :true == Casbinex.deleteRoleForUser('alice', 'data2_admin') - assert :false == Casbinex.enforce('alice', 'data2', 'read') + assert :true == Casbinex.enforce("alice", "data2", "read") + assert :true == Casbinex.deleteRoleForUser("alice", "data2_admin") + assert :false == Casbinex.enforce("alice", "data2", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -93,11 +93,11 @@ defmodule CasbinexTest do test "can add user to role" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert :true == Casbinex.enforce('alice', 'data2', 'read') - assert :true == Casbinex.deleteRoleForUser('alice', 'data2_admin') - assert :false == Casbinex.enforce('alice', 'data2', 'read') - assert :true == Casbinex.addRoleForUser('alice', 'data2_admin') - assert :true == Casbinex.enforce('alice', 'data2', 'read') + assert :true == Casbinex.enforce("alice", "data2", "read") + assert :true == Casbinex.deleteRoleForUser("alice", "data2_admin") + assert :false == Casbinex.enforce("alice", "data2", "read") + assert :true == Casbinex.addRoleForUser("alice", "data2_admin") + assert :true == Casbinex.enforce("alice", "data2", "read") assert :ok == Casbinex.destroyEnforcer(); end @@ -105,12 +105,12 @@ defmodule CasbinexTest do test "can add user to multiple roles" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - Casbinex.addPolicy('data1_admin', 'data1', 'write') + Casbinex.addPolicy("data1_admin", "data1", "write") - assert :false == Casbinex.enforce('alice', 'data1', 'write') - assert :true == Casbinex.addRolesForUser('alice', ['data1_admin', 'data2_admin']) - assert :true == Casbinex.enforce('alice', 'data2', 'write') - assert :true == Casbinex.enforce('alice', 'data1', 'write') + assert :false == Casbinex.enforce("alice", "data1", "write") + assert :true == Casbinex.addRolesForUser("alice", ["data1_admin", "data2_admin"]) + assert :true == Casbinex.enforce("alice", "data2", "write") + assert :true == Casbinex.enforce("alice", "data1", "write") assert :ok == Casbinex.destroyEnforcer(); end @@ -119,8 +119,8 @@ defmodule CasbinexTest do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) assert [ - ['bob', 'data2', 'write'], - ['data2_admin', 'data2', 'write']] = Casbinex.getFilteredPolicy(1, ['data2', 'write']) + ["bob", "data2", "write"], + ["data2_admin", "data2", "write"]] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) assert :ok == Casbinex.destroyEnforcer(); end @@ -129,12 +129,26 @@ defmodule CasbinexTest do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) assert [ - ['bob', 'data2', 'write'], - ['data2_admin', 'data2', 'write'] - ] = Casbinex.getFilteredPolicy(1, ['data2', 'write']) + ["bob", "data2", "write"], + ["data2_admin", "data2", "write"] + ] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) - Casbinex.removeFilteredPolicy(1, ['data2', 'write']) - assert [] = Casbinex.getFilteredPolicy(1, ['data2', 'write']) + Casbinex.removeFilteredPolicy(1, ["data2", "write"]) + assert [] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) + + assert :ok == Casbinex.destroyEnforcer(); + end + + test "removes a filtered list of policies when policy selector is charlist" do + assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) + + assert [ + ["bob", "data2", "write"], + ["data2_admin", "data2", "read"], + ["data2_admin", "data2", "write"]] = Casbinex.getFilteredPolicy(1, "data2") + + Casbinex.removeFilteredPolicy(1, "data2") + assert [] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) assert :ok == Casbinex.destroyEnforcer(); end From 1a15840befee494db0cb6b52e91d2b6096531cd6 Mon Sep 17 00:00:00 2001 From: William Michaels Date: Wed, 6 Apr 2022 10:54:14 -0500 Subject: [PATCH 2/3] feat: add more error handling. fix typo --- c_src/casbin_nif.cpp | 38 +++++++++++++++++++--------------- lib/casbinex.ex | 49 +++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/c_src/casbin_nif.cpp b/c_src/casbin_nif.cpp index fdd7795..411d1b5 100644 --- a/c_src/casbin_nif.cpp +++ b/c_src/casbin_nif.cpp @@ -110,7 +110,7 @@ ERL_NIF_TERM DestroyEnforcer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM Enforce(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string sub = ListToString(env, argv[0]); @@ -128,7 +128,7 @@ ERL_NIF_TERM Enforce(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM AddPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string sub = ListToString(env, argv[0]); @@ -147,7 +147,7 @@ ERL_NIF_TERM AddPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM RemovePolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string sub = ListToString(env, argv[0]); @@ -166,7 +166,7 @@ ERL_NIF_TERM RemovePolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM AddGroupingPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -184,7 +184,7 @@ ERL_NIF_TERM AddGroupingPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ERL_NIF_TERM GetUsersForRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string role = ListToString(env, argv[0]); @@ -199,7 +199,7 @@ ERL_NIF_TERM GetUsersForRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM GetRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -212,7 +212,7 @@ ERL_NIF_TERM GetRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM DeleteRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string role = ListToString(env, argv[0]); @@ -230,7 +230,7 @@ ERL_NIF_TERM DeleteRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM AddRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -249,7 +249,7 @@ ERL_NIF_TERM AddRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) ERL_NIF_TERM AddRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -268,7 +268,7 @@ ERL_NIF_TERM AddRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] ERL_NIF_TERM DeleteRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -287,7 +287,7 @@ ERL_NIF_TERM DeleteRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg ERL_NIF_TERM DeleteRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } string user = ListToString(env, argv[0]); @@ -306,7 +306,7 @@ ERL_NIF_TERM DeleteRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv ERL_NIF_TERM RemoveFilteredPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } int fieldIndex = 0; @@ -320,15 +320,17 @@ ERL_NIF_TERM RemoveFilteredPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM a return enforcer->RemoveFilteredPolicy(fieldIndex, resourceId) ?PF_ATOM_TRUE :PF_ATOM_FALSE; - } catch(...) { - return PF_ATOM_FALSE; + } catch(const casbin::CasbinRBACException &e) { + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("RBAC exception")); + } catch(std::exception e2) { + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING(e2.what())); } } ERL_NIF_TERM GetFilteredPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { if(!enforcer) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create and enforcer first.")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } int fieldIndex = 0; @@ -339,8 +341,10 @@ ERL_NIF_TERM GetFilteredPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv try{ return VectorToList(env, enforcer->GetFilteredPolicy(fieldIndex, resourceId)); - } catch(...) { - return PF_ATOM_FALSE; + } catch(const casbin::CasbinRBACException &e) { + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("RBAC exception")); + } catch(std::exception e2) { + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING(e2.what())); } } diff --git a/lib/casbinex.ex b/lib/casbinex.ex index 6888268..790e672 100644 --- a/lib/casbinex.ex +++ b/lib/casbinex.ex @@ -5,18 +5,6 @@ defmodule Casbinex do alias Casbinex.Base - defp listToCharlists(list) do - list |> Enum.map(&to_charlist(&1)) - end - - defp listToStrings(list) do - list |> Enum.map(&List.to_string(&1)) - end - - defp listsToStrings(list) do - list |> Enum.map(&listToStrings(&1)) - end - def createEnforcer(modelpath, policypath) do Base.createEnforcer(String.to_charlist(modelpath), String.to_charlist(policypath)) end @@ -44,13 +32,15 @@ defmodule Casbinex do def getUsersForRole(role) do case Base.getUsersForRole(String.to_charlist(role)) do {:error, message} -> {:error, message} - list -> listToStrings(list) + list -> list_to_strings(list) end end def getRolesForUser(user) do - Base.getRolesForUser(String.to_charlist(user)) - |> listToStrings + case Base.getRolesForUser(String.to_charlist(user)) do + {:error, message} -> {:error, message} + list -> list_to_strings(list) + end end def deleteRole(role) do @@ -70,7 +60,7 @@ defmodule Casbinex do end def addRolesForUser(user, roles) when is_list(roles) do - Base.addRolesForUser(String.to_charlist(user), listToCharlists(roles)) + Base.addRolesForUser(String.to_charlist(user), list_to_charlists(roles)) end def addRolesForUser(user, roles) do @@ -78,20 +68,37 @@ defmodule Casbinex do end def getFilteredPolicy(fieldindex, fields) when is_list(fields) do - Base.getFilteredPolicy(fieldindex, listToCharlists(fields)) - |> listsToStrings + case Base.getFilteredPolicy(fieldindex, list_to_charlists(fields)) do + {:error, message} -> {:error, message} + list -> map_to_stringlists(list) + end end def getFilteredPolicy(fieldindex, field) do - Base.getFilteredPolicy(fieldindex, [String.to_charlist(field)]) - |> listsToStrings + case Base.getFilteredPolicy(fieldindex, [String.to_charlist(field)]) do + {:error, message} -> {:error, message} + list -> map_to_stringlists(list) + end end def removeFilteredPolicy(fieldindex, fields) when is_list(fields) do - Base.removeFilteredPolicy(fieldindex, listToCharlists(fields)) + Base.removeFilteredPolicy(fieldindex, list_to_charlists(fields)) end def removeFilteredPolicy(fieldindex, field) do Base.removeFilteredPolicy(fieldindex, [String.to_charlist(field)]) end + + # Utility functions for converting lists of strings to charlists + defp list_to_charlists(list) do + list |> Enum.map(&to_charlist(&1)) + end + + defp list_to_strings(list) do + list |> Enum.map(&List.to_string(&1)) + end + + defp map_to_stringlists(list) do + list |> Enum.map(&list_to_strings(&1)) + end end From 46111c93a0467ab6499e6438fa3f3e5a97e36a7a Mon Sep 17 00:00:00 2001 From: William Michaels Date: Wed, 6 Apr 2022 12:19:02 -0500 Subject: [PATCH 3/3] feat: simplified the code further and return ok tuples --- c_src/casbin_nif.cpp | 82 +++++++++++++++++++++++++++--------------- lib/casbinex.ex | 59 +++++++++--------------------- test/casbinex_test.exs | 22 ++++++------ 3 files changed, 81 insertions(+), 82 deletions(-) diff --git a/c_src/casbin_nif.cpp b/c_src/casbin_nif.cpp index 411d1b5..92ab3d7 100644 --- a/c_src/casbin_nif.cpp +++ b/c_src/casbin_nif.cpp @@ -33,11 +33,32 @@ string ListToString(ErlNifEnv* env, ERL_NIF_TERM term) { return string(stringData, res); } +string BinToString(ErlNifEnv* env, ERL_NIF_TERM term) { + ERL_NIF_TERM maybeBin = term; + + unsigned int listLength = 0; + ErlNifBinary term_bin; + if (!enif_inspect_iolist_as_binary(env, term, &term_bin)) + { + // we blame the user if address isn't a string + return string(); + } + + return string(reinterpret_cast(term_bin.data), term_bin.size); +} + ERL_NIF_TERM VectorToList(ErlNifEnv* env, const vector &input) { ERL_NIF_TERM enifList[input.size()]; for(int ii = 0; ii < input.size(); ++ii) { - enifList[ii] = enif_make_string(env, input.at(ii).c_str(), ERL_NIF_LATIN1); + ERL_NIF_TERM component_term; + + const char* inputCharArray = (const char*)input.at(ii).c_str(); + const int inputLength = strlen(inputCharArray); + char *component_term_bin = reinterpret_cast(enif_make_new_binary(env, inputLength, &component_term)); + strncpy(component_term_bin, inputCharArray, inputLength); + + enifList[ii] = component_term; } return enif_make_list_from_array(env, enifList, input.size()); @@ -65,14 +86,14 @@ vector ListToVector(ErlNifEnv* env, ERL_NIF_TERM term) { items = term; while(enif_get_list_cell(env, items, &item, &items)) - resultVector.push_back(ListToString(env, item)); + resultVector.push_back(BinToString(env, item)); return resultVector; } ERL_NIF_TERM CreateEnforcer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - string modelPath = ListToString(env, argv[0]); - string policyPath = ListToString(env, argv[1]); + string modelPath = BinToString(env, argv[0]); + string policyPath = BinToString(env, argv[1]); try{ @@ -113,9 +134,9 @@ ERL_NIF_TERM Enforce(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string sub = ListToString(env, argv[0]); - string obj = ListToString(env, argv[1]); - string act = ListToString(env, argv[2]); + string sub = BinToString(env, argv[0]); + string obj = BinToString(env, argv[1]); + string act = BinToString(env, argv[2]); try{ return enforcer->Enforce({sub.c_str(), obj.c_str(), act.c_str()}) @@ -131,9 +152,9 @@ ERL_NIF_TERM AddPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string sub = ListToString(env, argv[0]); - string obj = ListToString(env, argv[1]); - string act = ListToString(env, argv[2]); + string sub = BinToString(env, argv[0]); + string obj = BinToString(env, argv[1]); + string act = BinToString(env, argv[2]); try{ enforcer->InvalidateCache(); @@ -150,9 +171,9 @@ ERL_NIF_TERM RemovePolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string sub = ListToString(env, argv[0]); - string obj = ListToString(env, argv[1]); - string act = ListToString(env, argv[2]); + string sub = BinToString(env, argv[0]); + string obj = BinToString(env, argv[1]); + string act = BinToString(env, argv[2]); try{ enforcer->InvalidateCache(); @@ -169,8 +190,8 @@ ERL_NIF_TERM AddGroupingPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); - string group = ListToString(env, argv[1]); + string user = BinToString(env, argv[0]); + string group = BinToString(env, argv[1]); try{ enforcer->InvalidateCache(); @@ -187,9 +208,10 @@ ERL_NIF_TERM GetUsersForRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string role = ListToString(env, argv[0]); + string role = BinToString(env, argv[0]); try{ - return VectorToList(env, enforcer->GetUsersForRole(role)); + ERL_NIF_TERM list = VectorToList(env, enforcer->GetUsersForRole(role)); + return make_result_tuple( PF_ATOM_OK, list ); } catch(const casbin::CasbinRBACException &e) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("RBAC exception")); } catch(...) { @@ -202,9 +224,10 @@ ERL_NIF_TERM GetRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); + string user = BinToString(env, argv[0]); try{ - return VectorToList(env, enforcer->GetRolesForUser(user)); + ERL_NIF_TERM list = VectorToList(env, enforcer->GetRolesForUser(user)); + return make_result_tuple( PF_ATOM_OK, list ); } catch(...) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Unexpected exception")); } @@ -215,7 +238,7 @@ ERL_NIF_TERM DeleteRole(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string role = ListToString(env, argv[0]); + string role = BinToString(env, argv[0]); try{ enforcer->InvalidateCache(); return enforcer->DeleteRole({role}) @@ -233,8 +256,8 @@ ERL_NIF_TERM AddRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); - string role = ListToString(env, argv[1]); + string user = BinToString(env, argv[0]); + string role = BinToString(env, argv[1]); try{ enforcer->InvalidateCache(); return enforcer->AddRoleForUser(user, role) @@ -252,7 +275,7 @@ ERL_NIF_TERM AddRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); + string user = BinToString(env, argv[0]); vector roles = ListToVector(env, argv[1]); try{ enforcer->InvalidateCache(); @@ -271,7 +294,7 @@ ERL_NIF_TERM DeleteRolesForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); + string user = BinToString(env, argv[0]); try{ enforcer->InvalidateCache(); return enforcer->DeleteRolesForUser(user) @@ -290,8 +313,8 @@ ERL_NIF_TERM DeleteRoleForUser(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("Must create an enforcer first.")); } - string user = ListToString(env, argv[0]); - string role = ListToString(env, argv[1]); + string user = BinToString(env, argv[0]); + string role = BinToString(env, argv[1]); try{ enforcer->InvalidateCache(); return enforcer->DeleteRoleForUser(user, role) @@ -340,11 +363,12 @@ ERL_NIF_TERM GetFilteredPolicy(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv vector resourceId = ListToVector(env, argv[1]); try{ - return VectorToList(env, enforcer->GetFilteredPolicy(fieldIndex, resourceId)); + ERL_NIF_TERM list = VectorToList(env, enforcer->GetFilteredPolicy(fieldIndex, resourceId)); + return make_result_tuple( PF_ATOM_OK, list ); } catch(const casbin::CasbinRBACException &e) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("RBAC exception")); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING("RBAC exception") ); } catch(std::exception e2) { - return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING(e2.what())); + return make_result_tuple( PF_ATOM_ERROR, PF_MAKE_STRING(e2.what()) ); } } diff --git a/lib/casbinex.ex b/lib/casbinex.ex index 790e672..cf3f72c 100644 --- a/lib/casbinex.ex +++ b/lib/casbinex.ex @@ -6,7 +6,7 @@ defmodule Casbinex do alias Casbinex.Base def createEnforcer(modelpath, policypath) do - Base.createEnforcer(String.to_charlist(modelpath), String.to_charlist(policypath)) + Base.createEnforcer(modelpath, policypath) end def destroyEnforcer() do @@ -14,91 +14,66 @@ defmodule Casbinex do end def enforce(sub, obj, act) do - Base.enforce(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) + Base.enforce(sub, obj, act) end def addPolicy(sub, obj, act) do - Base.addPolicy(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) + Base.addPolicy(sub, obj, act) end def removePolicy(sub, obj, act) do - Base.removePolicy(String.to_charlist(sub), String.to_charlist(obj), String.to_charlist(act)) + Base.removePolicy(sub, obj, act) end def addGroupingPolicy(user, group) do - Base.addGroupingPolicy(String.to_charlist(user), String.to_charlist(group)) + Base.addGroupingPolicy(user, group) end def getUsersForRole(role) do - case Base.getUsersForRole(String.to_charlist(role)) do - {:error, message} -> {:error, message} - list -> list_to_strings(list) - end + Base.getUsersForRole(role) end def getRolesForUser(user) do - case Base.getRolesForUser(String.to_charlist(user)) do - {:error, message} -> {:error, message} - list -> list_to_strings(list) - end + Base.getRolesForUser(user) end def deleteRole(role) do - Base.deleteRole(String.to_charlist(role)) + Base.deleteRole(role) end def deleteRoleForUser(user, role) do - Base.deleteRoleForUser(String.to_charlist(user), String.to_charlist(role)) + Base.deleteRoleForUser(user, role) end def deleteRolesForUser(user) do - Base.deleteRolesForUser(String.to_charlist(user)) + Base.deleteRolesForUser(user) end def addRoleForUser(user, role) do - Base.addRoleForUser(String.to_charlist(user), String.to_charlist(role)) + Base.addRoleForUser(user, role) end def addRolesForUser(user, roles) when is_list(roles) do - Base.addRolesForUser(String.to_charlist(user), list_to_charlists(roles)) + Base.addRolesForUser(user, roles) end def addRolesForUser(user, roles) do - Base.addRoleForUser(String.to_charlist(user), String.to_charlist(roles)) + Base.addRoleForUser(user, roles) end def getFilteredPolicy(fieldindex, fields) when is_list(fields) do - case Base.getFilteredPolicy(fieldindex, list_to_charlists(fields)) do - {:error, message} -> {:error, message} - list -> map_to_stringlists(list) - end + Base.getFilteredPolicy(fieldindex, fields) end def getFilteredPolicy(fieldindex, field) do - case Base.getFilteredPolicy(fieldindex, [String.to_charlist(field)]) do - {:error, message} -> {:error, message} - list -> map_to_stringlists(list) - end + Base.getFilteredPolicy(fieldindex, [field]) end def removeFilteredPolicy(fieldindex, fields) when is_list(fields) do - Base.removeFilteredPolicy(fieldindex, list_to_charlists(fields)) + Base.removeFilteredPolicy(fieldindex, fields) end def removeFilteredPolicy(fieldindex, field) do - Base.removeFilteredPolicy(fieldindex, [String.to_charlist(field)]) - end - - # Utility functions for converting lists of strings to charlists - defp list_to_charlists(list) do - list |> Enum.map(&to_charlist(&1)) - end - - defp list_to_strings(list) do - list |> Enum.map(&List.to_string(&1)) - end - - defp map_to_stringlists(list) do - list |> Enum.map(&list_to_strings(&1)) + Base.removeFilteredPolicy(fieldindex, [field]) end end diff --git a/test/casbinex_test.exs b/test/casbinex_test.exs index e3d7bb9..d40bacf 100644 --- a/test/casbinex_test.exs +++ b/test/casbinex_test.exs @@ -29,11 +29,11 @@ defmodule CasbinexTest do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) # alice is in the data2_admin group - assert ["alice"] == Casbinex.getUsersForRole("data2_admin") + assert { :ok, ["alice"] } == Casbinex.getUsersForRole("data2_admin") #add bob to the group assert :true == Casbinex.addGroupingPolicy("bob", "data2_admin") - assert ["bob", "alice"] == Casbinex.getUsersForRole("data2_admin") + assert { :ok, ["bob", "alice"] } == Casbinex.getUsersForRole("data2_admin") #delete the group assert :true == Casbinex.deleteRole("data2_admin") @@ -45,7 +45,7 @@ defmodule CasbinexTest do test "get a list of roles for the user" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert ["data2_admin"] == Casbinex.getRolesForUser("alice") + assert { :ok, ["data2_admin"] } == Casbinex.getRolesForUser("alice") assert :ok == Casbinex.destroyEnforcer(); end @@ -118,9 +118,9 @@ defmodule CasbinexTest do test "retrieves a filtered list of policies" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert [ + assert { :ok, [ ["bob", "data2", "write"], - ["data2_admin", "data2", "write"]] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) + ["data2_admin", "data2", "write"]] } = Casbinex.getFilteredPolicy(1, ["data2", "write"]) assert :ok == Casbinex.destroyEnforcer(); end @@ -128,13 +128,13 @@ defmodule CasbinexTest do test "removes a filtered list of policies" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert [ + assert { :ok, [ ["bob", "data2", "write"], ["data2_admin", "data2", "write"] - ] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) + ] } = Casbinex.getFilteredPolicy(1, ["data2", "write"]) Casbinex.removeFilteredPolicy(1, ["data2", "write"]) - assert [] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) + assert { :ok, []} = Casbinex.getFilteredPolicy(1, ["data2", "write"]) assert :ok == Casbinex.destroyEnforcer(); end @@ -142,13 +142,13 @@ defmodule CasbinexTest do test "removes a filtered list of policies when policy selector is charlist" do assert { :ok, _ } = Casbinex.createEnforcer(@model_path, @pgconnection) - assert [ + assert { :ok, [ ["bob", "data2", "write"], ["data2_admin", "data2", "read"], - ["data2_admin", "data2", "write"]] = Casbinex.getFilteredPolicy(1, "data2") + ["data2_admin", "data2", "write"]] } = Casbinex.getFilteredPolicy(1, "data2") Casbinex.removeFilteredPolicy(1, "data2") - assert [] = Casbinex.getFilteredPolicy(1, ["data2", "write"]) + assert { :ok, [] } = Casbinex.getFilteredPolicy(1, ["data2", "write"]) assert :ok == Casbinex.destroyEnforcer(); end