Merge branch 'feature/add-deny-option-for-acl' of git://github.com/BrandtHill/mosquitto into BrandtHill-feature/add-deny-option-for-acl
This commit is contained in:
commit
f18f1a08a9
@ -107,14 +107,16 @@
|
||||
listed will have access. Topic access is added with
|
||||
lines of the format:</para>
|
||||
|
||||
<para><code>topic [read|write|readwrite] <topic></code></para>
|
||||
<para><code>topic [read|write|readwrite|deny] <topic></code></para>
|
||||
|
||||
<para>The access type is controlled using "read", "write" or
|
||||
"readwrite". This parameter is optional (unless
|
||||
<para>The access type is controlled using "read", "write",
|
||||
"readwrite" or "deny". This parameter is optional (unless
|
||||
<topic> includes a space character) - if not
|
||||
given then the access is read/write. <topic> can
|
||||
contain the + or # wildcards as in
|
||||
subscriptions.</para>
|
||||
subscriptions. The "deny" option can used to explicity
|
||||
deny access to a topic that would otherwise be granted
|
||||
by a broader read/write/readwrite statement.</para>
|
||||
|
||||
<para>The first set of topics are applied to anonymous
|
||||
clients, assuming <option>allow_anonymous</option> is
|
||||
@ -131,7 +133,7 @@
|
||||
substitution within the topic. The form is the same as
|
||||
for the topic keyword, but using pattern as the
|
||||
keyword.</para>
|
||||
<para><code>pattern [read|write|readwrite] <topic></code></para>
|
||||
<para><code>pattern [read|write|readwrite|deny] <topic></code></para>
|
||||
|
||||
<para>The patterns available for substition are:</para>
|
||||
<itemizedlist mark="circle">
|
||||
|
@ -217,10 +217,16 @@ int add__acl(struct mosquitto__security_options *security_opts, const char *user
|
||||
/* Add acl to user acl list */
|
||||
if(acl_user->acl){
|
||||
acl_tail = acl_user->acl;
|
||||
while(acl_tail->next){
|
||||
acl_tail = acl_tail->next;
|
||||
if(access == MOSQ_ACL_NONE){
|
||||
/* Put "deny" acls at front of the list */
|
||||
acl->next = acl_tail;
|
||||
acl_user->acl = acl;
|
||||
}else{
|
||||
while(acl_tail->next){
|
||||
acl_tail = acl_tail->next;
|
||||
}
|
||||
acl_tail->next = acl;
|
||||
}
|
||||
acl_tail->next = acl;
|
||||
}else{
|
||||
acl_user->acl = acl;
|
||||
}
|
||||
@ -291,10 +297,16 @@ int add__acl_pattern(struct mosquitto__security_options *security_opts, const ch
|
||||
|
||||
if(security_opts->acl_patterns){
|
||||
acl_tail = security_opts->acl_patterns;
|
||||
while(acl_tail->next){
|
||||
acl_tail = acl_tail->next;
|
||||
if(access == MOSQ_ACL_NONE){
|
||||
/* Put "deny" acls at front of the list */
|
||||
acl->next = acl_tail;
|
||||
security_opts->acl_patterns = acl;
|
||||
}else{
|
||||
while(acl_tail->next){
|
||||
acl_tail = acl_tail->next;
|
||||
}
|
||||
acl_tail->next = acl;
|
||||
}
|
||||
acl_tail->next = acl;
|
||||
}else{
|
||||
security_opts->acl_patterns = acl;
|
||||
}
|
||||
@ -334,7 +346,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
|
||||
acl_root = NULL;
|
||||
}
|
||||
|
||||
/* Loop through all ACLs for this client. */
|
||||
/* Loop through all ACLs for this client. ACL denials are iterated over first. */
|
||||
while(acl_root){
|
||||
/* Loop through the topic looking for matches to this ACL. */
|
||||
|
||||
@ -345,6 +357,10 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
|
||||
}
|
||||
mosquitto_topic_matches_sub(acl_root->topic, topic, &result);
|
||||
if(result){
|
||||
if(acl_root->access == MOSQ_ACL_NONE){
|
||||
/* Access was explicitly denied for this topic. */
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
}
|
||||
if(access & acl_root->access){
|
||||
/* And access is allowed. */
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
@ -374,7 +390,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop through all pattern ACLs. */
|
||||
/* Loop through all pattern ACLs. ACL denial patterns are iterated over first. */
|
||||
if(!context->id) return MOSQ_ERR_ACL_DENIED;
|
||||
clen = strlen(context->id);
|
||||
|
||||
@ -418,6 +434,10 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
|
||||
mosquitto_topic_matches_sub(local_acl, topic, &result);
|
||||
mosquitto__free(local_acl);
|
||||
if(result){
|
||||
if(acl_root->access == MOSQ_ACL_NONE){
|
||||
/* Access was explicitly denied for this topic pattern. */
|
||||
return MOSQ_ERR_ACL_DENIED;
|
||||
}
|
||||
if(access & acl_root->access){
|
||||
/* And access is allowed. */
|
||||
return MOSQ_ERR_SUCCESS;
|
||||
@ -505,6 +525,8 @@ static int aclfile__parse(struct mosquitto_db *db, struct mosquitto__security_op
|
||||
access = MOSQ_ACL_WRITE;
|
||||
}else if(!strcmp(access_s, "readwrite")){
|
||||
access = MOSQ_ACL_READ | MOSQ_ACL_WRITE;
|
||||
}else if(!strcmp(access_s, "deny")){
|
||||
access = MOSQ_ACL_NONE;
|
||||
}else{
|
||||
log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid topic access type \"%s\" in acl_file \"%s\".", access_s, security_opts->acl_file);
|
||||
rc = MOSQ_ERR_INVAL;
|
||||
|
@ -14,12 +14,15 @@ def write_config(filename, port, per_listener):
|
||||
def write_acl(filename, global_en, user_en, pattern_en):
|
||||
with open(filename, 'w') as f:
|
||||
if global_en:
|
||||
f.write('topic readwrite topic/global\n')
|
||||
f.write('topic readwrite topic/global/#\n')
|
||||
f.write('topic deny topic/global/except\n')
|
||||
if user_en:
|
||||
f.write('user username\n')
|
||||
f.write('topic readwrite topic/username\n')
|
||||
f.write('topic readwrite topic/username/#\n')
|
||||
f.write('topic deny topic/username/except\n')
|
||||
if pattern_en:
|
||||
f.write('pattern readwrite pattern/%u\n')
|
||||
f.write('pattern readwrite pattern/%u/#\n')
|
||||
f.write('pattern deny pattern/%u/except\n')
|
||||
|
||||
|
||||
|
||||
@ -77,12 +80,15 @@ def acl_test(port, per_listener, global_en, user_en, pattern_en):
|
||||
if global_en:
|
||||
single_test(port, per_listener, username=None, topic="topic/global", expect_deny=False)
|
||||
single_test(port, per_listener, username="username", topic="topic/global", expect_deny=True)
|
||||
single_test(port, per_listener, username=None, topic="topic/global/except", expect_deny=True)
|
||||
if user_en:
|
||||
single_test(port, per_listener, username=None, topic="topic/username", expect_deny=True)
|
||||
single_test(port, per_listener, username="username", topic="topic/username", expect_deny=False)
|
||||
single_test(port, per_listener, username="username", topic="topic/username/except", expect_deny=True)
|
||||
if pattern_en:
|
||||
single_test(port, per_listener, username=None, topic="pattern/username", expect_deny=True)
|
||||
single_test(port, per_listener, username="username", topic="pattern/username", expect_deny=False)
|
||||
single_test(port, per_listener, username="username", topic="pattern/username/except", expect_deny=True)
|
||||
|
||||
def do_test(port, per_listener):
|
||||
try:
|
||||
|
Loading…
Reference in New Issue
Block a user