diff --git a/src/main/java/org/ultramine/permission/GroupPermission.java b/src/main/java/org/ultramine/permission/GroupPermission.java index 943025f..6f9ed11 100644 --- a/src/main/java/org/ultramine/permission/GroupPermission.java +++ b/src/main/java/org/ultramine/permission/GroupPermission.java @@ -1,38 +1,24 @@ package org.ultramine.permission; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; - -public class GroupPermission extends MetaHolder implements IChangeablePermission, IDirtyListener +public class GroupPermission extends PermissionHolder implements IChangeablePermission { - private static Logger logger = LogManager.getLogger(GroupPermission.class); - - private String key; - private boolean dirty; - - private PermissionResolver permissionResolver = new PermissionResolver(); - private List listeners = new ArrayList(); - private Map permissions = new HashMap(); - private MetaResolver metaResolver = new MetaResolver(); + private final String key; + private final List listeners = new ArrayList(); public GroupPermission(String key) { super(); this.key = key.toLowerCase(); - this.dirty = false; } public GroupPermission(String key, Map meta) { super(meta); this.key = key.toLowerCase(); - this.dirty = true; } @Override @@ -60,59 +46,6 @@ } @Override - public PermissionResolver getPermissions() - { - if (isDirty()) - calculate(); - - return permissionResolver; - } - - @Override - public MetaResolver getMeta() - { - if (isDirty()) - calculate(); - - return metaResolver; - } - - public void addPermission(IPermission permission) - { - if (permissions.containsKey(permission.getKey())) - return; - - permissions.put(permission.getKey(), permission); - if (permission instanceof IChangeablePermission) - ((IChangeablePermission) permission).subscribe(this); - - makeDirty(); - } - - public void removePermission(IPermission permission) - { - removePermission(permission.getKey()); - } - - public void removePermission(String key) - { - if (!permissions.containsKey(key)) - return; - - IPermission perm = permissions.remove(key); - if (perm instanceof IChangeablePermission) - ((IChangeablePermission) perm).unsubscribe(this); - - makeDirty(); - } - - @Override - public boolean isDirty() - { - return dirty; - } - - @Override public void subscribe(IDirtyListener listener) { listeners.add(listener); @@ -127,48 +60,15 @@ @Override public void makeDirty() { - logger.error(getName()); if (isDirty()) return; - dirty = true; + super.makeDirty(); for (IDirtyListener listener : listeners) listener.makeDirty(); } @Override - public void setMeta(String key, Object value) - { - super.setMeta(key, value); - makeDirty(); - } - - @Override - public void removeMeta(String key) - { - super.removeMeta(key); - makeDirty(); - } - - public void calculate() - { - if (!isDirty()) - return; - dirty = false; - - permissionResolver.clear(); - metaResolver.clear(); - - for (IPermission permission : permissions.values()) - { - permissionResolver.merge(permission.getPermissions(), permission.getPriority()); - metaResolver.merge(permission.getMeta(), permission.getPriority()); - } - - metaResolver.merge(innerMeta, Integer.MAX_VALUE); - } - - @Override public int hashCode() { return getKey().hashCode(); diff --git a/src/main/java/org/ultramine/permission/PermissionHolder.java b/src/main/java/org/ultramine/permission/PermissionHolder.java new file mode 100644 index 0000000..97366e5 --- /dev/null +++ b/src/main/java/org/ultramine/permission/PermissionHolder.java @@ -0,0 +1,114 @@ +package org.ultramine.permission; + +import java.util.HashMap; +import java.util.Map; + +public class PermissionHolder extends MetaHolder implements IDirtyListener +{ + private boolean dirty; + + private Map permissions = new HashMap(); + private PermissionResolver permissionResolver = new PermissionResolver(); + private MetaResolver metaResolver = new MetaResolver(); + + public PermissionHolder() + { + super(); + this.dirty = false; + } + + public PermissionHolder(Map meta) + { + super(meta); + this.dirty = true; + } + + public PermissionResolver getPermissions() + { + if (isDirty()) + calculate(); + + return permissionResolver; + } + + @Override + public MetaResolver getMeta() + { + if (isDirty()) + calculate(); + + return metaResolver; + } + + public void addPermission(IPermission permission) + { + if (permissions.containsKey(permission.getKey())) + return; + + permissions.put(permission.getKey(), permission); + if (permission instanceof IChangeablePermission) + ((IChangeablePermission) permission).subscribe(this); + + makeDirty(); + } + + public void removePermission(IPermission permission) + { + removePermission(permission.getKey()); + } + + public void removePermission(String key) + { + if (!permissions.containsKey(key)) + return; + + IPermission perm = permissions.remove(key); + if (perm instanceof IChangeablePermission) + ((IChangeablePermission) perm).unsubscribe(this); + + makeDirty(); + } + + public boolean isDirty() + { + return dirty; + } + + @Override + public void makeDirty() + { + dirty = true; + } + + @Override + public void setMeta(String key, Object value) + { + super.setMeta(key, value); + makeDirty(); + } + + @Override + public void removeMeta(String key) + { + super.removeMeta(key); + makeDirty(); + } + + public void calculate() + { + if (!isDirty()) + return; + dirty = false; + + permissionResolver.clear(); + metaResolver.clear(); + + for (IPermission permission : permissions.values()) + { + permissionResolver.merge(permission.getPermissions(), permission.getPriority()); + metaResolver.merge(permission.getMeta(), permission.getPriority()); + } + + metaResolver.merge(innerMeta, Integer.MAX_VALUE); + } +} diff --git a/src/main/java/org/ultramine/permission/PermissionResolver.java b/src/main/java/org/ultramine/permission/PermissionResolver.java index d9aeb3e..7c7ba4f 100644 --- a/src/main/java/org/ultramine/permission/PermissionResolver.java +++ b/src/main/java/org/ultramine/permission/PermissionResolver.java @@ -23,14 +23,14 @@ return resolver; } - public boolean has(String key) + public CheckResult check(String key) { if (key == null) - return false; + return CheckResult.UNRESOLVED; key = key.toLowerCase(); if (values.containsKey(key)) - return values.get(key); + return toCheckResult(values.get(key)); int index = key.lastIndexOf('.'); while (index >= 0) @@ -38,13 +38,19 @@ key = key.substring(0, index); String wildcard = key + ".*"; if (values.containsKey(wildcard)) - return values.get(wildcard); + return toCheckResult(values.get(wildcard)); index = key.lastIndexOf('.'); } if (values.containsKey("*")) - return values.get("*"); + return toCheckResult(values.get("*")); - return false; + return CheckResult.UNRESOLVED; + } + + public enum CheckResult { TRUE, FALSE, UNRESOLVED } + private CheckResult toCheckResult(boolean bool) + { + return bool ? CheckResult.TRUE : CheckResult.FALSE; } } diff --git a/src/main/java/org/ultramine/permission/User.java b/src/main/java/org/ultramine/permission/User.java new file mode 100644 index 0000000..78a079b --- /dev/null +++ b/src/main/java/org/ultramine/permission/User.java @@ -0,0 +1,31 @@ +package org.ultramine.permission; + +import java.util.Map; + +public class User extends PermissionHolder +{ + private final String name; + + public User(String name) + { + super(); + this.name = name; + } + + public User(String name, Map meta) + { + super(meta); + this.name = name; + } + + public String getName() + { + return name; + } + + @Override + public int getPriority() + { + return getMeta().getInt("priority"); + } +} \ No newline at end of file diff --git a/src/main/java/org/ultramine/permission/UserContainer.java b/src/main/java/org/ultramine/permission/UserContainer.java new file mode 100644 index 0000000..48049fa --- /dev/null +++ b/src/main/java/org/ultramine/permission/UserContainer.java @@ -0,0 +1,73 @@ +package org.ultramine.permission; + +import java.util.HashMap; +import java.util.Map; + +public class UserContainer +{ + private Map users; + protected UserContainer parentContainer; + + public UserContainer() + { + users = new HashMap(); + } + + public UserContainer(UserContainer parentContainer) + { + this(); + this.parentContainer = parentContainer; + } + + public boolean checkUserPermission(String userName, String permissionKey) + { + if (parentContainer != null && parentContainer.contains(userName)) + switch (parentContainer.get(userName).getPermissions().check(permissionKey)) + { + case TRUE: return true; + case FALSE: return false; + } + + if (contains(userName)) + switch (get(userName).getPermissions().check(permissionKey)) + { + case TRUE: return true; + case FALSE: return false; + } + + return false; + } + + public T get(String name) + { + return users.get(name); + } + + public void add(T user) + { + if (users.containsKey(user.getName())) + return; + + users.put(user.getName(), user); + } + + public void remove(String name) + { + users.remove(name); + } + + public void remove(User user) + { + remove(user.getName()); + } + + public boolean contains(String name) + { + return users.containsKey(name); + } + + public boolean contains(User user) + { + return contains(user.getName()); + } +} diff --git a/src/test/groovy/org/ultramine/permission/GroupPermissionTest.groovy b/src/test/groovy/org/ultramine/permission/GroupPermissionTest.groovy index b69863c..f433981 100644 --- a/src/test/groovy/org/ultramine/permission/GroupPermissionTest.groovy +++ b/src/test/groovy/org/ultramine/permission/GroupPermissionTest.groovy @@ -9,57 +9,6 @@ */ class GroupPermissionTest extends Specification { - MetaResolver createMetaResolver(Map meta) - { - def resolver = new MetaResolver() - resolver.merge(meta, 0) - return resolver - } - - def "Test calculation"() { - setup: - def resolver = Mock(PermissionResolver) - def perm1 = Mock(IPermission) { - getKey() >> "p.1" - getPermissions() >> resolver - getMeta() >> createMetaResolver([test1: "1", test2: "1", test3: "1"]) - getPriority() >> 1 - } - def perm2 = Mock(IPermission) { - getKey() >> "p.2" - getPermissions() >> resolver - getMeta() >> createMetaResolver([test2: "2"]) - getPriority() >> 2 - } - - def group = new GroupPermission("group.test", [test1: "0"]) - group.permissionResolver = resolver - group.addPermission(perm1) - group.addPermission(perm2) - - when: "Calculate meta and permissions" - group.calculate() - - then: "Permissions are calculated" - !group.isDirty() - 1 * resolver.clear() - 1 * resolver.merge(resolver, 1) - 1 * resolver.merge(resolver, 2) - 0 * resolver._ - - and: "Meta is correct" - group.getMeta().getString("test1") == "0" - group.getMeta().getString("test2") == "2" - group.getMeta().getString("test3") == "1" - - when: "Calculate one more time" - group.calculate() - - then: "Nothing happens" - !group.isDirty() - 0 * resolver._ - } - def "Test recursive calculation"() { setup: "Prepare recursive groups" def group1 = new GroupPermission("g1", [m1: "a"]) diff --git a/src/test/groovy/org/ultramine/permission/NegativePermissionTest.groovy b/src/test/groovy/org/ultramine/permission/NegativePermissionTest.groovy index 4b04d70..91835de 100644 --- a/src/test/groovy/org/ultramine/permission/NegativePermissionTest.groovy +++ b/src/test/groovy/org/ultramine/permission/NegativePermissionTest.groovy @@ -1,5 +1,6 @@ package org.ultramine.permission +import static org.ultramine.permission.PermissionResolver.CheckResult.* import spock.lang.Specification /** @@ -27,7 +28,7 @@ perm.getDescription() == "NOT: Test Description" perm.getPriority() == 100 perm.getMeta().getString("1") == "mock" - !perm.getPermissions().has("test.key") + perm.getPermissions().check("test.key") == FALSE } def "Test isDirty IPermission"() { @@ -83,7 +84,7 @@ perm.getDescription() == "NOT: Test Description" perm.getPriority() == 100 perm.getMeta().getString("1") == "mock" - !perm.getPermissions().has("test.key") + perm.getPermissions().check("test.key") == FALSE } def "Test isDirty IChangeablePermission"() { diff --git a/src/test/groovy/org/ultramine/permission/PermissionHolderTest.groovy b/src/test/groovy/org/ultramine/permission/PermissionHolderTest.groovy new file mode 100644 index 0000000..d7fbd33 --- /dev/null +++ b/src/test/groovy/org/ultramine/permission/PermissionHolderTest.groovy @@ -0,0 +1,90 @@ +package org.ultramine.permission + +import spock.lang.Specification + +class PermissionHolderTest extends Specification { + + MetaResolver createMetaResolver(Map meta) + { + def resolver = new MetaResolver() + resolver.merge(meta, 0) + return resolver + } + + def "Test calculation"() { + setup: + def resolver = Mock(PermissionResolver) + def perm1 = Mock(IPermission) { + getKey() >> "p.1" + getPermissions() >> resolver + getMeta() >> createMetaResolver([test1: "1", test2: "1", test3: "1"]) + getPriority() >> 1 + } + def perm2 = Mock(IPermission) { + getKey() >> "p.2" + getPermissions() >> resolver + getMeta() >> createMetaResolver([test2: "2"]) + getPriority() >> 2 + } + + def holder = new PermissionHolder([test1: "0"]) + holder.permissionResolver = resolver + holder.addPermission(perm1) + holder.addPermission(perm2) + + when: "Calculate meta and permissions" + holder.calculate() + + then: "Permissions are calculated" + !holder.isDirty() + 1 * resolver.clear() + 1 * resolver.merge(resolver, 1) + 1 * resolver.merge(resolver, 2) + 0 * resolver._ + + and: "Meta is correct" + holder.getMeta().getString("test1") == "0" + holder.getMeta().getString("test2") == "2" + holder.getMeta().getString("test3") == "1" + + when: "Calculate one more time" + holder.calculate() + + then: "Nothing happens" + !holder.isDirty() + 0 * resolver._ + } + + def "Test dirty methods"() { + setup: + def holder = new PermissionHolder() + + when: "Call setMeta method" + holder.calculate() + holder.setMeta("test", 21) + + then: "Group becomes dirty" + holder.isDirty() + + when: "Call removeMeta method" + holder.calculate() + holder.removeMeta("test") + + then: "Group becomes dirty" + holder.isDirty() + + when: "Call addPermission method" + holder.calculate() + holder.addPermission(new Permission("test")) + + then: "Group becomes dirty" + holder.isDirty() + + when: "Call removePermission method" + holder.calculate() + holder.removePermission("test") + + then: "Group becomes dirty" + holder.isDirty() + } +} diff --git a/src/test/groovy/org/ultramine/permission/PermissionResolverTest.groovy b/src/test/groovy/org/ultramine/permission/PermissionResolverTest.groovy index 5486561..51f106a 100644 --- a/src/test/groovy/org/ultramine/permission/PermissionResolverTest.groovy +++ b/src/test/groovy/org/ultramine/permission/PermissionResolverTest.groovy @@ -2,6 +2,7 @@ import spock.lang.Specification import spock.lang.Unroll +import static org.ultramine.permission.PermissionResolver.CheckResult.* /** * Created by Евгений on 08.05.2014. @@ -22,7 +23,7 @@ def resolver = PermissionResolver.createForKey(key, 0) then: "Resolver has this key" - resolver.has(key) + resolver.check(key) == TRUE where: key << ["test.key", "super.test.*", "^group.admin"] @@ -38,11 +39,11 @@ def inverted = PermissionResolver.createInverted(resolver) then: "Permission are inverted" - inverted.has("p.false") - !inverted.has("p.true") + inverted.check("p.false") == TRUE + inverted.check("p.true") == FALSE and: "New permissions are not created" - !inverted.has("group.admin") + inverted.check("group.admin") == UNRESOLVED } def "Test wildcard"() { @@ -51,16 +52,16 @@ resolver.addEntry("test.perm.*", true, 0) expect: "Other permissions are not affected" - !resolver.has("group.admin") - !resolver.has("group.admin.super") + resolver.check("group.admin") == UNRESOLVED + resolver.check("group.admin.super") == UNRESOLVED and: "Parent nodes are not affected" - !resolver.has("test") - !resolver.has("test.perm") + resolver.check("test") == UNRESOLVED + resolver.check("test.perm") == UNRESOLVED and: "Child nodes are affected" - resolver.has("test.perm.1") - resolver.has("test.perm.2.3") + resolver.check("test.perm.1") == TRUE + resolver.check("test.perm.2.3") == TRUE } def "Test single permission override wildcard"() { @@ -70,15 +71,35 @@ resolver.addEntry("test.perm.super", false, 0) expect: "Wildcard has lower priority" - !resolver.has("test.perm.super") - resolver.has("test.perm.super2") + resolver.check("test.perm.super") == FALSE + resolver.check("test.perm.super2") == TRUE when: "Invert resolver" resolver = PermissionResolver.createInverted(resolver) then: "Same effect" - resolver.has("test.perm.super") - !resolver.has("test.perm.super2") + resolver.check("test.perm.super") == TRUE + resolver.check("test.perm.super2") == FALSE + } + + def "Test higher node wildcard priority"() { + setup: "Resolver with wildcards" + def resolver = new PermissionResolver() + resolver.addEntry("test.perm.*", true, 1) + resolver.addEntry("test.perm.super.*", false, 0) + + expect: "Higher node wildcard has priority" + resolver.check("test.perm.super.p") == FALSE + resolver.check("test.perm.super.p.p") == FALSE + resolver.check("test.perm.p") == TRUE + + when: "Invert resolver" + resolver = PermissionResolver.createInverted(resolver) + + then: "Same effect" + resolver.check("test.perm.super.p") == TRUE + resolver.check("test.perm.super.p.p") == TRUE + resolver.check("test.perm.p") == FALSE } def "Test clear"() { @@ -90,7 +111,7 @@ resolver.clear() then: "It has no permissions" - !resolver.has("test.perm") + resolver.check("test.perm") == UNRESOLVED } def "Test merge"() { @@ -112,11 +133,11 @@ result.merge(resolver2, 2) then: - !result.has("test.perm") - !result.has("test.perm.1") - !result.has("test.perm.2") - result.has("test.perm.3") - !result.has("group.admin") + result.check("test.perm") == FALSE + result.check("test.perm.1") == FALSE + result.check("test.perm.2") == FALSE + result.check("test.perm.3") == TRUE + result.check("group.admin") == UNRESOLVED when: "Merge second then first" result = new PermissionResolver() @@ -124,21 +145,21 @@ result.merge(resolver1, 1) then: "Same effect" - !result.has("test.perm") - !result.has("test.perm.1") - !result.has("test.perm.2") - result.has("test.perm.3") - !result.has("group.admin") + result.check("test.perm") == FALSE + result.check("test.perm.1") == FALSE + result.check("test.perm.2") == FALSE + result.check("test.perm.3") == TRUE + result.check("group.admin") == UNRESOLVED when: "Merge first to second" resolver2.merge(resolver1, 1) then: - resolver2.has("test.perm") - !resolver2.has("test.perm.1") - !resolver2.has("test.perm.2") - resolver2.has("test.perm.3") - !resolver2.has("group.admin") + resolver2.check("test.perm") == TRUE + resolver2.check("test.perm.1") == FALSE + resolver2.check("test.perm.2") == FALSE + resolver2.check("test.perm.3") == TRUE + resolver2.check("group.admin") == UNRESOLVED } def "Test clear -> merge lower priority"() { @@ -151,6 +172,6 @@ resolver.merge(inverted, 50) then: - resolver.has("test") + resolver.check("test") == TRUE } } diff --git a/src/test/groovy/org/ultramine/permission/UserContainerTest.groovy b/src/test/groovy/org/ultramine/permission/UserContainerTest.groovy new file mode 100644 index 0000000..dc95748 --- /dev/null +++ b/src/test/groovy/org/ultramine/permission/UserContainerTest.groovy @@ -0,0 +1,46 @@ +package org.ultramine.permission + +import spock.lang.Specification + +class UserContainerTest extends Specification { + + def stubUser(String name, Map permissions) { + def resolver = new PermissionResolver(); + resolver.merge(permissions, 0) + Mock(User) { + getName() >> name + getPermissions() >> resolver + } + } + + def "Test permissions"() { + setup: + def parent = new UserContainer() + def child = new UserContainer(parent) + + when: "Add user to parent container" + parent.add(stubUser("parent", [parent: true])) + + then: "Both container has user with permission" + parent.checkUserPermission("parent", "parent") + child.checkUserPermission("parent", "parent") + + when: "Add user to child container" + child.add(stubUser("child", [child: true])) + + then: "Only child container has user with permission" + !parent.checkUserPermission("child", "child") + child.checkUserPermission("child", "child") + + when: "Override parent user in child container" + child.add(stubUser("parent", [parent: false, child: true])) + + then: "Parent container permissions have higher priority" + child.checkUserPermission("parent", "parent") + child.checkUserPermission("parent", "child") + + and: "Parent container permissions is not modified" + parent.checkUserPermission("parent", "parent") + !parent.checkUserPermission("parent", "child") + } +}