Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support AutoSave in built-in FileAdapter #391

Merged
merged 5 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -99,10 +100,10 @@ public void savePolicy(Model model) {

private List<String> getModelPolicy(Model model, String ptype) {
List<String> policy = new ArrayList<>();
model.model.get(ptype).forEach((k, v) -> {
Optional.ofNullable(model.model.get(ptype)).ifPresent(entry -> entry.forEach((k, v) -> {
List<String> p = v.policy.parallelStream().map(x -> k + ", " + Util.arrayToString(x)).collect(Collectors.toList());
policy.addAll(p);
});
}));
return policy;
}

Expand Down Expand Up @@ -130,15 +131,35 @@ private void savePolicyFile(String text) {
*/
@Override
public void addPolicy(String sec, String ptype, List<String> rule) {
throw new UnsupportedOperationException("not implemented");
String ruleText = System.lineSeparator() + ptype + ", " + String.join(", ", rule);
if (byteArrayInputStream != null && readOnly) {
throw new CasbinAdapterException("Policy file can not write, because use inputStream is readOnly");
}
try (FileOutputStream fos = new FileOutputStream(filePath, true)) {
IOUtils.write(ruleText, fos, Charset.forName("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
throw new CasbinAdapterException("Policy add error");
}
}

/**
* removePolicy removes a policy rule from the storage.
*/
@Override
public void removePolicy(String sec, String ptype, List<String> rule) {
throw new UnsupportedOperationException("not implemented");
String ruleText = ptype + ", " + String.join(", ", rule);
if (byteArrayInputStream != null && readOnly) {
throw new CasbinAdapterException("Policy file can not write, because use inputStream is readOnly");
}
try {
List<String> lines = IOUtils.readLines(new FileInputStream(filePath), Charset.forName("UTF-8"));
lines.remove(ruleText);
savePolicyFile(String.join("\n", lines));
} catch (IOException e) {
e.printStackTrace();
throw new CasbinAdapterException("Policy remove error");
}
}

/**
Expand Down
79 changes: 68 additions & 11 deletions src/test/java/org/casbin/jcasbin/main/EnforcerUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

package org.casbin.jcasbin.main;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import org.casbin.jcasbin.model.Model;
import org.casbin.jcasbin.persist.Adapter;
import org.casbin.jcasbin.persist.file_adapter.FileAdapter;
Expand All @@ -29,9 +27,7 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

Expand Down Expand Up @@ -365,22 +361,34 @@ public void testEnableAutoSave() {
testEnforce(e, "bob", "data2", "write", true);

e.enableAutoSave(true);
// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
// but also affects the policy in the storage.
e.removePolicy("alice", "data1", "read");

// However, the file adapter doesn't implement the AutoSave feature, so enabling it has no effect at all here.

// Affects the policy in the memory
testEnforce(e, "alice", "data1", "read", false);
// Affects the policy in the adapter
// Reload the policy from the storage to see the effect.
e.loadPolicy();
testEnforce(e, "alice", "data1", "read", true); // Will not be false here.
testEnforce(e, "alice", "data1", "read", false); // Will not be false here.
testEnforce(e, "alice", "data1", "write", false);
testEnforce(e, "alice", "data2", "read", false);
testEnforce(e, "alice", "data2", "write", false);
testEnforce(e, "bob", "data1", "read", false);
testEnforce(e, "bob", "data1", "write", false);
testEnforce(e, "bob", "data2", "read", false);
testEnforce(e, "bob", "data2", "write", true);

// enableAutoSave is enabled, prevent previous operations from affecting the CSV file.
e.addPolicy("alice", "data1", "read");

// Test group policy
e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");
testEnforce(e, "alice", "data2", "read", true);
e.removeGroupingPolicy("alice", "data2_admin");
testEnforce(e, "alice", "data2", "read", false);
e.loadPolicy();
testEnforce(e, "alice", "data2", "read", false);
e.addGroupingPolicy("alice", "data2_admin");
e.loadPolicy();
testEnforce(e, "alice", "data2", "read", true);
}

@Test
Expand All @@ -398,6 +406,54 @@ public void testInitWithAdapter() {
testEnforce(e, "bob", "data2", "write", true);
}

@Test
public void testFileAdapterAutoSave() {
Enforcer e = new Enforcer("examples/basic_model.conf", "examples/basic_policy.csv");

// test addPolicy() autoSave
e.enableAutoSave(false);
imp2002 marked this conversation as resolved.
Show resolved Hide resolved
testEnforce(e, "erica", "data3", "read", false);
e.addPolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", true);
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", false);

e.enableAutoSave(true);
testEnforce(e, "erica", "data3", "read", false);
e.addPolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", true);
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", true);

// test removePolicy() autoSave
e.enableAutoSave(false);
e.removePolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", false);
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", true);
e.enableAutoSave(true);
e.removePolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", false);
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", false);

// test savePolicy()
e.enableAutoSave(false);
e.addPolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", true);
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", false);
e.addPolicy("erica", "data3", "read");
testEnforce(e, "erica", "data3", "read", true);
e.savePolicy();
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", true);
e.removePolicy("erica", "data3", "read");
e.savePolicy();
e.loadPolicy();
testEnforce(e, "erica", "data3", "read", false);
}

@Test
public void testRoleLinks() {
Enforcer e = new Enforcer("examples/rbac_model.conf");
Expand Down Expand Up @@ -569,6 +625,7 @@ public void testPriorityExplicit() {
testEnforce(e, "data2_allow_group", "data2", "write", true);

// add a higher priority policy
e.enableAutoSave(false);
e.addPolicy("bob", "data2", "write", "deny", "1");

testEnforce(e, "alice", "data1", "write", true);
Expand All @@ -584,7 +641,7 @@ public void testPriorityExplicit() {
@Test
public void testEnforceWithMatcher() {
Enforcer e = new Enforcer("examples/basic_model.conf", "examples/basic_policy.csv");

e.enableAutoSave(false);
// the previous matcher is
// m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
testEnforce(e, "alice", "data1", "read", true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void testGetPolicyAPI() {
@Test
public void testModifyPolicyAPI() {
Enforcer e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetPolicy(e, asList(
asList("alice", "data1", "read"),
asList("bob", "data2", "write"),
Expand Down Expand Up @@ -131,7 +131,7 @@ public void testModifyPolicyAPI() {
@Test
public void testModifyGroupingPolicyAPI() {
Enforcer e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetRoles(e, "alice", asList("data2_admin"));
testGetRoles(e, "bob", asList());
testGetRoles(e, "eve", asList());
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public void testRBACModelWithDomains() {
@Test
public void testRBACModelWithDomainsAtRuntime() {
Enforcer e = new Enforcer("examples/rbac_with_domains_model.conf");

e.enableAutoSave(false);
e.addPolicy("admin", "domain1", "data1", "read");
e.addPolicy("admin", "domain1", "data1", "write");
e.addPolicy("admin", "domain2", "data2", "read");
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/org/casbin/jcasbin/main/RbacAPIUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class RbacAPIUnitTest {
@Test
public void testRoleAPI() {
Enforcer e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetRoles(e, "alice", asList("data2_admin"));
testGetRoles(e, "bob", asList());
testGetRoles(e, "data2_admin", asList());
Expand Down Expand Up @@ -128,7 +128,7 @@ public void testRoleAPIWithRegex() {
@Test
public void testGFunctionCache() {
Enforcer e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testEnforce(e, "alice", "data2", "read", true);
e.removeGroupingPolicy(Arrays.asList("alice","data2_admin"));
// Ensure that the gFunction cache is different for each enforce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class RbacAPIWithDomainsUnitTest {
@Test
public void testRoleAPIWithDomains() {
Enforcer e = new Enforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv");

e.enableAutoSave(false);
testGetRolesInDomain(e, "alice", "domain1", asList("admin"));
testGetRolesInDomain(e, "bob", "domain1", asList());
testGetRolesInDomain(e, "admin", "domain1", asList());
Expand Down Expand Up @@ -51,7 +51,7 @@ public void testRoleAPIWithDomains() {
@Test
public void testUserAPIWithDomains() {
Enforcer e = new Enforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv");

e.enableAutoSave(false);
testGetUsersInDomain(e, "alice", "domain1", asList());
testGetUsersInDomain(e, "bob", "domain1", asList());
testGetUsersInDomain(e, "admin", "domain1", asList("alice"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -394,22 +394,23 @@ public void testEnableAutoSave() {
testEnforce(e, "bob", "data2", "write", true);

e.enableAutoSave(true);
// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
// but also affects the policy in the storage.
e.removePolicy("alice", "data1", "read");

// However, the file adapter doesn't implement the AutoSave feature, so enabling it has no effect at all here.

// Affects the policy in the memory
testEnforce(e, "alice", "data1", "read", false);
// Affects the policy in the adapter
// Reload the policy from the storage to see the effect.
e.loadPolicy();
testEnforce(e, "alice", "data1", "read", true); // Will not be false here.
testEnforce(e, "alice", "data1", "read", false); // Will not be false here.
testEnforce(e, "alice", "data1", "write", false);
testEnforce(e, "alice", "data2", "read", false);
testEnforce(e, "alice", "data2", "write", false);
testEnforce(e, "bob", "data1", "read", false);
testEnforce(e, "bob", "data1", "write", false);
testEnforce(e, "bob", "data2", "read", false);
testEnforce(e, "bob", "data2", "write", true);

// enableAutoSave is enabled, prevent previous operations from affecting the CSV file.
e.addPolicy("alice", "data1", "read");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void testGetPolicyAPI() {
@Test
public void testModifyPolicyAPI() {
Enforcer e = new SyncedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetPolicy(e, asList(
asList("alice", "data1", "read"),
asList("bob", "data2", "write"),
Expand Down Expand Up @@ -96,7 +96,7 @@ public void testModifyPolicyAPI() {
@Test
public void testModifyGroupingPolicyAPI() {
Enforcer e = new SyncedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetRoles(e, "alice", asList("data2_admin"));
testGetRoles(e, "bob", asList());
testGetRoles(e, "eve", asList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class SyncedRbacAPIUnitTest {
@Test
public void testRoleAPI() {
Enforcer e = new SyncedEnforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");

e.enableAutoSave(false);
testGetRoles(e, "alice", asList("data2_admin"));
testGetRoles(e, "bob", asList());
testGetRoles(e, "data2_admin", asList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class SyncedRbacAPIWithDomainsUnitTest {
@Test
public void testRoleAPIWithDomains() {
Enforcer e = new SyncedEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv");

e.enableAutoSave(false);
testGetRolesInDomain(e, "alice", "domain1", asList("admin"));
testGetRolesInDomain(e, "bob", "domain1", asList());
testGetRolesInDomain(e, "admin", "domain1", asList());
Expand Down Expand Up @@ -51,7 +51,7 @@ public void testRoleAPIWithDomains() {
@Test
public void testUserAPIWithDomains() {
Enforcer e = new SyncedEnforcer("examples/rbac_with_domains_model.conf", "examples/rbac_with_domains_policy.csv");

e.enableAutoSave(false);
testGetUsersInDomain(e, "alice", "domain1", asList());
testGetUsersInDomain(e, "bob", "domain1", asList());
testGetUsersInDomain(e, "admin", "domain1", asList("alice"));
Expand Down
1 change: 1 addition & 0 deletions src/test/java/org/casbin/jcasbin/main/WatcherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public void testSetWatcher() {
@Test
public void testSelfModify() {
Enforcer enforcer = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv");
enforcer.enableAutoSave(false);
SampleWatcher thisIsTestWatcher = new SampleWatcher();
enforcer.setWatcher(thisIsTestWatcher);
AtomicInteger called = new AtomicInteger(-1);
Expand Down
Loading