Coder Social home page Coder Social logo

wiomoc / mosquitto-jwt-auth Goto Github PK

View Code? Open in Web Editor NEW
38.0 5.0 10.0 41 KB

Mosquitto Auth Plugin which enables authentication via JWTs and authorisation via ACLs stored in JWT claims

License: MIT License

Rust 100.00%
mqtt mosquitto jwt security

mosquitto-jwt-auth's Introduction

mosquitto-jwt-auth

Build Coverage Status

Simple Plugin for Mosquitto which enables authentication and authorisation via JWT as MQTT password.

Requires at least Mosquitto v1.6.3. Tested on Mac OS and Linux.

Building

Prebuild version for Linux is available here

  1. If not done yet, install Rust
  2. Clone git clone [email protected]:wiomoc/mosquitto-jwt-auth.git
  3. Build cargo build --release, on success plugin should be located at target/release/libmosquitto_jwt_auth.so

Configuration

One could choose between the basic JWT validation and the more advanced JWKS validation.

Basic JWT validation

To enable this, the configuration property auth_opt_jwt_alg has to be set to the desired JWT / JWS algorithm. The key to validate the JWT could be supplied over various ways:

  • in a file: auth_opt_jwt_sec_file has to be set to the filename containing the key
  • over an environment variable: auth_opt_jwt_sec_env has to be set to name of the environment variable
  • directly in the config: auth_opt_jwt_sec_base64 has to be set to the base64 encoded key If a asymmetric algorithm is used (eg. RS256 or ES256) the key has to be given in DER format.

JWKS validation

To enable this, the configuration property auth_opt_jwt_jwks_file has to be set to the filename containing the JWK set. Note that both the JWK and the JWT have to have the keyid (kid) set.

Key rotation

If you want to implement key rotation you can update this file using a external program regularly and reload the plugin by sending a SIGHUP to the mosquitto process.

Example intergrated in crontab using curl:

*/10 * * * * curl -o mosquitto_jwks.json https://my-idp.com/jwks.json && killall -SIGHUP mosquitto

Properties

auth_plugin should point to the path of libmosquitto_jwt_auth.so

Property Valid values Usage
auth_opt_jwt_alg HS256, HS384, HS512, ES256, ES384, RS256, RS384, RS512, PS256, PS384, PS512 Sets the algorithm of the JWT signature
auth_opt_jwt_sec_file <path to file> Path to the file which contains the secret used for verification of the signature.
auth_opt_jwt_sec_env <enviroment variable name> Name of the environment variable which contains the base64 encoded key used for verification of the signature.
auth_opt_jwt_sec_base64 <base64-encoded-secret> Base64 encoded key used for verification of the signature.
auth_opt_jwt_jwks_file <path to file> Path to the file which contains a JWK set.
auth_opt_jwt_validate_exp (default) true, false true if the exp claim / the expiry date of the JWT should be validated
auth_opt_jwt_validate_sub_match_username (default) true, false true if the MQTT username has to be the same as specified in the sub claim

Custom Claims

The plugin authorizes subscriptions and publications based on the acl stated in JWT claims.

  • publ (Optional) Contains the Topics(filters) the client is allowed to publish in

  • subs (Optional) Contains the Topics(filters) the client is allowed to subscribe to

    {
      "sub": "mqttUser",
      "iat": 1516239022,
      "exp": 1616239022,
      "subs": ["/+/topic", "/abc/#"],
      "publ": ["/abc"]
    }
    

mosquitto-jwt-auth's People

Contributors

stefanfoulis avatar wiomoc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mosquitto-jwt-auth's Issues

Set the username from a claim field and use mosquitto ACL %c

Hi,

Is there a way to set the username from a claim field?
For instance i have a jwt token like that:

{
  "user_name": "[email protected]",
  "creationDate": "2020-10-28T15:33:30.792732Z",
  "client_id": "nebowebap_cloudtest",
  "aud": [
    "MyScriptSSO"
  ],
  "scope": [
    "read"
  ],
  "exp": 1605108810, 
  "jti": "723efff8-5d75-44a9-91c1-ff4430a615d8",
}

And i would like %c matches with the "user_name" field's value. (https://medium.com/jungletronics/mosquitto-acls-ac062aea3f9)

jwt_sec_file: Reload file for rotating public key support

First of all, thanks for this crate!

For a long running mosquitto instance, it might be beneficial if the jwt public key file can be re-loaded instead of only reading it in once at start. This is because a lot of jwt servers have rotating public keys.

I thought about a spawned thread somewhere around here:

file_contents

With either another option like "auth_opt_jwt_sec_reload_sec 3600" or a file watch mechanism.

The secret would no longer be in secret: Vec<u8> but in secret: ArcSwap<Vec<u8>> (see arc_swap crate). ArcSwap basically allows thread safe pointer swaps and exterior mutability.

WDYT?

Configuring mosquitto.conf

Sorry for posting here, i have few questions...

  1. i configured my mosquitto.conf like this:

auth_plugin /home/user/mosquitoplugin/mosquitto-jwt-auth-master/target/release/libmosquitto_jwt_auth.so

auth_opt_jwt_alg HS256
auth_opt_jwt_sec_file /home/user/secret.txt
auth_opt_jwt_validate_exp false
auth_opt_jwt_validate_sub_match_username false

in the secret.txt i put a simple string.

Is this ok ?

Also, what are those options stand for ?
auth_opt_jwt_sec_env
auth_opt_jwt_sec_base64

i thought only the secret specified here auth_opt_jwt_sec_file matters. Can you give me some advise ? i'm a bit lost :)

recommended way to install mosquitto-jwt-auth in docker

I am new to mosquitto and rust and am probably just missing some very obvious information.
I couldn't figure out yet how to install this plugin.
I am currently using the official docker image
.

Ideally I'd like to use the official image and just add a few layers to it to install this plugin.

I've seen other plugins install themselves using git clone and make, however this plugin does not have a Makefile.
Here I see there seems to be a cargo package. However if I do cargo install mosquitto-jwt-auth I get this error:

Step 6/11 : RUN cargo install mosquitto-jwt-auth
 ---> Running in f96144d4d563
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading mosquitto-jwt-auth v0.2.0
  Installing mosquitto-jwt-auth v0.2.0
error: specified package has no binaries
ERROR: Service 'mqtt' failed to build: The command '/bin/sh -c cargo install mosquitto-jwt-auth' returned a non-zero code: 101

Documentation request / offer

Thanks for library - it's just my lack of experience I'm sure, but I'm struggling to get jwt auth working....

Would it be possible to add some pointers to newbies like myself - for example, how should the token be passed in? as username, password...? does it need to contain any particular claims to make things work? Is there any further reading material that I or others could be pointed to?

I've looked and looked but of course I might have missed something obvious...

I'm happy to help write/format some short guidance if only I could get it working myself... I do appreciate that this isn't probably your highest priority! but despite mosquito and this plug-in's popularity I can't find very much info on it. I failed to find a better way to communicate than raising an issue - please forgive or correct me.

And also I would very much like to have some sort of acl applied to the token presenting clients - any advice as to how this might be configured would also be really wonderful. I've got the standard acl working in mosquitto I was just wondering how they would be integrated - by clientID and using that as a pattern match in the acl perhaps?

Thanks you in advance, for all the work you've already done, and perhaps, in anticipation of being able to help me and others a tiny bit more!

Kindest regards

Gareth

Public API of mosquitto-jwt-auth exposes UB to safe code

For example, the following safe program leads to mosquitto-jwt-auth performing Undefined Behavior:

// [dependencies]
// mosquitto-jwt-auth = "0.2.0"

fn main() {
    mosquitto_jwt_auth::mosquitto_sys::mosquitto_auth_plugin_init(
        0xdeadbeefusize as _,
        0xcafebabeusize as _,
        100,
    );
}
Segmentation fault (core dumped)

In general it is unsound for a safe API to result in UB.

ACL doesn't allow subscriptions to topics with wildcards, even if permissions would allow it

Hi! I was delighted to find this plugin, which seems like exactly what I need for a project I'm working on.
However, in the particular way I'm using it, it's exhibiting some behavior that's unexpected (to me at least)... not sure if it's a bug, or if I'm misunderstanding how this behavior is supposed to work.

So when the user authenticates against my web app, it looks up which "room" the user is supposed to have access to, and issues them a JWT that gives them permission to publish and subscribe to any topic under that room ID, using a multi-level wildcard:

{
  "iat": 1588141196,
  "exp": 1588227596,
  "sub": "d2925b0f-23ce-42ee-9a0e-f3779d3970bd",
  "publ": [
    "1/#"
  ],
  "subs": [
    "1/#"
  ]
}

When the client connects to Mosquitto, they present the token, and are successfully authenticated. Then they attempt to subscribe to 1/#, but the subscription doesn't seem to work.

It seems that mostquitto-jwt-auth is rejecting the subscription to 1/#, even though the user is presenting a token that gives them subs permission to 1/#.

Just to double-check that this is what the plugin is doing, and not a configuration error on my party, I tweaked one of the unit tests to test my use case:

    #[test]
    fn test_acl_check() {
        let mut instance = MosquittoJWTAuthPluginInstance::new();
        instance.config = Some(MosquittoJWTAuthPluginConfig {
            validation: Validation::default(),
            validate_sub_match_username: true,
            secret: Vec::new(),
        });

        let client_id0 = 33 as ClientID;

        instance.client_permissions.insert(
            client_id0,
            Permissions {
                r#pub: Vec::new(),
                sub: vec![
                    topic_utils::parse_topic_path("1/#", true).unwrap(),
                ],
            },
        );

        let result = instance.acl_check(client_id0, AclType::Subscribe, "1/#");
        assert_eq!(result, Ok(()));
    }

This test fails, returning Err(()) instead of Ok(()).

I should also note that this behavior seems to differ from the normal ACL behavior for Mosquitto. If I create an acl_file like this:

user testuser
topic readwrite 1/#

... the user seems to be able to subscribe to all topics under 1/ using 1/#

Cannot load plugin

Load error: Error loading shared library libgcc_s.so.1: No such file or directory (needed by /mosquitto/plugins/libmosquitto_jwt_auth.so)

used Prebuild version for Linux

ACL: Support for client id and username

Is it possible to add support for Username / Client ID in the ACLs?

Mosquitto Docs

%c to match the client id of the client
%u to match the username of the client

The patterns available for substition are:

    %c to match the client id of the client

    %u to match the username of the client

The substitution pattern must be the only text for that level of hierarchy. Pattern ACLs apply to all users even if the "user" keyword has previously been given.

Example:

pattern write sensor/%u/data

Allow access for bridge connection messages:

pattern write $SYS/broker/connection/%c/state

Not able to publish after configuring jwt token

mosquitto_pub -h localhost -t test -m "hello world" -u "root" -P "eyJhbGciOiJIUzI1NiJ9.eyJVc2VybmFtZSI6InJvb3QiLCJleHAiOjE2NTU5MDYwODcsImlhdCI6MTY1NTY0Njg4N30.LVRjr3uW_VZv_hbBQUijGELVgKkEZSGdSOBOR0L2EPo" -p 8083

When I publish, I am getting
Error: The connection was lost.
I am able to subscribe to it with JWT Token.

Do I need to configure ACL for this as I currently have no ACL file?

Wildcardsubscribtion is not working

I created the following JW Token. This should allow to subscribe to "test/#" but it dont.

Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjM5NDAwNTM3LCJleHAiOjE2Mzk2MTY1MzcsInN1YnMiOlsidGVzdFwvIyJdfQ.bp7vzz-fKAt5nlZ-xZbXZ3yUIyui1WFEqtJaEmyXLtI

{
  "typ": "JWT",
  "alg": "HS256"
}.{
  "sub": "test",
  "iat": 1639400537,
  "exp": 1639616537,
  "subs": [
    "test/#"
  ]
}.[Signature]

Then try to use the Token with mosqutto_sub:

mosquitto_sub  -d -c -i shell -p 9000 -t "test/#" -u "test" -P "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0IiwiaWF0IjoxNjM5NDAwNTM3LCJleHAiOjE2Mzk2MTY1MzcsInN1YnMiOlsidGVzdFwvIyJdfQ.bp7vzz-fKAt5nlZ-xZbXZ3yUIyui1WFEqtJaEmyXLtI"
Client shell sending CONNECT
Client shell received CONNACK (0)
Client shell sending SUBSCRIBE (Mid: 1, Topic: test/#, QoS: 0, Options: 0x00)
Client shell received SUBACK
Subscribed (mid: 1): 128
Client shell sending DISCONNECT
All subscription requests were denied.

Mosquitto Version: 2.0.14-0

Mosquitto Config

listener 9000 127.0.0.1
protocol mqtt
socket_domain ipv4
auth_plugin /usr/local/lib/libmosquitto_jwt_auth.so
auth_opt_jwt_alg HS256
auth_opt_jwt_sec_base64 RGFzIGlzdCBHZWhlaW0gNTE0
auth_opt_jwt_validate_exp true
auth_opt_jwt_validate_sub_match_username false

Expected: Subscription is ok
Actual: Subscription is deny with 0x80

MS Azure AD jwks integration

I am trying to validate MS Azure AD generated JWT tokens using jwks. However biscuit is throwing error decoding jwt: ValidationError(MissingAlgorithm). Since MS AD jwks doesn't contain alg field I am not sure if the error is due to that. Does this library work with MS Azure AD jwks? If so could you please share more details on how to integrate? Just to add I a testing on docker image of mosquitto eclipse.

Wich public key format to use with EC alg (ES256) ?

For RSA plublic key, I found that you should use a base 64 encoded DER using PKCS1.

In python, this is given by:

base64.b64encode(public_jwk.prepared_key.public_bytes(
    encoding=serialization.Encoding.DER,
    format=serialization.PublicFormat.PKCS1
))

Now I'm trying to switch to EC based keys, I first tried to use a JWKS file (see #13 ), bit it seems unsupported for now. Now I'm trying to use the auth_opt_jwt_sec_base64 option, but I'm not sure how to format the key, because PKCS1 is RSA only.

I tried this:

base64.b64encode(public_jwk.prepared_key.public_bytes(
    encoding=serialization.Encoding.DER,
    format=serialization.PublicFormat.SubjectPublicKeyInfo
))

But with that I always get ValidationError(InvalidSignature). I'm sure that the token I use are properly signed because I can validate them using the https://jwt.io/ provided tool.

Mosquitto crashes when attempting login with jwt in username

I've experienced mosquitto crashing when I try to login without a password and use the jwt as username.

Being able to login in this way is useful when all we want to give the clients is a single "api-key".

I experienced this with the paho library (on python). I've not tried any other libraries yet.
https://www.eclipse.org/paho/clients/python/docs/#username-pw-set

If it does not turn out to be obvious where the error is happening, I can try to make an easier to reproduce example.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.