mosquitto ---mosquitto-auth-plug

本文介绍了一种用于Mosquitto MQTT代理的插件,该插件能够从多种后端(如MySQL、PostgreSQL、Redis等)进行用户身份验证和授权。插件支持复杂的权限检查和超级用户功能,同时提供了缓存机制以提高性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://github.com/jpmens/mosquitto-auth-plug

This is a plugin to authenticate and authorize Mosquitto users from one of several distinct back-ends:

  • MySQL
  • PostgreSQL
  • CDB
  • SQLite3 database
  • Redis key/value store
  • TLS PSK (the psk back-end is a bit of a shim which piggy-backs onto the other database back-ends)
  • LDAP
  • HTTP (custom HTTP API)
  • JWT
  • MongoDB
  • Files

Introduction

This plugin can perform authentication (check username / password) and authorization (ACL). Currently not all back-ends have the same capabilities (the the section on the back-end you're interested in).

CapabilitymysqlrediscdbsqliteldappskpostgreshttpjwtMongoDBFiles
authenticationYYYYYYYYYYY
superusersY    3YYYYN
acl checkingY122 3YYYYY
static superusersYYYY 3YYYYY
  1. Topic wildcards (+/#) are not supported
  2. Currently not implemented; back-end returns TRUE
  3. Dependent on the database used by PSK

Multiple back-ends can be configured simultaneously for authentication, and they're attempted in the order you specify. Once a user has been authenticated, the same back-end is used to check authorization (ACLs). Superusers are checked for in all back-ends. The configuration option is called auth_opt_backends and it takes a comma-separated list of back-end names which are checked in exactly that order.

auth_opt_backends cdb,sqlite,mysql,redis,postgres,http,jwt,mongo

  Note: anonymous MQTT connections are assigned a username of configured in the plugin as auth_opt_anonusername and they are handled by a so-called fallback back-end which is the first configured back-end.

Passwords are obtained from the back-end as a PBKDF2 string (see section on Passwords below). Even if you try and store a clear-text password, it simply won't work.

The mysql and mongo back-ends support expansion of %c and %u as clientid and username respectively. This allows ACLs in the database to look like this:

+-----------+---------------------------------+----+
| username  | topic                           | rw |
+-----------+---------------------------------+----+
| bridge-01 | $SYS/broker/connection/%c/state |  2 |
+-----------+---------------------------------+----+

The plugin supports so-called superusers. These are usernames exempt from ACL checking. In other words, if a user is a superuser, that user doesn't require ACLs.

A static superuser is one configured with the fnmatch(3) auth_opt_superusers option. The other 'superusers' are configured (i.e. enabled) from within the particular database back-end. Effectively both are identical in that ACL checking is disabled if a user is a superuser.

Note that not all back-ends currently have 'superuser' queries implemented. todo. At that point the auth_opt_superusers will probably disappear.

Building the plugin

In order to compile the plugin you'll require a copy of the Mosquitto source code together with the libraries required for the back-end you want to use in the plugin. OpenSSL is also required.

Copy config.mk.in to config.mk and modify config.mk to suit your building environment, in particular, you have to configure which back-ends you want to provide as well as the path to the Mosquitto source and its library.

After a make you should have a shared object called auth-plug.so which you will reference in your mosquitto.conf.

Note that OpenSSL as shipped with OS X is probably too old. You may wish to use a version supplied by home brew or build your own, and then adapt OPENSSLDIR in config.mk.

Configuration

The plugin is configured in Mosquitto's configuration file (typically mosquitto.conf), and it is loaded into Mosquitto auth the auth_plugin option.

auth_plugin /path/to/auth-plug.so

Options therein with a leading auth_opt_ are handed to the plugin. The following "global" auth_opt_* plugin options exist:

OptiondefaultMandatoryMeaning
backends Ycomma-separated list of back-ends to load
superusers  fnmatch(3) case-sensitive string
log_quietfalse don't log DEBUG messages
cacheseconds  Deprecated. Alias for acl_cacheseconds
acl_cacheseconds300 number of seconds to cache ACL lookups. 0 disables
auth_cacheseconds0 number of seconds to cache AUTH lookups. 0 disables
acl_cachejitter0 maximum number of seconds to add/remove to ACL lookups cache TTL. 0 disables
auth_cachejitter0 maximum number of seconds to add/remove to AUTH lookups cache TTL. 0 disables
=======   

Individual back-ends have their options described in the sections below.

There are two caches, one for ACL and another for authentication. By default only the ACL cache is enabled.

After a backend responds (postitively or negatively) for an ACL or AUTH lookup, the result will be kept in cache for the configured TTL, the same ACL lookup will be served from the cache as long as the TTL is valid. The configured TTL is the auth/acl_cacheseconds combined with a random value between -auth/acl_cachejitter and +auth/acl_cachejitter. For example, with an acl_cacheseconds of 300 and acl_cachejitter of 10, ACL lookup TTL are distributed between 290 and 310 seconds.

Set auth/acl_cachejitter to 0 disable any randomization of cache TTL. Settings auth/acl_cacheseconds to 0 disable caching entirely. Caching is useful when your backend lookup is expensive. Remember that ACL lookup will be performed for each message which is sent/received on a topic. Jitter is useful to reduce lookup storms that could occur every auth/acl_cacheseconds if lots of clients connect at the same time (for example after a server restart, all your clients may reconnect immediately and all may cause ACL lookups every acl_cacheseconds).

MySQL

The mysql back-end is currently the most feature-complete: it supports obtaining passwords, checking for superusers, and verifying ACLs by configuring up to three distinct SQL queries used to obtain those results.

You configure the SQL queries in order to adapt to whichever schema you currently have.

The following auth_opt_ options are supported by the mysql back-end:

OptiondefaultMandatoryMeaning
hostlocalhost hostname/address
port3306 TCP port
user  username
pass  password
dbname Ydatabase name
userquery YSQL for users
superquery  SQL for superusers
aclquery  SQL for ACLs
mysql_opt_reconnecttrue enable MYSQL_OPT_RECONNECT option
mysql_auto_connecttrue enable auto_connect function
anonusernameanonymous username to use for anonymous connections
ssl_enabledfalse enable SSL
ssl_key  path name of client private key file
ssl_cert  path name of client public key certificate file
ssl_ca  path name of Certificate Authority(CA) certificate file
ssl_capath  path name of directory that contains trusted CA certifcate files
ssl_cipher  permitted ciphers for SSL encryption

The SQL query for looking up a user's password hash is mandatory. The query MUST return a single row only (any other number of rows is considered to be "user not found"), and it MUST return a single column only with the PBKDF2 password hash. A single '%s' in the query string is replaced by the username attempting to access the broker.

SELECT pw FROM users WHERE username = '%s' LIMIT 1

The SQL query for checking whether a user is a superuser - and thus circumventing ACL checks - is optional. If it is specified, the query MUST return a single row with a single value: 0 is false and 1 is true. We recommend using a SELECT IFNULL(COUNT(*),0) FROM ... for this query as it satisfies both conditions. ). A single '%s' in the query string is replaced by the username attempting to access the broker. The following example uses the same users table, but it could just as well reference a distinct table or view.

SELECT IFNULL(COUNT(*), 0) FROM users WHERE username = '%s' AND super = 1

The SQL query for checking ACLs is optional, but if it is specified, the mysql back-end can try to limit access to particular topics or topic branches depending on the value of a database table. The query MAY return zero or more rows for a particular user, each returning EXACTLY one column containing a topic (wildcards are supported). A single '%s' in the query string is replaced by the username attempting to access the broker, and a single '%d' is replaced with the integer value 1 signifying a read-only access attempt (SUB) or 2 signifying a read-write access attempt (PUB).

In the following example, the table has an INT(1) column rw containing 1 for readonly topics, and 2 for read-write topics:

SELECT topic FROM acls WHERE (username = '%s') AND (rw >= %d)

Mosquitto configuration for the mysql back-end:

auth_plugin /home/jpm/mosquitto-auth-plug/auth-plug.so
auth_opt_host localhost
auth_opt_port 3306
auth_opt_dbname test
auth_opt_user jjj
auth_opt_pass supersecret
auth_opt_userquery SELECT pw FROM users WHERE username = '%s'
auth_opt_superquery SELECT COUNT(*) FROM users WHERE username = '%s' AND super = 1
auth_opt_aclquery SELECT topic FROM acls WHERE (username = '%s') AND (rw >= %d)
auth_opt_anonusername AnonymouS

Assuming the following database tables:

mysql> SELECT * FROM users;
+----+----------+---------------------------------------------------------------------+-------+
| id | username | pw                                                                  | super |
+----+----------+---------------------------------------------------------------------+-------+
|  1 | jjolie   | PBKDF2$sha256$901$x8mf3JIFTUFU9C23$Mid2xcgTrKBfBdye6W/4hE3GKeksu00+ |     0 |
|  2 | a        | PBKDF2$sha256$901$XPkOwNbd05p5XsUn$1uPtR6hMKBedWE44nqdVg+2NPKvyGst8 |     0 |
|  3 | su1      | PBKDF2$sha256$901$chEZ4HcSmKtlV0kf$yRh2N62uq6cHoAB6FIrxIN2iihYqNIJp |     1 |
+----+----------+---------------------------------------------------------------------+-------+

mysql> SELECT * FROM acls;
+----+----------+-------------------+----+
| id | username | topic             | rw |
+----+----------+-------------------+----+
|  1 | jjolie   | loc/jjolie        |  1 |
|  2 | jjolie   | $SYS/something    |  1 |
|  3 | a        | loc/test/#        |  1 |
|  4 | a        | $SYS/broker/log/+ |  1 |
|  5 | su1      | mega/secret       |  1 |
|  6 | nop      | mega/secret       |  1 |
+----+----------+-------------------+----+

the above SQL queries would enable the following combinations (note the * at the beginning of the line indicating a superuser)

  jjolie     PBKDF2$sha256$901$x8mf3JIFTUFU9C23$Mid2xcgTrKBfBdye6W/4hE3GKeksu00+
	loc/a                                    DENY
	loc/jjolie                               PERMIT
	mega/secret                              DENY
	loc/test                                 DENY
	$SYS/broker/log/N                        DENY
  nop        <nil>
	loc/a                                    DENY
	loc/jjolie                               DENY
	mega/secret                              PERMIT
	loc/test                                 DENY
	$SYS/broker/log/N                        DENY
  a          PBKDF2$sha256$901$XPkOwNbd05p5XsUn$1uPtR6hMKBedWE44nqdVg+2NPKvyGst8
	loc/a                                    DENY
	loc/jjolie                               DENY
	mega/secret                              DENY
	loc/test                                 PERMIT
	$SYS/broker/log/N                        PERMIT
* su1        PBKDF2$sha256$901$chEZ4HcSmKtlV0kf$yRh2N62uq6cHoAB6FIrxIN2iihYqNIJp
	loc/a                                    PERMIT
	loc/jjolie                               PERMIT
	mega/secret                              PERMIT
	loc/test                                 PERMIT
	$SYS/broker/log/N                        PERMIT

The mysql back-end will re-connect to the MySQL server when the connection has gone away. If you wish, you can disable this by configuring:

auth_opt_mysql_opt_reconnect false
auth_opt_mysql_auto_connect false

LDAP

The LDAP plugin currently does authentication only; authenticated users are allowed to publish/subscribe at will.

The user with which Mosquitto connects to the broker is searched in the LDAP directory via the ldap_uri configuration parameter. This LDAP search MUST return exactly one entry. The user's password is then use with the DN of the entry found to bind to the directory. If that LDAP bind succeeds, the user is authenticated. In other cases, authentication fails.

OptiondefaultMandatoryMeaning
binddn Ythe DN of an object which may search users
bindpw Yits password
ldap_uri Yan LDAP uri with filter

Example configuration:

auth_plugin /path/to/auth-plug.so
auth_opt_backends ldap
auth_opt_binddn cn=manager,dc=mens,dc=de
auth_opt_bindpw s3crit
auth_opt_ldap_uri ldap://127.0.0.1/ou=Users,dc=mens,dc=de?cn?sub?(&(objectclass=inetOrgPerson)(uid=@))

CDB

OptiondefaultMandatoryMeaning
cdbname Ypath to .cdb

SQLITE

OptiondefaultMandatoryMeaning
dbpath Ypath to database
sqliteuserquery YSQL for users

Example:

auth_opt_sqliteuserquery SELECT pw FROM users WHERE username = ?

Redis

auth_opt_redis_userquery GET %s
auth_opt_redis_aclquery GET %s-%s

In auth_opt_redis_userquery the parameter is the username, whereas in auth_opt_redis_aclquery, the first parameter is the username and the second is the topic. When using ACLS topic must be an exact match - wildcards are not supported.

If no options are provided then it will default to not using an ACL and using the above userquery.

OptiondefaultMandatoryMeaning
redis_hostlocalhost hostname / IP address
redis_port6379 TCP port number

HTTP

The http back-end is for auth by custom HTTP API.

The following auth_opt_ options are supported by the http back-end:

OptiondefaultMandatoryMeaning
http_ip YIP address,will skip dns lookup
http_port80 TCP port number
http_hostname  hostname for HTTP header
http_getuser_uri YURI for check username/password
http_superuser_uri YURI for check superuser
http_aclcheck_uri YURI for check acl
http_with_tlsfalseNUse TLS on connect
http_basic_auth_key NBasic Authentication Key
http_retry_count3NNumber of retries done if backend is unavailable

If the configured URLs return an HTTP status code == 2xx, the authentication / authorization succeeds. If the status code == 4xx authentication / authorization fails. For status code == 5xx or server unreachable, the HTTP request will be retried up to http_retry_count. If all tries fail and if no other backend succeeded, then an error is returned and client is disconnected.

URI-Paramusernamepasswordclientidtopicacc
http_getuser_uriYYNNN
http_superuser_uriYNNNN
http_aclcheck_uriYNYYY

Mosquitto configuration for the http back-end:

auth_opt_backends http
auth_opt_http_ip 127.0.0.1
auth_opt_http_port 8089
#auth_opt_http_hostname example.org
auth_opt_http_getuser_uri /auth
auth_opt_http_superuser_uri /superuser
auth_opt_http_aclcheck_uri /acl

A very simple example service using Python and bottle can be found in examples/http-auth-be.py.

The http plugin can utilize environment variables which are exported before it (i.e. Mosquitto) is started by adding configuration settings like

auth_opt_<interface>_<method>_params <key>=<evn_name>[,<key>=<evn_name>]*

For example, set the following:

export DOMAIN=example.com
export PORT=8080

and add the following settings to mosquitto.conf:

auth_opt_http_getuser_params domain=DOMAIN,port=PORT
auth_opt_http_superuser_params domain=DOMAIN,port=PORT
auth_opt_http_aclcheck_params domain=DOMAIN,port=PORT

JWT

The jwt back-end is for auth by JWT-webtokens. The JWT and HTTP configurations are identical, so please read the http-section above.

The username-field is interpreted as the token-field and passed to the http-server in an Authorization-header.

Authorization: Bearer %token

Note: Some clients require the password-field to be populated. This field is ignored by the JWT-backend, so feel free to input some gibberish.

PostgreSQL

The postgres like mysql back-end is currently the most feature-complete: it supports obtaining passwords, checking for superusers, and verifying ACLs by configuring up to three distinct SQL queries used to obtain those results.

You configure the SQL queries in order to adapt to whichever schema you currently have.

The following auth_opt_ options are supported by the mysql back-end:

OptiondefaultMandatoryMeaning
hostlocalhost hostname/address
port5432 TCP port
user  username
pass  password
dbname Ydatabase name
userquery YSQL for users
superquery  SQL for superusers
aclquery  SQL for ACLs
sslcert  SSL/TLS Client Cert.
sslkey  SSL/TLS Client Cert. Key

The SQL query for looking up a user's password hash is mandatory. The query MUST return a single row only (any other number of rows is considered to be "user not found"), and it MUST return a single column only with the PBKDF2 password hash. A single '$1' in the query string is replaced by the username attempting to access the broker.

SELECT pass FROM account WHERE username = $1 limit 1

The SQL query for checking whether a user is a superuser - and thus circumventing ACL checks - is optional. If it is specified, the query MUST return a single row with a single value: 0 is false and 1 is true. We recommend using a SELECT COALESCE(COUNT(*),0) FROM ... for this query as it satisfies both conditions. ). A single '$1' in the query string is replaced by the username attempting to access the broker. The following example uses the same users table, but it could just as well reference a distinct table or view.

SELECT COALESCE(COUNT(*),0) FROM account WHERE username = $1 AND super = 1

The SQL query for checking ACLs is optional, but if it is specified, the mysql back-end can try to limit access to particular topics or topic branches depending on the value of a database table. The query MAY return zero or more rows for a particular user, each returning EXACTLY one column containing a topic (wildcards are supported). A single '$1' in the query string is replaced by the username attempting to access the broker, and a single '$2' is replaced with the integer value 1 signifying a read-only access attempt (SUB) or 2 signifying a read-write access attempt (PUB).

In the following example, the table has a column rw containing 1 for readonly topics, 2 for writeonly topics and 3 for readwrite topics:

SELECT topic FROM acl WHERE (username = $1) AND rw >= $2

Mosquitto configuration for the postgres back-end:

auth_plugin /home/jpm/mosquitto-auth-plug/auth-plug.so
auth_opt_host localhost
auth_opt_port 5432
auth_opt_dbname test
auth_opt_user jjj
auth_opt_pass supersecret
auth_opt_userquery SELECT pw FROM account WHERE username = $1 limit 1
auth_opt_superquery SELECT COALESCE(COUNT(*),0) FROM account WHERE username = $1 AND mosquitto_super = 1
auth_opt_aclquery SELECT topic FROM acls WHERE (username = $1) AND (rw & $2) > 0
auth_opt_sslcert /etc/postgresql/ssl/client.crt
auth_opt_sslkey /etc/postgresql/ssl/client.key

Assuming the following database tables:

=> SELECT * FROM account;
+----+----------+---------------------------------------------------------------------+-------+
| id | username | pw                                                                  | super |
+----+----------+---------------------------------------------------------------------+-------+
|  1 | jjolie   | PBKDF2$sha256$901$x8mf3JIFTUFU9C23$Mid2xcgTrKBfBdye6W/4hE3GKeksu00+ |     0 |
|  2 | a        | PBKDF2$sha256$901$XPkOwNbd05p5XsUn$1uPtR6hMKBedWE44nqdVg+2NPKvyGst8 |     0 |
|  3 | su1      | PBKDF2$sha256$901$chEZ4HcSmKtlV0kf$yRh2N62uq6cHoAB6FIrxIN2iihYqNIJp |     1 |
+----+----------+---------------------------------------------------------------------+-------+

=> SELECT * FROM acls;
+----+----------+-------------------+----+
| id | username | topic             | rw |
+----+----------+-------------------+----+
|  1 | jjolie   | loc/jjolie        |  1 |
|  2 | jjolie   | $SYS/something    |  1 |
|  3 | a        | loc/test/#        |  1 |
|  4 | a        | $SYS/broker/log/+ |  1 |
|  5 | su1      | mega/secret       |  1 |
|  6 | nop      | mega/secret       |  1 |
+----+----------+-------------------+----+

the above SQL queries would enable the following combinations (note the * at the beginning of the line indicating a superuser)

  jjolie     PBKDF2$sha256$901$x8mf3JIFTUFU9C23$Mid2xcgTrKBfBdye6W/4hE3GKeksu00+
  loc/a                                    DENY
  loc/jjolie                               PERMIT
  mega/secret                              DENY
  loc/test                                 DENY
  $SYS/broker/log/N                        DENY
  nop        <nil>
  loc/a                                    DENY
  loc/jjolie                               DENY
  mega/secret                              PERMIT
  loc/test                                 DENY
  $SYS/broker/log/N                        DENY
  a          PBKDF2$sha256$901$XPkOwNbd05p5XsUn$1uPtR6hMKBedWE44nqdVg+2NPKvyGst8
  loc/a                                    DENY
  loc/jjolie                               DENY
  mega/secret                              DENY
  loc/test                                 PERMIT
  $SYS/broker/log/N                        PERMIT
* su1        PBKDF2$sha256$901$chEZ4HcSmKtlV0kf$yRh2N62uq6cHoAB6FIrxIN2iihYqNIJp
  loc/a                                    PERMIT
  loc/jjolie                               PERMIT
  mega/secret                              PERMIT
  loc/test                                 PERMIT
  $SYS/broker/log/N                        PERMIT

MongoDB

The mongo back-end works with superuser and ACL checks. Additional build dependencies are https://github.com/mongodb/mongo-c-driver >=1.4.0 and https://github.com/mongodb/libbson >=1.4.0.

You should set up a users collection (required) and a topic lists collection (optional) with the following format:

Users collection

Each user document must have a username, a hashed password, and at least one of:

  • A superuser prop, allowing full access to all topics
  • An embedded array or sub-document to use as an ACL (see 'ACL format')
  • A foreign key pointing to another document containing an ACL (see 'ACL format')

You may use any combination of these options; authorisation will be granted if any check passes.

The user document has the following format (note that the property names are configurable variables, see 'Configuration').

{
    [user_username_prop]: string, // Username as given in the MQTT connect request
    [user_password_prop]: string, // A PBKDF2 hash, see 'Passwords' section
    [user_topiclist_fk_prop]: int | oid | string, // reference to a document in collection_topics)
    [user_topics_prop]: string[] | { [topic: string]: "r"|"w"|"rw" }, // see 'ACL format'
    [user_superuser_prop]: int | boolean // optional, superuser if truthy
}

As an example using default options, a user document with an embedded ACL might look like:

{
    "username": "user1", "password": "PBKDF2$sha256$901$8ebTR72Pcmjl3cYq$SCVHHfqn9t6Ev9sE6RMTeF3pawvtGqTu", "superuser": false, "topics": { "public/#": "r", "client/user1/#": "rw" } }
Topic lists collection (optional)

If the user document references a separate topics document, that document should exist and must have the format:

{
    [topiclist_key_prop]: int | oid | string, // unique id, as referenced by users[user_topiclist_fk_prop],
    [topiclist_topics_prop]: string[] | { [topic: string]: "r"|"w"|"rw" } // see 'ACL format'
}

This strategy will be especially suitable if you have a complex ACL shared between many users.

ACL format

Topics may be given as either an array of topic strings, eg ["topic1/#", "topic2/+"], in which case all topics will be read-write, or as a sub-document mapping topic names to the strings "r""w""rw", eg { "article/#":"r", "article/+/comments":"rw", "ballotbox":"w" }.

Configuration

The following auth_opt_mongo_ options are supported by the mongo back-end:

OptiondefaultMeaning
urimongodb://localhost:27107MongoDB connection string (database part is ignored)
databasemqGateName of the database containing users (and topiclists)
user_collusersCollection for user documents
topiclist_colltopicsCollection for topiclist documents (optional if embedded topics are used)
user_username_propusernameUsername property name in the user document
user_password_proppasswordPassword property name in the user document
user_superuser_propsuperuserSuperuser property name in the user document
user_topics_proptopicsName of a property on the user document containing an embedded topic list
user_topiclist_fk_proptopicsProperty used as a foreign key to reference a topiclist document
topiclist_key_prop_idUnique key in the topiclist document pointed to by user_topiclist_fk_prop
topiclist_topics_proptopicsProperty containing topics within the topiclist document

Mosquitto configuration for the mongo back-end:

auth_plugin /home/jpm/mosquitto-auth-plug/auth-plug.so
auth_opt_mongo_uri mongodb://localhost:27017

Files

The files backend attempts to re-implement the files behavior in vanilla Mosquitto, however the user's password file contains PBKDF2 passwords instead of passwords hashed with the mosquitto-passwd program; you would use our np utility or similar to create the PBKDF2 hashes.

The configuration directives for the Files backend are as follows:

auth_opt_backends files
auth_opt_password_file file.pw
auth_opt_acl_file file.acl

with examples of these files being:

password_file
# comment
jpm:PBKDF2$sha256$901$UGfDz79cAaydRsEF$XvYwauPeviFd1NfbGL+dxcn1K7BVfMeW
jane:PBKDF2$sha256$901$wvvH0fe7Ftszt8nR$NZV6XWWg01dCRiPOheVNsgMJDX1mzd2v
acl_file
user jane
topic read #

user jpm
topic dd

The syntax for the ACL file is that as described in mosquitto.conf(5).

Passwords

A user's password is stored as a PBKDF2 hash in the back-end. An example "password" is a string with five pieces in it, delimited by $, inspired by this.

PBKDF2$sha256$901$8ebTR72Pcmjl3cYq$SCVHHfqn9t6Ev9sE6RMTeF3pawvtGqTu
--^--- --^--- -^- ------^--------- -------------^------------------
  |      |     |        |                       |
  |      |     |        |                       +-- : hashed password
  |      |     |        +-------------------------- : salt
  |      |     +----------------------------------- : iterations
  |      +----------------------------------------- : hash function
  +------------------------------------------------ : marker

Note that the salt by default will be taken as-is (thus it will not be base64 decoded before the validation). In case your own implementation uses the raw bytes when hashing the password and base64 is only used for display purpose, compile this project with the -DRAW_SALT flag (you could add this in the config.mk file to CFG_CFLAGS).

Creating a user

A trivial utility to generate hashes is included as np. Copy and paste the whole string generated into the respective back-end.

$ np
Enter password:
Re-enter same password:
PBKDF2$sha256$901$Qh18ysY4wstXoHhk$g8d2aDzbz3rYztvJiO3dsV698jzECxSg

For example, in Redis:

$ redis-cli
> SET n2 PBKDF2$sha256$901$Qh18ysY4wstXoHhk$g8d2aDzbz3rYztvJiO3dsV698jzECxSg
> QUIT

Configure Mosquitto

listener 1883

auth_plugin /path/to/auth-plug.so
auth_opt_redis_host 127.0.0.1
auth_opt_redis_port 6379

# Usernames with this fnmatch(3) (a.k.a glob(3))  pattern are exempt from the
# module's ACL checking
auth_opt_superusers S*

ACL

In addition to ACL checking which is possibly performed by a back-end, there's a more "static" checking which can be configured in mosquitto.conf.

Note that if ACLs are being verified by the plugin, this also applies to Will topics (last will and testament). Failing to correctly set up an ACL for these, will cause a broker to silently fail with a 'not authorized' message.

Users can be given "superuser" status (i.e. they may access any topic) if their username matches the glob specified in auth_opt_superusers.

In our example above, any user with a username beginning with a capital "S" is exempt from ACL-checking.

PUB/SUB

At this point you ought to be able to connect to Mosquitto.

mosquitto_pub  -t '/location/n2' -m hello -u n2 -P secret

PSK

If Mosquitto has been built with PSK support, and auth-plug has been built with BE_PSK defined, it supports authenticating PSK connections over TLS, as long as Mosquitto is appropriately configured.

The way this works is that the psk back-end actually uses one of auth-plug's other databases (mysqlsqlitecdb, etc.) to obtain the pre-shared key from the "users" query, and it uses the same database's back-end for performing authorization (aka ACL checks).

Consider the following mosquitto.conf snippet:

...
auth_opt_psk_database mysql
...
listener 8885
psk_hint hint1
tls_version tlsv1
use_identity_as_username true

TLS PSK is available on port 8885 and is activated with, say,

mosquitto_pub -h localhost -p 8885 -t x -m hi --psk-identity ps2 --psk 020202

The use_identity_as_username option has auth-plug see the name ps2 as the username, and this is given to the database back-end (here: mysql) to look up the password as defined for the mysql back-end. auth-plug uses its getuser() query to read the clear-text (not PKBDF2) hex key string which it returns to Mosquitto for authentication. If authentication passes, the connection is established.

For authorization, auth_plug uses the identity as the username and the topic to perform ACL-checking as described earlier.

The following log-snippet serves as an illustration:

New connection from ::1 on port 8885.
|-- psk_key_get(hint1, ps1) from [mysql] finds PSK: 1
New client connected from ::1 as mosqpub/90759-tiggr.ww. (c1, k60).
Sending CONNACK to mosqpub/90759-tiggr.ww. (0)
|-- user ps1 was authenticated in back-end 0 (psk)
|--   mysql: topic_matches(x, x) == 1
|-- aclcheck(ps1, x, 2) AUTHORIZED=1 by psk
Received PUBLISH from mosqpub/90759-tiggr.ww. (d0, q0, r0, m0, 'x', ... (2 bytes))
Received DISCONNECT from mosqpub/90759-tiggr.ww.

Requirements

  • hiredis, the Minimalistic C client for Redis
  • OpenSSL (tested with 1.0.0c, but should work with earlier versions)
  • Mosquitto broker
  • Redis server
  • MySQL
  • TinyCDB by Michael Tokarev (included in contrib/).

Credits

  • Uses base64.[ch] (and yes, I know OpenSSL has base64 routines, but no thanks). These files are

Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan (Royal Institute of Technology, Stockholm, Sweden).

  • Uses [uthash][2] by Troy D. Hanson.

Possibly related

Press




<think>我们正在解决Mosquitto加载身份验证插件时出现的错误:authpluginloaderror'找不到指定的模块'根据引用[3]中的内容,我们注意到编译mosquitto时使用了`-DWITH_WEBSOCKETS=ON`选项,但未明确提及如何加载身份验证插件。而引用[2]提到了使用mosquitto-auth-plug插件进行身份验证,该插件支持多种数据库。错误信息“找不到指定的模块”通常表示动态链接库(DLL)或共享库文件缺失或路径不正确。在Windows上,这可能是由于缺少DLL文件;在Linux上,可能是共享库(如.so文件)的问题。由于引用[3]的步骤是在Linux环境下(例如CentOS)编译安装Mosquitto,因此我们假设问题出现在Linux环境中。在Linux中,这种错误通常是因为:1.插件文件(.so文件)未放置在Mosquitto的插件目录中,或者Mosquitto配置文件中指定的路径不正确。2.插件依赖的库未安装或不在动态链接器搜索路径中。解决方案:1.确认插件文件路径是否正确:在mosquitto.conf中,配置插件路径的指令是`plugin`。例如:```iniplugin/path/to/mosquitto_auth_plugin.so```确保路径指向正确的.so文件。如果使用mosquitto-auth-plug,那么编译后生成的插件文件通常是`auth-plug.so`(或类似名称)。2.检查插件文件的权限和所有权:确保mosquitto用户(在引用[3]中创建了mosquitto用户)有权限读取该文件。3.检查依赖库:使用`ldd`命令检查插件所需的共享库是否都已安装。例如:```bashldd/path/to/mosquitto_auth_plugin.so```如果显示有库缺失(显示为“notfound”),则需要安装相应的库。4.环境变量`LD_LIBRARY_PATH`:如果依赖库安装在非标准路径(如`/usr/local/lib`),则需要将该路径添加到`LD_LIBRARY_PATH`中。也可以在运行mosquitto之前设置:```bashexportLD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH```或者,可以将该路径添加到系统的库配置中(例如,创建文件`/etc/ld.so.conf.d/mylib.conf`并运行`ldconfig`)。5.编译插件时的依赖:根据引用[2]中mosquitto-auth-plug的要求,编译该插件需要安装一些依赖库,如OpenSSL、MySQL(如果使用MySQL作为后端)等。请确保在编译插件之前已经安装了这些依赖。6.重新编译插件:如果插件是自行编译的,确保编译过程正确,没有错误。注意:插件版本需要与Mosquitto版本兼容。7.检查mosquitto的编译选项:在编译Mosquitto时,如果需要支持动态加载插件,必须启用插件支持。在引用[3]的编译步骤中,我们使用了:```bashcmake-DWITH_WEBSOCKETS=ON...```但没有提到`WITH_AUTH_PLUGIN`或类似选项。实际上,Mosquitto从1.5版本开始支持动态加载插件,默认应该已经启用。但为了确保,可以查看编译时的输出或者尝试重新编译Mosquitto并明确开启插件支持(如果有相关选项)。8.查看Mosquitto日志:在启动mosquitto时使用`-v`参数(详细模式)或者查看日志文件(在引用[3]中配置了日志路径`/var/log/mosquitto`),可以获取更详细的错误信息。针对引用[3]中的步骤,我们注意到在编译mosquitto之前先编译了cJSON和libwebsockets,但并没有编译mosquitto-auth-plug的步骤。所以,如果我们要使用mosquitto-auth-plug,需要额外编译这个插件。编译mosquitto-auth-plug的步骤(参考其GitHub仓库的说明)通常如下:1.安装依赖(如git、gcc、make、libssl-dev等)2.克隆仓库:`gitclonehttps://github.com/jpmens/mosquitto-auth-plug.git`3.进入目录,复制配置文件模板:`cpconfig.mk.inconfig.mk`4.编辑config.mk,设置后端(如MYSQL)和库路径5.执行`make`编译后,会生成一个`auth-plug.so`文件(或其他类似名称),然后在mosquitto.conf中配置这个文件。总结解决步骤:如果是在Linux环境下,我们可以按照以下步骤操作:步骤1:确认插件文件存在且路径正确步骤2:在mosquitto.conf中配置插件(使用绝对路径)步骤3:设置环境变量LD_LIBRARY_PATH(如果需要)步骤4:检查依赖库(使用ldd)步骤5:重新启动mosquitto服务(并查看日志)注意:在引用[3]中,编译mosquitto时使用了自定义的安装路径(通过cmake的`-DCMAKE_PREFIX_PATH`),这可能会影响库的搜索路径。因此,确保插件所需的库在`/usr/local/lib`下或者已经添加到`LD_LIBRARY_PATH`中。如果上述步骤仍然不能解决问题,请提供更多信息,例如:-操作系统的具体版本-mosquitto-auth-plug的编译配置(config.mk)和编译日志-mosquitto的详细日志(使用`mosquitto-c/etc/mosquitto/mosquitto.conf-v`运行)另外,引用[4]是一个在CentOS7上安装和配置Mosquitto的教程,也可以参考其关于安全(包括认证插件)的部分。这里我们提供一个在Linux系统(以CentOS为例)上解决该问题的步骤示例:假设我们已经按照引用[3]的步骤编译安装好了mosquitto,现在要编译并加载mosquitto-auth-plug:1.安装依赖:```bashsudoyuminstallgitgccmakeopenssl-develmariadb-devel#如果有其他后端需求,安装相应的开发包```2.克隆并编译mosquitto-auth-plug:```bashgitclonehttps://github.com/jpmens/mosquitto-auth-plug.gitcdmosquitto-auth-plugcpconfig.mk.inconfig.mk```编辑config.mk,设置要使用的后端(例如MYSQL)和路径。例如:```#指定后端BACKEND_CDB?=noBACKEND_MYSQL?=yesBACKEND_SQLITE?=noBACKEND_REDIS?=no...#库和头文件的路径(根据实际情况修改)MYSQL_CFLAGS?=$(shellmysql_config--cflags)MYSQL_LIBS?=$(shellmysql_config--libs)```然后编译:```bashmake```编译成功后,在目录下会生成`auth-plug.so`文件。3.将`auth-plug.so`复制到mosquitto的插件目录(如`/etc/mosquitto/plugins`)或自定义目录,然后在mosquitto.conf中加载:```iniplugin/etc/mosquitto/plugins/auth-plug.so```4.配置插件所需的认证后端(如MySQL的用户名密码表),具体参考mosquitto-auth-plug的文档。5.设置环境变量(如果依赖库不在标准路径):在启动mosquitto之前,可以设置:```bashexportLD_LIBRARY_PATH=/usr/local/mysql/lib:$LD_LIBRARY_PATH#如果MySQL库在非标准路径```或者,将其添加到systemd服务文件中(如果mosquitto作为服务运行)。6.检查共享库依赖:```bashldd/etc/mosquitto/plugins/auth-plug.so```确保所有库都找到。7.修改mosquitto.conf,配置插件所需的认证选项(例如指定数据库连接信息),然后重启mosquitto服务。8.查看日志文件(在引用[3]中配置的`/var/log/mosquitto`),或者直接运行(调试时):```bashmosquitto-c/etc/mosquitto/mosquitto.conf-v```如果问题仍然存在,请根据错误日志进行排查。注意:错误“找不到指定的模块”在Windows中常见,如果在Windows上遇到该错误,则需要确保编译出的DLL文件及其依赖的DLL文件(如OpenSSL的DLL)都在PATH环境变量指定的路径中,或者与mosquitto.exe在同一目录。但引用中提到的编译步骤都是在Linux环境下,因此此处重点处理Linux环境。以上步骤应该能够解决大部分由于插件加载路径或依赖库缺失导致的问题。</think> ### Mosquitto 2.0.18 认证插件加载错误解决方案 针对您遇到的错误 `auth plugin load error '找不到指定的模块'`,结合系统引用信息,以下是完整解决方案: --- ### 根本原因分析 该错误通常由三个核心问题引起: 1. **插件路径配置错误**:`mosquitto.conf` 中指定的插件路径不正确 2. **依赖库缺失**:插件需要但未安装的库(如 OpenSSL、libwebsockets 等) 3. **权限问题**:mosquitto 用户无法访问插件或库文件 --- ### 详细解决步骤 #### 1. 验证插件路径配置 编辑配置文件 `/etc/mosquitto/mosquitto.conf`: ```ini # 确保路径指向实际插件位置 plugin /usr/local/lib/mosquitto_auth_plugin.so # 添加后端认证配置(示例使用MySQL) auth_opt_backends mysql auth_opt_host localhost auth_opt_dbname mqtt_auth auth_opt_user mqtt_user auth_opt_password your_password ``` ▶ **关键检查**:`plugin` 路径必须与实际编译生成的 `.so` 文件路径一致 #### 2. 安装缺失依赖库 根据引用[2][3]的编译要求: ```bash # 安装基础编译工具 sudo apt install build-essential cmake libssl-dev -y # Debian/Ubuntu sudo yum install openssl-devel cmake3 gcc-c++ -y # CentOS/RHEL # 安装MySQL开发库(以MySQL为例) sudo apt install libmysqlclient-dev -y # Debian sudo yum install mariadb-devel -y # CentOS ``` #### 3. 验证动态库依赖 使用 `ldd` 检查插件依赖: ```bash ldd /usr/local/lib/mosquitto_auth_plugin.so | grep "not found" ``` ▶ 若出现缺失库: - 安装对应 `-dev` 或 `-devel` 包 - 添加库路径到 `/etc/ld.so.conf.d/mosquitto.conf`: ```bash echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/mosquitto.conf sudo ldconfig ``` #### 4. 修复文件权限(引用[3]) ```bash sudo chown mosquitto:mosquitto /usr/local/lib/mosquitto_auth_plugin.so sudo chmod 755 /usr/local/lib/mosquitto_auth_plugin.so # 检查日志目录权限 sudo chown mosquitto:mosquitto /var/log/mosquitto ``` #### 5. 启用调试模式验证 临时启动服务调试: ```bash sudo -u mosquitto mosquitto -c /etc/mosquitto/mosquitto.conf -v ``` ▶ 观察控制台输出的详细错误信息 --- ### 完整安装参考流程(引用[3]补充) ```bash # 1. 安装编译依赖 sudo apt install build-essential cmake libssl-dev libc-ares-dev libmysqlclient-dev # 2. 编译mosquitto-auth-plug git clone https://github.com/jpmens/mosquitto-auth-plug.git cd mosquitto-auth-plug make # 3. 复制生成的插件 sudo cp auth-plug.so /usr/local/lib/mosquitto_auth_plugin.so ``` --- ### 预防性措施 1. **服务管理**:如引用[1]所述,确保安装为系统服务: ```bash sudo systemctl enable mosquitto sudo systemctl restart mosquitto ``` 2. **环境隔离**:使用 Docker 容器化部署(推荐)避免依赖冲突 3. **日志监控**:定期检查 `/var/log/mosquitto/mosquitto.log` > 若使用 Windows 系统,请注意: > - 确保 `.dll` 文件与 `mosquitto.exe` 同目录 > - 安装 [Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值