From 8b8058dc47dc5b98f7efe4811f6597089d79922d Mon Sep 17 00:00:00 2001 From: andrea Date: Tue, 19 May 2015 22:07:57 +0200 Subject: [PATCH] Added basic initial implementation for ACL validation --- .../spi/impl/security/ACLAuthorizator.java | 26 ++++++++- .../spi/impl/security/ACLFileParser.java | 4 ++ .../spi/impl/security/Authorization.java | 4 +- .../spi/impl/security/IAuthorizator.java | 8 ++- .../impl/security/PermitAllAuthorizator.java | 5 ++ .../spi/impl/subscriptions/Token.java | 5 +- .../impl/security/ACLAuthorizatorTest.java | 54 +++++++++++++++++++ 7 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 broker/src/test/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizatorTest.java diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizator.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizator.java index 743dfdbb..e402c75b 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizator.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizator.java @@ -15,6 +15,9 @@ */ package org.eclipse.moquette.spi.impl.security; +import static org.eclipse.moquette.spi.impl.security.Authorization.Permission.*; +import static org.eclipse.moquette.spi.impl.security.Authorization.Permission; +import org.eclipse.moquette.spi.impl.subscriptions.SubscriptionsStore; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,19 +33,38 @@ public class ACLAuthorizator implements IAuthorizator { private static final Logger LOG = LoggerFactory.getLogger(ACLAuthorizator.class); - List authorisations = Collections.emptyList(); + List m_authorisations = Collections.emptyList(); public ACLAuthorizator(String aclFilePath) { File aclFile = new File(aclFilePath); try { - authorisations = ACLFileParser.parse(aclFile); + m_authorisations = ACLFileParser.parse(aclFile); } catch (ParseException pex) { LOG.warn(String.format("Format error in parsing acl file %s", aclFile), pex); } } + public ACLAuthorizator(List authorisations) { + m_authorisations = authorisations; + } + @Override public boolean canWrite(String topic) { + return canDoOperation(topic, WRITE); + } + + public boolean canRead(String topic) { + return canDoOperation(topic, READ); + } + + private boolean canDoOperation(String topic, Permission permission) { + for (Authorization auth : m_authorisations) { + if (auth.permission == permission) { + if (SubscriptionsStore.matchTopics(topic, auth.topic)) { + return true; + } + } + } return false; } } diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLFileParser.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLFileParser.java index c0407d90..e05d52a7 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLFileParser.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/ACLFileParser.java @@ -27,6 +27,10 @@ import java.util.List; import static org.eclipse.moquette.spi.impl.security.Authorization.Permission; /** + * Parses the acl configuration file. + * If a line starts with # it's comment. + * Blank lines are skipped. The format is "topic [read|write|readwrite] " + * * @author andrea * */ public class ACLFileParser { diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/Authorization.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/Authorization.java index 2a5328a3..1cb4400a 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/Authorization.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/Authorization.java @@ -21,8 +21,8 @@ package org.eclipse.moquette.spi.impl.security; * @author andrea */ public class Authorization { - private String topic; - private Permission permission; + protected final String topic; + protected final Permission permission; /** * Access rights diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/IAuthorizator.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/IAuthorizator.java index 0c02e546..39d64dc1 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/IAuthorizator.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/IAuthorizator.java @@ -16,7 +16,11 @@ package org.eclipse.moquette.spi.impl.security; /** - * ACL checker + * ACL checker. + * + * Create an authorizator that matches topic names with same grammar of subscriptions. + * The # is always a terminator and its the multilevel matcher. + * The + sign is the single level matcher. * * @author andrea */ @@ -26,4 +30,6 @@ public interface IAuthorizator { * Ask the implementation of the authorizator if the topic can be used in a publish. * */ boolean canWrite(String topic); + + boolean canRead(String topic); } diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/PermitAllAuthorizator.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/PermitAllAuthorizator.java index 4a8c6c20..a22a8aca 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/security/PermitAllAuthorizator.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/security/PermitAllAuthorizator.java @@ -23,4 +23,9 @@ public class PermitAllAuthorizator implements IAuthorizator { public boolean canWrite(String topic) { return true; } + + @Override + public boolean canRead(String topic) { + return true; + } } diff --git a/broker/src/main/java/org/eclipse/moquette/spi/impl/subscriptions/Token.java b/broker/src/main/java/org/eclipse/moquette/spi/impl/subscriptions/Token.java index 117e986c..5bb87f7b 100644 --- a/broker/src/main/java/org/eclipse/moquette/spi/impl/subscriptions/Token.java +++ b/broker/src/main/java/org/eclipse/moquette/spi/impl/subscriptions/Token.java @@ -15,7 +15,10 @@ */ package org.eclipse.moquette.spi.impl.subscriptions; -class Token { +/** + * Internal use only class. + * */ +public class Token { static final Token EMPTY = new Token(""); static final Token MULTI = new Token("#"); diff --git a/broker/src/test/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizatorTest.java b/broker/src/test/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizatorTest.java new file mode 100644 index 00000000..ab467d16 --- /dev/null +++ b/broker/src/test/java/org/eclipse/moquette/spi/impl/security/ACLAuthorizatorTest.java @@ -0,0 +1,54 @@ +package org.eclipse.moquette.spi.impl.security; + +import org.junit.Test; + +import static java.util.Arrays.*; +import static org.eclipse.moquette.spi.impl.security.Authorization.Permission.*; +import static org.junit.Assert.*; + +public class ACLAuthorizatorTest { + + @Test + public void testCanWriteSimpleTopic() { + ACLAuthorizator authorizator = new ACLAuthorizator(asList(new Authorization("/sensors", WRITE))); + + //verify + assertTrue(authorizator.canWrite("/sensors")); + } + + @Test + public void testCanReadSimpleTopic() { + ACLAuthorizator authorizator = new ACLAuthorizator(asList(new Authorization("/sensors", READ))); + + //verify + assertTrue(authorizator.canRead("/sensors")); + } + + @Test + public void testCanReadWriteMixedSimpleTopic() { + Authorization topicWriteACL = new Authorization("/sensors", WRITE); + Authorization topicReadACL = new Authorization("/sensors/anemometer", READ); + ACLAuthorizator authorizator = new ACLAuthorizator(asList(topicWriteACL, topicReadACL)); + + //verify + assertTrue(authorizator.canWrite("/sensors")); + assertFalse(authorizator.canRead("/sensors")); + } + + @Test + public void testCanWriteMultiMatherTopic() { + ACLAuthorizator authorizator = new ACLAuthorizator(asList(new Authorization("/sensors/#", WRITE))); + + //verify + assertTrue(authorizator.canWrite("/sensors/anemometer/wind")); + } + + @Test + public void testCanWriteSingleMatherTopic() { + ACLAuthorizator authorizator = new ACLAuthorizator(asList(new Authorization("/sensors/+", WRITE))); + + //verify + assertTrue(authorizator.canWrite("/sensors/anemometer")); + } + +} \ No newline at end of file