[464543] Run default checks after plugins.

This commit is contained in:
Roger A. Light 2015-06-29 23:31:39 +01:00
parent 5c642c9cfd
commit e773ea1bee
6 changed files with 127 additions and 65 deletions

View File

@ -80,9 +80,9 @@
authenticate using the MQTT username/password if using the
password_file option.</para>
<para>Both certificate and PSK based encryption are configured on a per-listener basis.</para>
<para>Authentication plugins can be created to replace the
password_file and psk_file options (as well as the ACL options)
with e.g. SQL based lookups.</para>
<para>Authentication plugins can be created to augment the
password_file, acl_file and psk_file options with e.g. SQL based
lookups.</para>
<para>It is possible to support multiple authentication schemes at
once. A config could be created that had a listener for all of the
different encryption options described above and hence a large
@ -205,6 +205,12 @@
<para>Can be specified multiple times to load multiple
plugins. The plugins will be processed in the order
that they are specified.</para>
<para>If <option>password_file</option>, or
<option>acl_file</option> are used in the config file
alongsize <option>auth_plugin</option>, the plugin
checks will run first. If a plugin is used but neither
of the default password or acl options are used, access
will be denied.</para>
<para>Not currently reloaded on reload signal.</para>
</listitem>
</varlistentry>

View File

@ -528,7 +528,8 @@
# offers very little in the way of security.
#
# See the TLS client require_certificate and use_identity_as_username options
# for alternative authentication options.
# for alternative authentication options. If an auth_plugin is used as well as
# password_file, the auth_plugin check will be made first.
#password_file
# Access may also be controlled using a pre-shared-key file. This requires
@ -536,6 +537,7 @@
# lines in the format:
# identity:key
# The key should be in hexadecimal format without a leading "0x".
# If an auth_plugin is used as well, the auth_plugin check will be made first.
#psk_file
# Control access to topics on the broker using an access control list
@ -585,6 +587,8 @@
#
# pattern write sensor/%u/data
#
# If an auth_plugin is used as well as acl_file, the auth_plugin check will be
# made first.
#acl_file
# -----------------------------------------------------------------
@ -597,7 +601,8 @@
#
# The auth_plugin option can be specified multiple times to load multiple
# plugins. The plugins will be processed in the order that they are specified
# here.
# here. If the auth_plugin option is specified alongside either of
# password_file or acl_file then the plugin checks will be made first.
#
#auth_plugin

View File

@ -38,7 +38,20 @@ struct mosquitto_auth_opt {
*
* Authentication plugins can implement one or both of authentication and
* access control. If your plugin does not wish to handle either of
* authentication or access control it should return MOSQ_ERR_DEFER.
* authentication or access control it should return MOSQ_ERR_DEFER. In this
* case, the next plugin will handle it. If all plugins return MOSQ_ERR_DEFER,
* the request will be denied.
*
* For each check, the following flow happens:
*
* * First plugin does the check, if it returns anything other than
* MOSQ_ERR_DEFER, then the check returns immediately. If the plugin returns
* MOSQ_ERR_DEFER then the next plugin runs its check.
* * If the final plugin returns MOSQ_ERR_DEFER, then the default password file
* and/or acl file check will be made if they are specified in the config
* file.
* * If plugins are defined and the password file and/or acl file are not
* specified, then the request will be denied.
*/
/* =========================================================================
@ -228,7 +241,7 @@ int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char
* Return value:
* Return 0 on success.
* Return >0 on failure.
* Return >0 if this function is not required.
* Return MOSQ_ERR_DEFER if your plugin does not wish to handle this check.
*/
int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len);

61
src/plugin_defer.c Normal file
View File

@ -0,0 +1,61 @@
/*
Copyright (c) 2015 Roger Light <roger@atchoo.org>
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
and Eclipse Distribution License v1.0 which accompany this distribution.
The Eclipse Public License is available at
http://www.eclipse.org/legal/epl-v10.html
and the Eclipse Distribution License is available at
http://www.eclipse.org/org/documents/edl-v10.php.
Contributors:
Roger Light - initial implementation and documentation.
*/
/* This is a skeleton authentication and access control plugin that simply defers all checks. */
#include "mosquitto_plugin.h"
#include "mosquitto.h"
int mosquitto_auth_plugin_version(void)
{
return MOSQ_AUTH_PLUGIN_VERSION;
}
int mosquitto_auth_plugin_init(void **user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count)
{
return MOSQ_ERR_SUCCESS;
}
int mosquitto_auth_plugin_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count)
{
return MOSQ_ERR_SUCCESS;
}
int mosquitto_auth_security_init(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload)
{
return MOSQ_ERR_SUCCESS;
}
int mosquitto_auth_security_cleanup(void *user_data, struct mosquitto_auth_opt *auth_opts, int auth_opt_count, bool reload)
{
return MOSQ_ERR_SUCCESS;
}
int mosquitto_auth_acl_check(void *user_data, const char *clientid, const char *username, const char *topic, int access)
{
return MOSQ_ERR_DEFER;
}
int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char *password)
{
return MOSQ_ERR_DEFER;
}
int mosquitto_auth_psk_key_get(void *user_data, const char *hint, const char *identity, char *key, int max_key_len)
{
return MOSQ_ERR_DEFER;
}

View File

@ -197,18 +197,13 @@ int mosquitto_security_init(struct mosquitto_db *db, bool reload)
int i;
int rc;
if(!db->auth_plugins){
return mosquitto_security_init_default(db, reload);
}else{
for(i=0; i<db->config->auth_plugin_count; i++){
rc = db->auth_plugins[i].security_init(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
for(i=0; i<db->config->auth_plugin_count; i++){
rc = db->auth_plugins[i].security_init(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
}
return MOSQ_ERR_SUCCESS;
return mosquitto_security_init_default(db, reload);
}
/* Apply security settings after a reload.
@ -219,10 +214,7 @@ int mosquitto_security_init(struct mosquitto_db *db, bool reload)
*/
int mosquitto_security_apply(struct mosquitto_db *db)
{
if(!db->auth_plugins){
return mosquitto_security_apply_default(db);
}
return MOSQ_ERR_SUCCESS;
return mosquitto_security_apply_default(db);
}
int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
@ -230,17 +222,13 @@ int mosquitto_security_cleanup(struct mosquitto_db *db, bool reload)
int i;
int rc;
if(!db->auth_plugins){
return mosquitto_security_cleanup_default(db, reload);
}else{
for(i=0; i<db->config->auth_plugin_count; i++){
rc = db->auth_plugins[i].security_cleanup(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
for(i=0; i<db->config->auth_plugin_count; i++){
rc = db->auth_plugins[i].security_cleanup(db->auth_plugins[i].user_data, db->config->auth_plugins[i].options, db->config->auth_plugins[i].option_count, reload);
if(rc != MOSQ_ERR_SUCCESS){
return rc;
}
}
return MOSQ_ERR_SUCCESS;
return mosquitto_security_cleanup_default(db, reload);
}
int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, const char *topic, int access)
@ -252,25 +240,22 @@ int mosquitto_acl_check(struct mosquitto_db *db, struct mosquitto *context, cons
if(!context->id){
return MOSQ_ERR_ACL_DENIED;
}
if(!db->auth_plugins){
return mosquitto_acl_check_default(db, context, topic, access);
}else{
#ifdef WITH_BRIDGE
if(context->bridge){
username = context->bridge->local_username;
}else
if(context->bridge){
username = context->bridge->local_username;
}else
#endif
{
username = context->username;
}
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].acl_check(db->auth_plugins[i].user_data, context->id, username, topic, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
{
username = context->username;
}
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].acl_check(db->auth_plugins[i].user_data, context->id, username, topic, access);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
return MOSQ_ERR_ACL_DENIED;
return mosquitto_acl_check_default(db, context, topic, access);
}
int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const char *password)
@ -278,17 +263,13 @@ int mosquitto_unpwd_check(struct mosquitto_db *db, const char *username, const c
int rc;
int i;
if(!db->auth_plugins){
return mosquitto_unpwd_check_default(db, username, password);
}else{
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].unpwd_check(db->auth_plugins[i].user_data, username, password);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].unpwd_check(db->auth_plugins[i].user_data, username, password);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
return MOSQ_ERR_AUTH;
return mosquitto_unpwd_check_default(db, username, password);
}
int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char *identity, char *key, int max_key_len)
@ -296,16 +277,12 @@ int mosquitto_psk_key_get(struct mosquitto_db *db, const char *hint, const char
int rc;
int i;
if(!db->auth_plugins){
return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len);
}else{
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].psk_key_get(db->auth_plugins[i].user_data, hint, identity, key, max_key_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
for(i=0; i<db->auth_plugin_count; i++){
rc = db->auth_plugins[i].psk_key_get(db->auth_plugins[i].user_data, hint, identity, key, max_key_len);
if(rc != MOSQ_ERR_PLUGIN_DEFER){
return rc;
}
}
return MOSQ_ERR_AUTH;
return mosquitto_psk_key_get_default(db, hint, identity, key, max_key_len);
}

View File

@ -231,7 +231,7 @@ int mosquitto_acl_check_default(struct mosquitto_db *db, struct mosquitto *conte
char *s;
if(!db || !context || !topic) return MOSQ_ERR_INVAL;
if(!db->acl_list && !db->acl_patterns) return MOSQ_ERR_SUCCESS;
if(!db->acl_list && !db->acl_patterns && !db->auth_plugins) return MOSQ_ERR_SUCCESS;
if(context->bridge) return MOSQ_ERR_SUCCESS;
if(!context->acl_list && !db->acl_patterns) return MOSQ_ERR_ACL_DENIED;
@ -639,7 +639,7 @@ int mosquitto_unpwd_check_default(struct mosquitto_db *db, const char *username,
#endif
if(!db) return MOSQ_ERR_INVAL;
if(!db->unpwd) return MOSQ_ERR_SUCCESS;
if(!db->unpwd && !db->auth_plugins) return MOSQ_ERR_SUCCESS;
if(!username) return MOSQ_ERR_INVAL; /* Check must be made only after checking db->unpwd. */
HASH_ITER(hh, db->unpwd, u, tmp){