Ejabberd MucSub issue with room leave/exit - ejabberd

we are working on an Instant Messaging app based on XMPP handling members-only persistent groups using XEP-0045 and MucSub.
We have some issues with room occupancy and we didn't find a way to let users abandon a room permanently: we tried several approaches and none of them led to successful behavior.
The behavior we are looking for is very similar to WhatsApp and other similar mobile apps.
The first thing we had to think about is: which users we consider as participants?
The parameters we can use are:
Affiliation
Role
Subscription
To consider it as a working solution, we need that:
All the standard and obvious features of group conversations
Members can join and leave the group
If a member leaves a group, he cannot rejoin without invitation
Members can see the list of members and their privileges
Membership should not be affected by the member’s connection status
The member list and privileges must be persistent across server reboots
Our test environment:
Ejabberd 19.09 with mucsub enabled
PostgreSQL DB
We explored the following approaches:
Approach 1:
We can use affiliation to determine if a user is a participant, and consider him as a non-participant when the affiliation is none, outcast or not affiliated.
Who we consider as a participant:
Affiliation: member (or owner or admin)
Role: any
Subscription: any
How to abandon a room:
a. Sending a presence unavailable
<presence to='roomX#conference.x.com/test2' from='test2#x.com' type='unavailable'>
<status>leave</status>
</presence>
b. changing your own affiliation
<iq from='test2#x.com/app'
id='1234'
to='roomX#conference.x.com'
type='set'>
<query xmlns='http://jabber.org/protocol/muc#admin'>
<item affiliation='none' jid='test2#x.com'/>
</query>
</iq>
New attributes of ex participants:
Affiliation: none (or outcast if the user has been banned)
Role: any
Subscription: any (more probably the user will be unsubscribed, but this parameter is not checked to determine participants)
Issues:
Sending a presence unavailable is not affecting the affiliation. (It’s not reflecting anywhere in the DB)
Sending a presence unavailable sometimes does not obtain a response from the server (related issue opened here: Ejabberd MucSub: When a member sends a presence unavailable, the service does not respond)
Setting an affiliation for yourself does not work (as per specs: only admins can change affiliations)
 Approach 2:
We can use subscriptions status to determine if a user is a participant, and consider him as a non-participant when the he unsubscribes.
Who we consider as a participant:
Affiliation: member (or owner or admin)
Role: any
Subscription: subscribed to all kind of events
How to abandon a room:
The user will abandon a room by unsubscribing.
<iq from='test2#x.com'
to='roomX#conference.x.com'
type='set'
id='12345'>
<unsubscribe xmlns='urn:xmpp:mucsub:0' />
</iq>
New attributes of ex participants:
Affiliation: member (or owner or admin)
Role: any
Subscription: not subscribed
Issues:
The ex participant can rejoin subscribe again without invitation, and following this approach will lead that he will be considered as a participant again (with no invitation)

Related

How do I create a broadcast message to all logged in users in Skyve?

I have a job that runs and updates user's preference details and I want to notify all the currently logged in users when the job completes so that they're aware of the change?
The EXT library provides a EXT.push() method where you don't have access to a webContext (e.g. from within an ServerSideAction class).
If you want the message to be broadcast, rather than to 1 specific user, then just use the method without specifying the user, e.g.
EXT.push(new PushMessage().growl(MessageSeverity.info, "Preference details have been updated"));
Alternatively, if you want the message just for one user, then include the user in the chain as follows:
EXT.push(new PushMessage().user(user).growl(MessageSeverity.info, "Your preference details have been updated"));

CAS X.509 auth with attributes from database

I want to configure Apereo CAS 6.0.x to perform X.509 authentication and then retrieve principal attributes from a database table.
Rudimentary X.509 authentication is working with these lines in application.properties (and appropriate reverse proxy setup):
cas.authn.x509.extractCert=true
cas.authn.x509.sslHeaderName=SSL_CLIENT_CERT
cas.authn.x509.principalDescriptor=SUBJECT_DN
The default "Log In Successful" page shows that it knows how to get my certificate's subject DN.
But I can't figure out how to tell CAS to then use that subject DN value to query my database for additional attributes.
This page explicitly mentions my need (though with LDAP instead of JDBC), but does not say specifically how to achieve it:
In many cases it is necessary to perform authentication by one means and resolve principals by another. The PrincipalResolver component provides this functionality. A common use case for this this mix-and-match strategy arises with X.509 authentication. It is common to store certificates in an LDAP directory and query the directory to resolve the principal ID and attributes from directory attributes. The X509CertificateAuthenticationHandler may be be combined with an LDAP-based principal resolver to accommodate this case.
What properties need to be set so that the X509 authentication handler resolves the principal against the database?
The missing ingredient was this line in application.properties:
cas.authn.x509.principalType=SUBJECT_DN
Without it, CAS does not attempt to query any attributeRepository settings that you may have.

Sending messages to unknown users in XMPP MultiUserChat with OMEMO encryption

I'm trying to build a MUC platform with OMEMO encryption to be used on an Android app. I'm using Ejabberd (v17.11) and Smack library (v4.2.1).
MUC rooms are persistent and they allow_subscription for Muc/Sub support, for offline messages.
When a client starts a new room as 'owner' and adds 'member's from his roster; all the clients join the room and everything seem fine.
The owner can send messages to the group and it is delivered to every member.
But when a group member tries to send a message, if he doesn't 'know' all the members of the group (if they are not in his roster) he cannot send message!
I found out that, when sending OMEMO message to the group, it is necessary to encrypt the message separately for every member and this necessitates getting every members' devicelist!
On this step:
mOmemoManager.encrypt(muc, msgBody);
It tries to encrypt for all recipients but fetching an unknown user's device list causes crash.
SENT:
<iq to='unknownuser#server.com' id='141' type='get'><query xmlns='http://jabber.org/protocol/disco#info' node='eu.siacs.conversations.axolotl.devicelist'></query></iq>
RECV:
<iq xml:lang='en' to='myuser#server.com/mobile' from='unknownuser#server.com' type='error' id='141'><query node='eu.siacs.conversations.axolotl.devicelist' xmlns='http://jabber.org/protocol/disco#info'/><error code='407' type='auth'><subscription-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/><text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>Not subscribed</text></error></iq>
Smack's error:
Could not fetch device list of unknownuser#server.com: .....
XMPPError: subscription-required - auth
So, how I can solve this?
In chat groups every user don't have to meet each other. Should I add everyone to everyone's roster when they come together on a group?
Or is this something about room affiliations or roles?
Or something about Ejabberd configuration?
[{title,<<"groupName">>},
{allow_query_users,true},
{allow_private_messages,true},
{allow_private_messages_from_visitors,anyone},
{allow_visitor_status,true},
{allow_visitor_nickchange,true},
{public,false},
{public_list,false},
{persistent,true},
{moderated,true},
{members_by_default,true},
{members_only,true},
{allow_user_invites,true},
{anonymous,false},
{logging,false},
{allow_voice_requests,true},
{allow_subscription,true},
{mam,true},
{presence_broadcast,[moderator,participant,visitor]},
{voice_request_min_interval,1800},
{vcard,<<>>},
{captcha_whitelist,[]},
{affiliations,[{{<<"user1">>,<<"server.com">>,<<>>},{member,<<>>}}, {{<<"user2">>,<<"server.com">>,<<>>},{owner,<<>>}}, {{<<"user3">>,<<"server.com">>,<<>>},{member,<<>>}}]},
{subject,[]},
{subject_author,<<>>}]
OMEMO requires the sender to be able to read the recipients OMEMO pubsub node. This is necessary to fetch the recipients preKey bundle to build a session.
Modern implementations configure the OMEMO pubsub node to be public - there is also an ejabberd config to force this for legacy clients.
Most client implementations of OMEMO therefore restrict the encryption feature to be available in private group chats only. In this scenario all contacts are in each others rosters and have access to each others OMEMO nodes. Encrypting publicly available group chats doesn't make sense anyways as an attacker could simply join the chat in order to read messages.
If you want to configure your OMEMO pubsub nodes to be public from within your client, take a look at how smack-openpgp does change to access model.

Problems with WebSession when executing a WebService (GeneXus)

Here is the problem: I have a KB Called APP1 that will execute an WebService of an Identity Provider (centralizes all the logins/sessions for different applications) that will return true if there is a logged user in current WebSession that has been granted to access the Application or false otherwise. When I create an web panel at the same KB as the Identity Provider, it works just fine, I get TRUE when there's a logged user, and FALSE when there's not. But when I call it from APP1 it always returns false, I believe that the problem is because the WebSession won't work properly when called through an WS. Any ideas of how to solve it?
My first advice is to try using GAM Single Sign on (X Evolution 3)
WebServices should be Stateless. I think that using the Database instead of WebSession could do the job.
Nonetheless, in order to call a restful WebService you will have to do something more complex as dealing with CookieContainers as stated in the following link.
Consider this solution:
User tries to access App1
There's no web session (App1 doesn't know who is connecting)
App1 redirects User to an IdentityProvider's special login page
If User is not logged, it provides credentials and logs in
IdentityProvider has a session for the user (it knows who is connecting), then it redirects to the referer, appending to the url an encrypted userid parameter.
App1 decodes the parameter, now it knows who is connecting.
App1 saves the userid to the web session, now the user is authenticated
App1 and IdentityProvider must share an encryption key.
Consider that if the encryption key gets compromised or cracked anyone can impersonate another user.
Depending in how secure you want your system to be, you should study other security issues:
every time the user connects it's encrypted login is the same an it shows in the url, it can be easily solved adding a nonce or salt.
The system could be abused generating multiple requests until it gets a valid encrypted userid. It can be mitigated using a large Salt and/or blocking multiple attempts from the same source.
Note that this isn't a tested protocol and I didn't study the security in depth. I got some inspiration from OpenId, but this is a simplified protocol and I could be missing security holes.

Spring3, Security3, Hibernate, MYSQL - How to install user tracking into database

First Project: Spring3, Security3, Hibernate, MYSQL - How to install user tracking into database
I am working on my first project with Spring3, Security3, Hibernate, MYSQL.
I have the system working great I use Spring3 and Security3 goign to MySQL for the login and
using Spring3 MVC, Hibernate and MYSQL for system data.
I have a number of questions. Once I login does Spring Security save the user object somewhere that I can have
Hibrernate access it. I want Hibernate to put the user name or role into each insert to the database so as
I do my searches the system knows to only show data for that user and only that user?
this somes like it should be easy. Spring should be saving the user somewhere the hibernate can access.
please help me out
Once the user is authenticated, you can access the user's authentication session details:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityContext will allow you to grab the Authentication object, and from that you can retrieve the principal (an object representing the authenticated user), roles, etc. You could inspect this information and determine what data should be stored/displayed for each user.
If you can add a request filter or interceptor (the vocabulary may vary between frameworks), you could probably make these security checks abstract/generic enough to be applied across your entire web app (instead of adding a few lines of code to every resource method you're attempting to secure). Either way, SecurityContext should get you closer to what you want.