diff --git a/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java b/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java index c3595c39..a1cbdf89 100644 --- a/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java +++ b/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java @@ -32,6 +32,7 @@ import org.casbin.jcasbin.model.FunctionMap; import org.casbin.jcasbin.model.Model; import org.casbin.jcasbin.persist.*; +import org.casbin.jcasbin.persist.file_adapter.FileAdapter; import org.casbin.jcasbin.rbac.DomainManager; import org.casbin.jcasbin.rbac.RoleManager; import org.casbin.jcasbin.util.BuiltInFunctions; @@ -70,7 +71,7 @@ void initialize() { watcher = null; enabled = true; - autoSave = true; + autoSave = adapter instanceof FileAdapter ? false : true; autoBuildRoleLinks = true; dispatcher = null; aviatorEval = AviatorEvaluator.newInstance(); diff --git a/src/main/java/org/casbin/jcasbin/persist/file_adapter/FileAdapter.java b/src/main/java/org/casbin/jcasbin/persist/file_adapter/FileAdapter.java index 0a463b5a..e6af32ba 100644 --- a/src/main/java/org/casbin/jcasbin/persist/file_adapter/FileAdapter.java +++ b/src/main/java/org/casbin/jcasbin/persist/file_adapter/FileAdapter.java @@ -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; /** @@ -99,10 +100,10 @@ public void savePolicy(Model model) { private List getModelPolicy(Model model, String ptype) { List policy = new ArrayList<>(); - model.model.get(ptype).forEach((k, v) -> { + Optional.ofNullable(model.model.get(ptype)).ifPresent(entry -> entry.forEach((k, v) -> { List p = v.policy.parallelStream().map(x -> k + ", " + Util.arrayToString(x)).collect(Collectors.toList()); policy.addAll(p); - }); + })); return policy; } @@ -130,7 +131,16 @@ private void savePolicyFile(String text) { */ @Override public void addPolicy(String sec, String ptype, List 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"); + } } /** @@ -138,7 +148,18 @@ public void addPolicy(String sec, String ptype, List rule) { */ @Override public void removePolicy(String sec, String ptype, List 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 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"); + } } /** diff --git a/src/test/java/org/casbin/jcasbin/main/EnforcerUnitTest.java b/src/test/java/org/casbin/jcasbin/main/EnforcerUnitTest.java index 0d37556f..a998047f 100644 --- a/src/test/java/org/casbin/jcasbin/main/EnforcerUnitTest.java +++ b/src/test/java/org/casbin/jcasbin/main/EnforcerUnitTest.java @@ -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; @@ -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; @@ -365,22 +361,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. - + testEnforce(e, "bob", "data2", "write", true); + e.removePolicy("bob", "data2", "write"); + // Affects the policy in the memory + testEnforce(e, "bob", "data2", "write", 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", true); 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); + testEnforce(e, "bob", "data2", "write", false); + // prevent previous operations from affecting the CSV file, add the remove policy + e.addPolicy("bob", "data2", "write"); } @Test @@ -398,6 +395,66 @@ 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); + 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 group policy auto save + e = new Enforcer("examples/rbac_model.conf", "examples/rbac_policy.csv"); + e.enableAutoSave(true); + 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 public void testRoleLinks() { Enforcer e = new Enforcer("examples/rbac_model.conf"); @@ -569,6 +626,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); diff --git a/src/test/java/org/casbin/jcasbin/main/SyncedEnforcerUnitTest.java b/src/test/java/org/casbin/jcasbin/main/SyncedEnforcerUnitTest.java index a9255ab0..471f7d4f 100644 --- a/src/test/java/org/casbin/jcasbin/main/SyncedEnforcerUnitTest.java +++ b/src/test/java/org/casbin/jcasbin/main/SyncedEnforcerUnitTest.java @@ -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. - + testEnforce(e, "bob", "data2", "write", true); + e.removePolicy("bob", "data2", "write"); + // Affects the policy in the memory + testEnforce(e, "bob", "data2", "write", 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", true); 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); + testEnforce(e, "bob", "data2", "write", false); + // prevent previous operations from affecting the CSV file, add the remove policy + e.addPolicy("bob", "data2", "write"); } @Test