Skip to content

Commit

Permalink
feat: add json parser to build attribute in duktape (#166)
Browse files Browse the repository at this point in the history
* feat: add json parser to build attribute in duktape

Signed-off-by: stonex <1479765922@qq.com>

* feat: implement test basic ABAC model without policy using json.

Signed-off-by: stonex <1479765922@qq.com>
  • Loading branch information
sheny1xuan authored Nov 13, 2021
1 parent 4371da5 commit 367254b
Show file tree
Hide file tree
Showing 15 changed files with 175 additions and 3 deletions.
1 change: 1 addition & 0 deletions bindings/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ target_link_libraries(pycasbin
PRIVATE
pybind11::module
casbin
nlohmann_json::nlohmann_json
)

if(WIN32)
Expand Down
1 change: 1 addition & 0 deletions casbin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ add_library(casbin STATIC ${CASBIN_SOURCE_FILES})

target_precompile_headers(casbin PRIVATE pch.h)
target_include_directories(casbin PRIVATE ${CASBIN_SOURCE_DIR})
target_link_libraries(casbin PRIVATE nlohmann_json::nlohmann_json)

set_target_properties(casbin PROPERTIES
PREFIX ""
Expand Down
3 changes: 2 additions & 1 deletion casbin/data_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#include <vector>
#include <initializer_list>
#include <unordered_map>
#include <nlohmann/json.hpp>
#include "abac_data.h"

namespace casbin {

typedef std::variant<std::string, std::shared_ptr<ABACData>> Data;
typedef std::variant<std::string, std::shared_ptr<ABACData>, std::shared_ptr<nlohmann::json>> Data;
typedef std::vector<Data> DataVector;
typedef std::initializer_list<Data> DataList;
typedef std::unordered_map<std::string, Data> DataMap;
Expand Down
24 changes: 24 additions & 0 deletions casbin/enforcer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,14 @@ bool Enforcer::EnforceWithMatcher(const std::string& matcher, const DataList& pa
else
throw CasbinEnforcerException("Not a valid type");
}
} else if (const auto json_param = std::get_if<std::shared_ptr<nlohmann::json>>(&param)) {

auto data_ptr = *json_param;
std::string token_name = r_tokens[i].substr(2, r_tokens[i].size() - 2);

PushObject(scope, token_name);
PushObjectPropFromJson(scope, *data_ptr, token_name);
PushObjectPropToObject(scope, "r", token_name);
}
++i;
}
Expand Down Expand Up @@ -556,7 +564,16 @@ bool Enforcer::EnforceWithMatcher(const std::string& matcher, const DataVector&
else
throw CasbinEnforcerException("Not a valid type");
}
} else if (const auto json_param = std::get_if<std::shared_ptr<nlohmann::json>>(&param)) {

auto data_ptr = *json_param;
std::string token_name = r_tokens[i].substr(2, r_tokens[i].size() - 2);

PushObject(scope, token_name);
PushObjectPropFromJson(scope, *data_ptr, token_name);
PushObjectPropToObject(scope, "r", token_name);
}

++i;
}

Expand Down Expand Up @@ -601,7 +618,14 @@ bool Enforcer::EnforceWithMatcher(const std::string& matcher, const DataMap& par
else
throw CasbinEnforcerException("Not a valid type");
}
} else if (const auto json_param = std::get_if<std::shared_ptr<nlohmann::json>>(&param_data)) {

auto data_ptr = *json_param;
PushObject(scope, param_name);
PushObjectPropFromJson(scope, *data_ptr, param_name);
PushObjectPropToObject(scope, "r", param_name);
}

}

bool result = m_enforce(matcher, scope);
Expand Down
34 changes: 33 additions & 1 deletion casbin/model/scope_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@


#include "./scope_config.h"

#include "./exception/illegal_argument_exception.h"
namespace casbin {

Scope InitializeScope() {
Expand Down Expand Up @@ -194,6 +194,38 @@ void PushObjectPropToObject(Scope scope, std::string obj, std::string identifier
duk_eval_string_noresult(scope, (obj+"len += 1;").c_str());
}

void PushObjectPropFromJson(Scope scope, nlohmann::json& j, std::string objName) {
if (j.is_null()) {
return;
}

for (auto& curJson: j.items()) {
auto key = curJson.key();
auto value = curJson.value();
if (value.is_object()) {

auto nextJsonName = key + "__";
PushObject(scope, nextJsonName);

PushObjectPropFromJson(scope, value, nextJsonName);

duk_get_global_string(scope, objName.c_str());
duk_get_global_string(scope, nextJsonName.c_str());
duk_put_prop_string(scope, -2, key.c_str());
} else if (value.is_number_float()) {
PushDoublePropToObject(scope, objName, value, key);
} else if (value.is_number_integer()) {
PushIntPropToObject(scope, objName, value, key);
} else if (value.is_string()) {
PushStringPropToObject(scope, objName, value, key);
} else if (value.is_boolean()) {
PushBooleanPropToObject(scope, objName, value, key);
} else {
throw IllegalArgumentException("Unsupported json value type");
}
}
}

Type CheckType(Scope scope){
if(duk_is_boolean(scope, -1))
return Type::Bool;
Expand Down
1 change: 1 addition & 0 deletions casbin/model/scope_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ void PushDoublePropToObject(Scope scope, std::string obj, double d, std::string
void PushStringPropToObject(Scope scope, std::string obj, std::string s, std::string identifier);
void PushPointerPropToObject(Scope scope, std::string obj, void * ptr, std::string identifier);
void PushObjectPropToObject(Scope scope, std::string obj, std::string identifier);
void PushObjectPropFromJson(Scope scope, nlohmann::json& j, std::string j_name);
Type CheckType(Scope scope);
bool FetchIdentifier(Scope scope, std::string identifier);
unsigned int Size(Scope scope);
Expand Down
2 changes: 2 additions & 0 deletions cmake/modules/FindExtPackages.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ set(CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY ON CACHE BOOL
###############################################################################
### Packages and versions ###

find_package(json 3.7.3 REQUIRED)

if(CASBIN_BUILD_TEST)
# googletest
# https://github.com/google/googletest
Expand Down
28 changes: 28 additions & 0 deletions cmake/modules/Findjson.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

# Copyright 2021 The casbin Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
include(FetchContent)

FetchContent_Declare(json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.7.3)

set(JSON_BuildTests OFF CACHE INTERNAL "")
FetchContent_GetProperties(json)
FetchContent_MakeAvailable(json)

if(NOT json_POPULATED)
FetchContent_Populate(json)
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()
1 change: 1 addition & 0 deletions include/casbin/casbin_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ namespace casbin {
void PushStringPropToObject(Scope scope, std::string obj, std::string s, std::string identifier);
void PushPointerPropToObject(Scope scope, std::string obj, void * ptr, std::string identifier);
void PushObjectPropToObject(Scope scope, std::string obj, std::string identifier);
void PushObjectPropFromJson(Scope scope, nlohmann::json& j, std::string j_name);
Type CheckType(Scope scope);
bool FetchIdentifier(Scope scope, std::string identifier);
unsigned int Size(Scope scope);
Expand Down
3 changes: 2 additions & 1 deletion include/casbin/casbin_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <initializer_list>
#include <memory>
#include <unordered_map>
#include <nlohmann/json.hpp>

namespace casbin {

Expand Down Expand Up @@ -121,7 +122,7 @@ namespace casbin {
*/
const std::shared_ptr<ABACData> GetDataObject(const AttributeMap& attribs);

typedef std::variant<std::string, std::shared_ptr<ABACData>> Data;
typedef std::variant<std::string, std::shared_ptr<ABACData>, std::shared_ptr<nlohmann::json>> Data;
typedef std::vector<Data> DataVector;
typedef std::initializer_list<Data> DataList;
typedef std::unordered_map<std::string, Data> DataMap;
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ if(CASBIN_BUILD_TEST)
PRIVATE
gtest_main
casbin
nlohmann_json::nlohmann_json
)

include(GoogleTest)
Expand Down
1 change: 1 addition & 0 deletions tests/benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ target_link_libraries(
PRIVATE
benchmark
casbin
nlohmann_json::nlohmann_json
)
2 changes: 2 additions & 0 deletions tests/config_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ static const std::string keymatch_policy_path = relative_path + "/examples/keyma

static const std::string priority_model_path = relative_path + "/examples/priority_model.conf";
static const std::string priority_policy_path = relative_path + "/examples/priority_policy.csv";

static const std::string abac_model_path = relative_path + "/examples/abac_model.conf";
57 changes: 57 additions & 0 deletions tests/enforcer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,61 @@ TEST(TestEnforcer, ABACData) {
ASSERT_TRUE(params == data->GetAttributes());
}

TEST(TestEnforcer, JsonData) {
using json = nlohmann::json;
casbin::Scope scope = casbin::InitializeScope();
casbin::PushObject(scope, "r");

json myJson = {
{"DoubleCase", 3.141},
{"IntegerCase", 2},
{"BoolenCase", true},
{"StringCase", "Bob"},
// {"nothing", nullptr},
{"x", {
{"y", {
{"z", 1}
}
},
{"x", 2
}
}
},
};

casbin::PushObjectPropFromJson(scope, myJson, "r");
std::string s1 = "r.DoubleCase == 3.141;";
std::string s2 = "r.IntegerCase == 2;";
std::string s3 = "r.BoolenCase == true;";
std::string s4 = "r.StringCase == \"Bob\";";
std::string s5 = "r.x.y.z == 1;";
std::string s6 = "r.x.x == 2;";

auto EvalAndGetTop = [] (casbin::Scope scope, std::string s) -> bool {
casbin::Eval(scope, s);
return casbin::GetBoolean(scope, -1);
};

ASSERT_TRUE(EvalAndGetTop(scope, s1));
ASSERT_TRUE(EvalAndGetTop(scope, s2));
ASSERT_TRUE(EvalAndGetTop(scope, s3));
ASSERT_TRUE(EvalAndGetTop(scope, s4));
ASSERT_TRUE(EvalAndGetTop(scope, s5));
ASSERT_TRUE(EvalAndGetTop(scope, s6));

s1 = "r.DoubleCase == 3.14;";
s2 = "r.IntegerCase == 1;";
s3 = "r.BoolenCase == false;";
s4 = "r.StringCase == \"BoB\";";
s5 = "r.x.y.z == 2;";
s6 = "r.x.x == 1;";

ASSERT_TRUE(!EvalAndGetTop(scope, s1));
ASSERT_TRUE(!EvalAndGetTop(scope, s2));
ASSERT_TRUE(!EvalAndGetTop(scope, s3));
ASSERT_TRUE(!EvalAndGetTop(scope, s4));
ASSERT_TRUE(!EvalAndGetTop(scope, s5));
ASSERT_TRUE(!EvalAndGetTop(scope, s6));
}

} // namespace
19 changes: 19 additions & 0 deletions tests/model_enforcer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,25 @@ TEST(TestModelEnforcer, TestRBACModelWithPattern) {
scope = InitializeParams("bob", "/pen2/2", "GET");
TestEnforce(e, scope, true);
}

TEST(TestModelEnforcer, TestABACModelWithJson) {
using json = nlohmann::json;

json obj = {
{"Owner", "alice"},
};
auto objPtr = std::make_shared<json>(obj);

casbin::DataMap mapParams = {{"sub", "alice"}, {"obj", objPtr}, {"act", "write"}};
casbin::DataList listParams = {"alice", objPtr, "write"};
casbin::DataVector vectorParams = {"alice", objPtr, "write"};

casbin::Enforcer e(abac_model_path);

ASSERT_TRUE(e.Enforce(mapParams));
ASSERT_TRUE(e.Enforce(listParams));
ASSERT_TRUE(e.Enforce(vectorParams));
}
/*
type testCustomRoleManager struct {}
Expand Down

0 comments on commit 367254b

Please sign in to comment.