Grant Moderator with JWT verification and token moderation enabled not working

Hello team, I am trying the feature “Grant Moderator”. It’s not working as expected when token moderation is enabled along with jwt verification.

Getting below error on console while trying grant moderator feature:

2020-08-18T23:12:50.268Z [modules/xmpp/ChatRoom.js] Set affiliation of participant error: <iq xmlns=​"jabber:​client" type=​"error" to=​"d6d34b9a-8a59-4d3c-bfb8-87bdb941a629@domain/​02fdac43-66e3-4e7d-8d77-1ddd03669249" from=​"webdev@conference.domain" id=​"89bada18-1049-4063-a578-b9ec6dfc40c9:​sendIQ">​<error type=​"modify">​<not-acceptable xmlns=​"urn:​ietf:​params:​xml:​ns:​xmpp-stanzas">​</not-acceptable>​</error>​</iq>​

Prosody debug logs:

Aug 18 16:12:50 http.server debug Firing event: POST domain/http-bind

Aug 18 16:12:50 mod_bosh debug Handling new request table: 0x559946f01660: <body rid="2527603814" sid="08a6c32c-0fe4-49b0-8868-70b99f296a4c" xmlns="http://jabber.org/protocol/httpbind"><iq id="89bada18-1049-4063-a578-b9ec6dfc40c9:sendIQ" to="webdev@conference.domain" type="set" xmlns="jabber:client"><query xmlns="http://jabber.org/protocol/muc#admin"><item affiliation="owner" nick="9b14e558"><reason>Your affiliation has been changed to &apos;owner&apos;.</reason></item></query></iq></body>

----------

Aug 18 16:12:50 mod_bosh debug BOSH body open (sid: 08a6c32c-0fe4-49b0-8868-70b99f296a4c)

Aug 18 16:12:50 mod_bosh debug BOSH stanza received: <iq id='89bada18-1049-4063-a578-b9ec6dfc40c9:sendIQ' type='set' to='webdev@conference.domain'>

Aug 18 16:12:50 bosh08a6c32c-0fe4-49b0-8868-70b99f296a4c debug Received[c2s]: <iq id='89bada18-1049-4063-a578-b9ec6dfc40c9:sendIQ' type='set' to='webdev@conference.domain'>

Can anyone help me with it?

That’s because token moderation plugin denies that possibility (here is the code).
If you want to be able to set moderator in conference, you would have to modify the code, i can’t tell you how - deleting this conditional block will turn on the auto-owning feature, but that can be turned off somewhere else i think.
But modifying it means, that you are allowing it just for the user present in conference, when he leaves and rejoins (with same jwt token) he might and probably be recognized as different user and thus without moderator rights. Some other problems may arise.

1 Like

Yea, I figured out an issue that token moderation blocks it. However, modifying that piece of code breaks other functionalities. Also, if we just remove that if block and keep other code as it is, it will allow granting but as soon as that new granted user clicks on microphone/video icon, this method will be again get called and check for moderator boolean which will be false in our case and so, it will take away moderator rights again. So, just checking if someone is able to make this work. I am able to make it work in a way that instead of checking one every handle_first_presence, check only when room is created. But, then, that is breaking other functionalities I am looking for.

My requirements are basically like:

  • Only those users with moderator boolean enabled should be provided moderator rights.

  • Moderator can join anytime in the room, so if guest joins first, he/she should not be given moderator rights (this breaks if I modify code above)

  • Moderator should be able to grant moderator rights to some one else anytime and those rights should not go away in that session unless he/she drops the call and joins back will be a different case.

  • If moderator leaves the room, still the moderator rights should not go away to others. (This is still fine if we can’t achieve this)

I am looking into code modification though. Lets see how it goes.

I think first two items on your requirements list are already done by jwt and token moderation plugin, the third and fourth item are in my opinion achievable only with new jwt token or non trivial coding in lua and jitsi internals.

We decided that in this setup we will do the “grant moderator” outside of jitsi (we are running jitsi via jitsi meet api from our app) and force rejoin that user with new jwt token with moderator set to true.
It’s not that nice as in-app functionality, but works without any hassle.

I see. Yea, that make sense to make it work, but then, I feel it can be a bit awkward experience. Alright, Thanks for sharing your insights. I will play with the code little bit and see if I can figure out something directly.

So i was searching through code to solve this and might come up with solution.

There is a config setting in jicofo, that turns off auto owning that the moderation plugin in my opinion tries to solve (assuming from this comment in code: -- noone else can assign owner (in order to block prosody/jisti's built in moderation functionality)
The config setting is

org.jitsi.jicofo.DISABLE_AUTO_OWNER

Default is false, If set to true, it should disable the auto owning feature, which leaves us only with manual operations to set owner (=grant moderator). I’ll try it on our stage env with modifications to moderation plugin, i believe that deleting lines 39-42 should be enough.

@mehtapaxshal
So disable auto owner did some good, but didn’t get rid of auto owning on user participant joining in, didn’t look -> didn’t find what is making jicofo grant user a moderator, resp. owner.
I made some tracing and decided to modify token moderation with this patch:

--- a/mod_token_moderation.lua  2020-09-09 17:08:27.959429997 +0200
+++ b/mod_token_moderation.lua  2020-09-10 15:40:45.901889531 +0200
@@ -38,7 +38,13 @@
                         return _set_affiliation(room, true, jid, affiliation, reason)
                 -- noone else can assign owner (in order to block prosody/jisti's built in moderation functionality
                 elseif affiliation == "owner" then
-                        return nil, "modify", "not-acceptable"
+                        log('debug', 'set_affiliation: room=%s, actor=%s, jid=%s, affiliation=%s, reason=%s', room, actor, jid, affiliation, reason);
+                        if string.match(actor, "focus@") then
+                            log('info', 'set_affiliation not acceptable, focus user');
+                            return nil, "modify", "not-acceptable";
+                        else
+                            return _set_affiliation(room, actor, jid, affiliation, reason);
+                        end;
                 -- keep other affil stuff working as normal (hopefully, haven't needed to use/test any of it)
                 else
                         return _set_affiliation(room, actor, jid, affiliation, reason);

It basically looks at who is the actor granting ownership (edit: or rather to whom grant the ownership?), if the actor start with focus@, than we deny the request. For safety reasons it might be more precise matching (like focus@authdomain/focus*), but that needs more work to be generally usable (i’ll hardcode our data here in our infrastructure).
From my initial testing it seems that it does exactly what is to be expected. I’ll leave it be on our staging env and see if something will come up.

The only thing that it DOES NOT handle is when user who was granted moderator leaves and joins back with old jwt token. He will be again non-moderator. Handling of issuing new jwt token is out of scope for jitsi, it needs to be done elsewhere.

1 Like

Awesome. This sounds amazing. I am busy with some other configurations. However, I will give this a try soon and update here. Thanks!

Also, this is expected. If granted moderator leaves and re-joins, they will/should loose ownership as it will be a new session for that person and he/she needs to be granted again if required.

Awesome. Some of your changes did a trick. Grant moderator works with jwt. Thanks for that. However, when the new granted moderator tries unmuting or muting, the moderatorship goes away and that’s because it was checking jwt at every events such as mute/unmute/video on/off, etc… So, I modified handle presence logic to just hook it when occupant joins so that it checks the moderator rights for the first time when someone joins instead of checking always.

And, Finally all above scenarios I wanted works. Thanks again :slight_smile:

Thanks for pointing that out, didn’t notice that behaviour.
@mehtapaxshal So i guess, that you modified this block:

-- Wrap presence handlers to set affiliations from token whenever a user joins
room.handle_normal_presence = function(thisRoom, origin, stanza)
        local pres = _handle_normal_presence(thisRoom, origin, stanza);
        setupAffiliation(thisRoom, origin, stanza);
        return pres;
end;

Probably deleted this whole function?

@mehtapaxshal I have the same behaviour you described (moderator role missed after mute/unmute…), could you please indicate which changes you made (about presence logic) in order to solve this issue?

Thanks a lot and thanks also to @nosmo !
Alex

Yea! That’s true. Let me share the piece of code here:

module:hook("muc-occupant-joined", function(event)
        log('info', 'occupant joined, checking token for ownership');
	local room = event.room
        setupAffiliation(room, event.origin, event.stanza);
        
	local _set_affiliation = room.set_affiliation;
        room.set_affiliation = function(room, actor, jid, affiliation, reason)
                if actor == "token_plugin" then
                        return _set_affiliation(room, true, jid, affiliation, reason)
                elseif affiliation == "owner" then
			log('debug', 'set_affiliation: room=%s, actor=%s, jid=%s, affiliation=%s, reason=%s', room, actor, jid, affiliation, reason);
			if string.match(tostring(actor), "focus@") then
				log('debug', 'set_affiliation not acceptable, focus user');
				return nil, "modify", "not-acceptable";
			else
				return _set_affiliation(room, actor, jid, affiliation, reason);
			end;

                else
                        return _set_affiliation(room, actor, jid, affiliation, reason);
                end;
        end;
end);

This is how the hook looks like.

@alexp modify code as above and it should work.

Halelujah! Of course, why it didn’t occured to me is a mystery :wink: Clever.

Now i get what the original moderation plugin was built for - to handle moderators in room based solely on jwt tokens and deny every other option how to set moderator, even for user granted moderators. That’s why all this presence handlers were there for.

Thx.

1 Like

Ok, it perfectly worked!!!

Thanks a lot @mehtapaxshal and @nosmo !!!

Alex

1 Like

So i’ve made one small change, it’s better to set set_affiliation handler only once when room is created, not on every occupant joined event, which might lead to some uneffective handler chains.
But @mehtapaxshal solution works well.

module:hook("muc-room-created", function(event)
    log('info', 'room created, adding token moderation code');

    local room = event.room
    local _set_affiliation = room.set_affiliation;
    room.set_affiliation = function(room, actor, jid, affiliation, reason);
        if actor == "token_plugin" then
            return _set_affiliation(room, true, jid, affiliation, reason);
        elseif affiliation == "owner" then
            log('debug', 'set_affiliation: room=%s, actor=%s, jid=%s, affiliation=%s, reason=%s', room, actor, jid, affiliation, reason);
            if string.match(tostring(actor), "focus@") then
               log('debug', 'set_affiliation not acceptable, focus user');
               return nil, "modify", "not-acceptable";
            else
                return _set_affiliation(room, actor, jid, affiliation, reason);
            end;
        else
            return _set_affiliation(room, actor, jid, affiliation, reason);
        end;
    end;
end);


module:hook("muc-occupant-joined", function(event)
    log('info', 'occupant joined, checking token for ownership');
    setupAffiliation(event.room, event.origin, event.stanza);
end);
1 Like