authorization by JWT token

Connecting to a jitsi without authorization can become insecure. In order to avoid uninvited guests during a meeting, conference or personal conversation, you should think about authorization. Under the cut, I will tell you in detail how we can improve our jitsi-meet service using a JWT token.

Below I have described a step-by-step instruction for installing and configuring a JWT token on debian. The whole process can be carried out as on an already running service jitsi-jibri (from my mana it definitely works), and in a new installation after completing the jitsi setup.

apt install git cmake luarocks libssl-dev liblua5.2
wget http://packages.prosody.im/debian/pool/main/p/prosody-trunk/prosody-trunk_1nightly1273-1~buster_amd64.deb
dpkg -i prosody-trunk_1nightly1273-1~buster_amd64.deb
apt install prosody -y
echo deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list
wget https://prosody.im/files/prosody-debian-packages.key -O- | sudo apt-key add -
apt update
apt upgrade
apt-get install jitsi-meet-tokens prosody-modules lua5.2 liblua5.2 luarocks libssl-dev

During the installation process, the Application ID and Application secret will be requested. We indicate them and be sure to remember them, they will be needed to generate a token (if you suddenly forgot them, then it’s okay, you can see / change them in the prosody configuration file)

luarocks install basexx

At the end of the /etc/prosody/prosody.cfg.lua file, add the line:

vim /etc/prosody/prosody.cfg.lua
Include "conf.d/*.cfg.lua"

We also find the line starting with “s2s_” and add before it:

c2s_require_encryption = false

We continue the installation:

luarocks download lua-cjson
luarocks unpack lua-cjson-2.1.0.6-1.src.rock

In the lua-cjson-2.1.0.6-1/lua-cjson/lua_cjson.c file, change line 743:

vim lua-cjson-2.1.0.6-1/lua-cjson/lua_cjson.c
len = lua_objlen(l, -1);
на
len = lua_rawlen(l, -1);

Save the file and continue with the installation:

cd lua-cjson-2.1.0.6-1/lua-cjson
luarocks make --force
cd ..
git clone https://github.com/ASolomatin/luajwt.git
cd luajwt/

Let’s make changes to the luajwtjitsi-1.3-7.rockspec file:

package = "luajwtjitsi"
version = "1.3-7"

source = {
        url = "git://github.com/ASolomatin/luajwt/",
        tag = "replace_luacrypto"
}

description = {
        summary = "JSON Web Tokens for Lua",
        detailed = "Very fast and compatible with pyjwt, php-jwt, ruby-jwt, node-jwt-simple and others",
        homepage = "https://github.com/jitsi/luajwt/",
        license = "MIT <http://opensource.org/licenses/MIT>"
}

dependencies = {
        "lua >= 5.2",
        "luaossl >= 20190731-0",
        "lua-cjson >= 2.1.0",
        "lbase64 >= 20120807-3"
}

build = {
        type = "builtin",
        modules = {
                luajwtjitsi = "luajwtjitsi.lua"
        }
}

We continue:

luarocks install luajwtjitsi 2.0-0
systemctl restart prosody

We check for errors, if there are, then we clean the file and restart the prosody:

vim /var/log/prosody/prosody.err
systemctl restart prosody
vim /var/log/prosody/prosody.err

To generate a token, you can go to website and there, setting the parameters to generate it, and then insert it into the URL in the format https:///name_room?jwt=token .

On the site enter the following data:

HEADER:ALGORITHM & TOKEN TYPE

{
  "typ": "JWT",
  "alg": "HS256"
}
PAYLOAD:DATA

{
 "context": {
    "user": {
      "name": "<user>",
      "id": "<user>@gmail.com",   #optional
      "email": "<user@gmail.com>",  #optional
      "avatar": "<link to user's avatar>"  #optional
    }
  },
  "aud": "jitsi",
  "iss": "<Application_ID>",
  "sub": "<FQDN>",
  "room": "*",
  "exp": 98753496345768,
  "moderator": true
}
VERIFY SIGNATURE

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),

<Application_secret>

) secret base64 encoded

https://habr.com/ru/company/timeweb/blog/666156/image
Bring to this form with the substitution of your own value instead of <...>

After successfully installing the necessary infrastructure, you need to register the configuration for correct operation. We received the basic configuration during the installation process, and the settings that I will give below are optional.

Editing prosody virtual hosts. In order for participants to connect to our conference at the invitation of a moderator without a token, we will create a guest host. By default, we installed the moderator module, but this module does not allow you to transfer moderator rights, we will change it to another one. We will also install a module that includes the lobby by default. This feature will allow the administrator to control who enters the room, and they, in turn, will have to “introduce themselves”.

vim /etc/prosody/conf.avail/<FQDN>.cfg.lua

We find our virtual host and bring it to the following value:

VirtualHost "<FQDN>"        
    authentication = "token"
    app_id="<APP_ID>"
    app_secret="<APP_SECRET>"
    allow_empty_token = false
    allow_unencrypted_plain_auth = true
  …
    ssl = {
        key = "/etc/prosody/certs/<FQDN>.key";
        certificate = "/etc/prosody/certs/<FQDN>.crt";
    }
    av_moderation_component = "avmoderation.<FQDN>"
    speakerstats_component = "speakerstats.<FQDN>"
    conference_duration_component = "conferenceduration.<FQDN>"
    -- we need bosh
    modules_enabled = {
        "bosh";
        "pubsub";
        "ping"; -- Enable mod_ping
        "speakerstats";
        "external_services";
        "conference_duration";
        "muc_lobby_rooms";
        "muc_breakout_rooms";
        "presence_identity";
        "av_moderation";
    }
    c2s_require_encryption = false
    lobby_muc = "lobby.<FQDN>"
    breakout_rooms_muc = "breakout.<FQDN>"
    main_muc = "conference.<FQDN>"
    muc_lobby_whitelist = { "recorder.<FQDN>" } -- Here we can whitelist jibri to enter lobby enabled rooms

VirtualHost "guest.<FQDN>"
    authentication = "anonymous"
    modules_enabled = {
            "bosh";
            "pubsub";
            "ping"; -- Enable mod_ping
            "speakerstats";
            "conference_duration";
        }
    c2s_require_encryption = false

Component "conference.<FQDN>" "muc"
    restrict_room_creation = true
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        "muc_domain_mapper";
        "polls";
        "token_verification";
        "token_moderation";
        "muc_rate_limit";
    }
    admins = { "focus@auth.<FQDN>" }
    muc_room_locking = false
    muc_room_default_public_jids = true

Component "breakout.<FQDN>" "muc"
    restrict_room_creation = true
    storage = "memory"
    modules_enabled = {
        "muc_meeting_id";
        "muc_domain_mapper";
        "token_verification";
        "muc_rate_limit";
        "polls";
    }
    admins = { "focus@auth.<FQDN>" }
    muc_room_locking = false
    muc_room_default_public_jids = true

-- internal muc component
Component "internal.auth.<FQDN>" "muc"
    storage = "memory"
    modules_enabled = {
        "ping";
    }
    admins = { "focus@auth.<FQDN>", "jvb@auth.<FQDN>" }
    muc_room_locking = false
    muc_room_default_public_jids = true
    muc_room_cache_size = 1000

VirtualHost "auth.<FQDN>"
    ssl = {
        key = "/etc/prosody/certs/auth.<FQDN>.key";
        certificate = "/etc/prosody/certs/auth.<FQDN>.crt";
    }
    modules_enabled = {
        "limits_exception";
    }
    authentication = "internal_hashed"

-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
Component "focus.<FQDN>" "client_proxy"
    target_address = "focus@auth.<FQDN>"

Component "speakerstats.<FQDN>" "speakerstats_component"
    muc_component = "conference.<FQDN>"

Component "conferenceduration.<FQDN>" "conference_duration_component"
    muc_component = "conference.<FQDN>"

Component "avmoderation.<FQDN>" "av_moderation_component"
    muc_component = "conference.<FQDN>"

Component "lobby.<FQDN>" "muc"
    storage = "memory"
    restrict_room_creation = true
    muc_room_locking = false
    muc_room_default_public_jids = true
    modules_enabled = {
        "muc_rate_limit";
        "polls";
    }

В конец файла добавляем следующее (это понадобится для jibri)

-- internal muc component, meant to enable pools of jibri and jigasi clients
-- Component "internal.auth.<FQDN>" "muc" -- Данный блок уже может быть выше в конфиге
--    modules_enabled = {
--        "ping";
--    }
--    storage = "memory"
--    muc_room_cache_size = 1000

VirtualHost "recorder.<FQDN>"
    modules_enabled = {
        "ping";
    }
    authentication = "internal_plain"

Clone the repository with modules and install:

cd ~
git clone https://github.com/nvonahsen/jitsi-token-moderation-plugin.git
mv jitsi-token-moderation-plugin/mod_token_moderation.lua /usr/share/jitsi-meet/prosody-plugins/bak.mod_token_moderation.lua
git clone https://github.com/dumasti/jitsi_mods.git
mv /usr/share/jitsi-meet/prosody-plugins/mod_muc_lobby_rooms.lua /usr/share/jitsi-meet/prosody-plugins/bak.mod_muc_lobby_rooms.lua
mv jitsi_mods/*.lua /usr/share/jitsi-meet/prosody-plugins/
mv /usr/share/jitsi-meet/prosody-plugins/mod_token_moderation_grand.lua /usr/share/jitsi-meet/prosody-plugins/mod_token_moderation.lua

Change the settings in the /etc/jitsi/meet/-config.js file to enable the guest host and other usefulness (optional).

cp /etc/jitsi/meet/<FQDN>-config.js /etc/jitsi/meet/bak.<FQDN>-config.js
vim /etc/jitsi/meet/<FQDN>-config.js
/* eslint-disable no-unused-vars, no-var */

var config = {
    hosts: {
        domain: '<FQDN>',

        anonymousdomain: 'guest.<FQDN>',
        muc: 'conference.<FQDN>'
    },

    bosh: '//<FQDN>/http-bind',

    testing: {
    },
    flags: {
    },

    enableNoAudioDetection: true,

    enableNoisyMicDetection: true,

    startAudioOnly: true,

    startWithAudioMuted: false,

    resolution: 1080,

    constraints: {
        video: {
            height: {
                ideal: 720,
                max: 1080,
                min: 360
            }
        }
    },

    disableSimulcast: true,

    fileRecordingsEnabled: true,
    liveStreamingEnabled: true,
    hiddenDomain: 'recorder.<FQDN>',

    channelLastN: -1,

    enableWelcomePage: true,

    defaultLanguage: 'en',

    enableUserRolesBasedOnToken: true,

    p2p: {
        enabled: true,
        stunServers: [

            { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }
        ]
    },

    analytics: {
    },

    deploymentInfo: {
    },

    mouseMoveCallbackInterval: 1000,
    makeJsonParserHappy: 'even if last key had a trailing comma'
};

/* eslint-enable no-unused-vars, no-var */
vim /etc/jitsi/jicofo/sip-communicator.properties
org.jitsi.jicofo.jibri.BREWERY=JibriBrewery@internal.auth.<FQDN>
org.jitsi.jicofo.jibri.PENDING_TIMEOUT=90
org.jitsi.jicofo.auth.URL=EXT_JWT:<FQDN>
systemctl restart jitsi-videobridge2 jicofo prosody

All is ready. Let’s go check.

If jibri is not yet installed, but you need to be able to record or broadcast conferences, then go here and continue installing jibri.

Thank you for attention!

Thanks for the help

Thanks for the editorial Daria Gulkovich. I also express my gratitude for the technical support (pendal in the right direction) to Nikita Suklich.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *