Projects tigase _server server-core Commits b1697d84
ctrl k
  • Add pre-processor to filter error messages based on RFC; #server-1344 (#190)

    Add pre-processor to filter error messages based on RFC; #server-1344
  • Loading...
  • Wojtek committed with GitHub 2 years ago
    b1697d84
    1 parent 4bbbe1cf
  • src/main/java/tigase/xmpp/impl/Message.java
    ■ ■ ■ ■ ■ ■
    skipped 73 lines
    74 74   public boolean preProcess(Packet packet, XMPPResourceConnection session, NonAuthUserRepository repo,
    75 75   Queue<Packet> results, Map<String, Object> settings) {
    76 76   boolean result = C2SDeliveryErrorProcessor.preProcess(packet, session, repo, results, settings, messageDeliveryLogic);
     77 + if (messageDeliveryLogic.preProcessFilter(packet, session)) {
     78 + return true;
     79 + }
    77 80   if (result) {
    78 81   packet.processedBy(id());
    79 82   }
    skipped 6 lines
  • src/main/java/tigase/xmpp/impl/MessageAmp.java
    ■ ■ ■ ■ ■ ■
    skipped 156 lines
    157 157   Queue<Packet> results, Map<String, Object> settings) {
    158 158   boolean processed = C2SDeliveryErrorProcessor.preProcess(packet, session, repo, results, settings,
    159 159   messageProcessor);
     160 + if (messageProcessor.preProcessFilter(packet, session)) {
     161 + return true;
     162 + }
    160 163   if (processed && packet.getPacketFrom() != null &&
    161 164   packet.getPacketFrom().getLocalpart().equals(ampJID.getLocalpart())) {
    162 165   processed = false;
    skipped 170 lines
  • src/main/java/tigase/xmpp/impl/MessageDeliveryLogic.java
    ■ ■ ■ ■ ■ ■
    skipped 24 lines
    25 25  import tigase.server.Packet;
    26 26  import tigase.server.xmppsession.PacketDefaultHandler;
    27 27  import tigase.server.xmppsession.SessionManager;
     28 +import tigase.vhosts.VHostManagerIfc;
    28 29  import tigase.xml.Element;
    29 30  import tigase.xmpp.*;
    30 31  import tigase.xmpp.jid.BareJID;
    skipped 20 lines
    51 52   private boolean silentlyIgnoreError = false;
    52 53   @Inject(nullAllowed = true)
    53 54   private SessionManager.MessageArchive messageArchive;
     55 + @Inject
     56 + private VHostManagerIfc vHostManager;
    54 57   
    55 58   private PacketDefaultHandler packetDefaultHandler = new PacketDefaultHandler();
    56 59   
    skipped 198 lines
    255 258   }
    256 259   } catch (NotAuthorizedException ex) {
    257 260   // should not happen, end even if it happend then we should return false
     261 + }
     262 + return false;
     263 + }
     264 + 
     265 + public boolean preProcessFilter(Packet packet, XMPPResourceConnection session) {
     266 + final StanzaType type = packet.getType();
     267 + // only handle messages within local domains; errors to external domains and components (i.e. mix, pubsub) will be delivered
     268 + if (type == StanzaType.error && vHostManager.isLocalDomain(packet.getStanzaTo().getDomain())) {
     269 + if (packet.getStanzaTo().getResource() == null) {
     270 + // 1) https://xmpp.org/rfcs/rfc6121.html#rules-localpart-barejid
     271 + //* 8.5.2.1. Available or Connected Resources > 8.5.2.1.1. Message
     272 + //> For a message stanza of type "error", the server MUST silently ignore the message.
     273 + //
     274 + //* 8.5.2.2. No Available or Connected Resources > 8.5.2.2.1. Message
     275 + //> For a message stanza of type "headline" or "error", the server MUST silently ignore the message.
     276 + //
     277 + return true;
     278 + } else {
     279 + //
     280 + //* 8.5.3.2. No Resource Matches > 8.5.3.2.1. Message
     281 + //> For a message stanza of type "error", the server MUST silently ignore the stanza.
     282 + if (session != null && session.getjid() != null && session.getjid().equals(packet.getStanzaTo())) {
     283 + // 2) https://xmpp.org/rfcs/rfc6121.html#rules-localpart-fulljid
     284 + //* 8.5.3.1. Resource Matches
     285 + //> For a message stanza, the server MUST deliver the stanza to the resource.
     286 + return false;
     287 + } else {
     288 + return true;
     289 + }
     290 + }
    258 291   }
    259 292   return false;
    260 293   }
    skipped 57 lines
  • src/test/java/tigase/server/xmppserver/S2SConnManAbstractTest.java
    ■ ■ ■ ■ ■
    skipped 31 lines
    32 32  import tigase.server.ConnectionManager;
    33 33  import tigase.server.Iq;
    34 34  import tigase.server.Packet;
    35  -import tigase.server.ServerComponent;
    36 35  import tigase.server.xmppserver.proc.AuthenticatorSelectorManager;
    37 36  import tigase.server.xmppserver.proc.Dialback;
    38 37  import tigase.server.xmppserver.proc.StartTLS;
    39 38  import tigase.util.dns.DNSEntry;
    40 39  import tigase.util.dns.DNSResolverFactory;
    41  -import tigase.util.stringprep.TigaseStringprepException;
    42  -import tigase.vhosts.VHostItem;
    43  -import tigase.vhosts.VHostItemImpl;
     40 +import tigase.vhosts.DummyVHostManager;
    44 41  import tigase.vhosts.VHostManagerIfc;
    45 42  import tigase.xml.Element;
    46 43  import tigase.xmpp.StanzaType;
    47  -import tigase.xmpp.jid.BareJID;
    48  -import tigase.xmpp.jid.JID;
    49 44   
    50 45  import java.io.IOException;
    51 46  import java.io.StringWriter;
    52 47  import java.net.UnknownHostException;
    53 48  import java.util.*;
    54  -import java.util.concurrent.ConcurrentHashMap;
    55 49  import java.util.concurrent.TimeUnit;
    56 50  import java.util.function.Consumer;
    57 51  import java.util.logging.Level;
    58 52  import java.util.logging.Logger;
    59  -import java.util.stream.Collectors;
    60 53   
    61 54  import static tigase.net.IOService.CERT_CHECK_RESULT;
    62 55   
    skipped 32 lines
    95 88   kernel.registerBean(DummyDialbackImpl.class).exportable().setActive(true).exec();
    96 89   kernel.registerBean(AuthenticatorSelectorManager.class).exportable().setActive(true).exec();
    97 90   kernel.registerBean("vHostManager")
    98  - .asClass(S2SConnManTest.DummyVHostManager.class)
     91 + .asClass(DummyVHostManager.class)
    99 92   .exportable()
    100 93   .setActive(true)
    101 94   .exec();
    skipped 30 lines
    132 125   
    133 126   protected static void setupCID(String localHostname, String remoteHostname) {
    134 127   cid = new CID(localHostname, remoteHostname);
    135  - final S2SConnManTest.DummyVHostManager instance = (S2SConnManTest.DummyVHostManager) kernel.getInstance(
     128 + final DummyVHostManager instance = (DummyVHostManager) kernel.getInstance(
    136 129   VHostManagerIfc.class);
    137 130   if (instance.getVHostItem(localHostname) == null) {
    138 131   instance.addVhost(localHostname);
    skipped 138 lines
    277 270   serv.getSessionData().put("dialback", "completed");
    278 271   }
    279 272   return super.process(p, serv, results);
    280  - }
    281  - }
    282  - 
    283  - /**
    284  - * Dummy {@code VHostManagerIfc} implementation, mostly to avoid exceptions in Dialback processor
    285  - */
    286  - public static class DummyVHostManager
    287  - implements VHostManagerIfc {
    288  - 
    289  - Map<String, VHostItem> items = new ConcurrentHashMap<>();
    290  - 
    291  - public DummyVHostManager() {
    292  - }
    293  - 
    294  - public void addVhost(String vhost) {
    295  - 
    296  - try {
    297  - VHostItem item = new VHostItemImpl(vhost);
    298  - items.put(vhost, item);
    299  - } catch (TigaseStringprepException e) {
    300  - log.log(Level.WARNING, "Adding VHost failed", e);
    301  - }
    302  - }
    303  - 
    304  - @Override
    305  - public boolean isLocalDomain(String domain) {
    306  - return false;
    307  - }
    308  - 
    309  - @Override
    310  - public boolean isLocalDomainOrComponent(String domain) {
    311  - return items.containsKey(domain);
    312  - }
    313  - 
    314  - @Override
    315  - public boolean isAnonymousEnabled(String domain) {
    316  - return false;
    317  - }
    318  - 
    319  - @Override
    320  - public ServerComponent[] getComponentsForLocalDomain(String domain) {
    321  - return new ServerComponent[0];
    322  - }
    323  - 
    324  - @Override
    325  - public ServerComponent[] getComponentsForNonLocalDomain(String domain) {
    326  - return new ServerComponent[0];
    327  - }
    328  - 
    329  - @Override
    330  - public VHostItem getVHostItem(String domain) {
    331  - return items.get(domain);
    332  - }
    333  - 
    334  - @Override
    335  - public VHostItem getVHostItemDomainOrComponent(String domain) {
    336  - return items.get(domain);
    337  - }
    338  - 
    339  - @Override
    340  - public void addComponentDomain(String domain) {
    341  - 
    342  - }
    343  - 
    344  - @Override
    345  - public void removeComponentDomain(String domain) {
    346  - 
    347  - }
    348  - 
    349  - @Override
    350  - public BareJID getDefVHostItem() {
    351  - return items.values()
    352  - .stream()
    353  - .map(VHostItem::getVhost)
    354  - .map(JID::toString)
    355  - .map(BareJID::bareJIDInstanceNS)
    356  - .findFirst()
    357  - .orElse(BareJID.bareJIDInstanceNS("not@available"));
    358  - }
    359  - 
    360  - @Override
    361  - public List<JID> getAllVHosts() {
    362  - return items.values().stream().map(VHostItem::getVhost).collect(Collectors.toList());
    363 273   }
    364 274   }
    365 275   
    skipped 124 lines
  • src/test/java/tigase/vhosts/DummyVHostManager.java
    ■ ■ ■ ■ ■ ■
     1 +/*
     2 + * Tigase XMPP Server - The instant messaging server
     3 + * Copyright (C) 2004 Tigase, Inc. (office@tigase.com)
     4 + *
     5 + * This program is free software: you can redistribute it and/or modify
     6 + * it under the terms of the GNU Affero General Public License as published by
     7 + * the Free Software Foundation, version 3 of the License.
     8 + *
     9 + * This program is distributed in the hope that it will be useful,
     10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12 + * GNU Affero General Public License for more details.
     13 + *
     14 + * You should have received a copy of the GNU Affero General Public License
     15 + * along with this program. Look for COPYING file in the top folder.
     16 + * If not, see http://www.gnu.org/licenses/.
     17 + */
     18 + 
     19 +package tigase.vhosts;
     20 + 
     21 +import tigase.server.ServerComponent;
     22 +import tigase.util.stringprep.TigaseStringprepException;
     23 +import tigase.xmpp.jid.BareJID;
     24 +import tigase.xmpp.jid.JID;
     25 + 
     26 +import java.util.List;
     27 +import java.util.Map;
     28 +import java.util.concurrent.ConcurrentHashMap;
     29 +import java.util.logging.Level;
     30 +import java.util.logging.Logger;
     31 +import java.util.stream.Collectors;
     32 + 
     33 +/**
     34 + * Dummy {@code VHostManagerIfc} implementation
     35 + */
     36 +public class DummyVHostManager
     37 + implements VHostManagerIfc {
     38 + 
     39 + private final static Logger LOG = Logger.getLogger(DummyVHostManager.class.getName());
     40 + private final Map<String, VHostItem> items = new ConcurrentHashMap<>();
     41 + 
     42 + public DummyVHostManager() {
     43 + }
     44 + 
     45 + @Override
     46 + public void addComponentDomain(String domain) {
     47 + 
     48 + }
     49 + 
     50 + public void addVhost(String vhost) {
     51 + 
     52 + try {
     53 + VHostItem item = new VHostItemImpl(vhost);
     54 + items.put(vhost, item);
     55 + } catch (TigaseStringprepException e) {
     56 + LOG.log(Level.WARNING, "Adding VHost failed", e);
     57 + }
     58 + }
     59 + 
     60 + @Override
     61 + public List<JID> getAllVHosts() {
     62 + return items.values().stream().map(VHostItem::getVhost).collect(Collectors.toList());
     63 + }
     64 + 
     65 + @Override
     66 + public ServerComponent[] getComponentsForLocalDomain(String domain) {
     67 + return new ServerComponent[0];
     68 + }
     69 + 
     70 + @Override
     71 + public ServerComponent[] getComponentsForNonLocalDomain(String domain) {
     72 + return new ServerComponent[0];
     73 + }
     74 + 
     75 + @Override
     76 + public BareJID getDefVHostItem() {
     77 + return items.values()
     78 + .stream()
     79 + .map(VHostItem::getVhost)
     80 + .map(JID::toString)
     81 + .map(BareJID::bareJIDInstanceNS)
     82 + .findFirst()
     83 + .orElse(BareJID.bareJIDInstanceNS("not@available"));
     84 + }
     85 + 
     86 + @Override
     87 + public VHostItem getVHostItem(String domain) {
     88 + return items.get(domain);
     89 + }
     90 + 
     91 + @Override
     92 + public VHostItem getVHostItemDomainOrComponent(String domain) {
     93 + return items.get(domain);
     94 + }
     95 + 
     96 + @Override
     97 + public boolean isAnonymousEnabled(String domain) {
     98 + return false;
     99 + }
     100 + 
     101 + @Override
     102 + public boolean isLocalDomain(String domain) {
     103 + return items.containsKey(domain);
     104 + }
     105 + 
     106 + @Override
     107 + public boolean isLocalDomainOrComponent(String domain) {
     108 + return items.containsKey(domain);
     109 + }
     110 + 
     111 + @Override
     112 + public void removeComponentDomain(String domain) {
     113 + 
     114 + }
     115 +}
     116 + 
  • src/test/java/tigase/xmpp/impl/MessageDeliveryLogicTest.java
    ■ ■ ■ ■ ■ ■
     1 +/*
     2 + * Tigase XMPP Server - The instant messaging server
     3 + * Copyright (C) 2004 Tigase, Inc. (office@tigase.com)
     4 + *
     5 + * This program is free software: you can redistribute it and/or modify
     6 + * it under the terms of the GNU Affero General Public License as published by
     7 + * the Free Software Foundation, version 3 of the License.
     8 + *
     9 + * This program is distributed in the hope that it will be useful,
     10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     12 + * GNU Affero General Public License for more details.
     13 + *
     14 + * You should have received a copy of the GNU Affero General Public License
     15 + * along with this program. Look for COPYING file in the top folder.
     16 + * If not, see http://www.gnu.org/licenses/.
     17 + */
     18 +package tigase.xmpp.impl;
     19 + 
     20 +import org.junit.Before;
     21 +import org.junit.Test;
     22 +import tigase.kernel.core.Kernel;
     23 +import tigase.server.Packet;
     24 +import tigase.vhosts.DummyVHostManager;
     25 +import tigase.xml.Element;
     26 +import tigase.xmpp.jid.BareJID;
     27 +import tigase.xmpp.jid.JID;
     28 + 
     29 +import java.util.UUID;
     30 + 
     31 +import static org.junit.Assert.assertFalse;
     32 +import static org.junit.Assert.assertTrue;
     33 + 
     34 +/**
     35 + * @author andrzej
     36 + */
     37 +public class MessageDeliveryLogicTest
     38 + extends ProcessorTestCase {
     39 + 
     40 + final static String domain = "example.com";
     41 + private MessageDeliveryLogic messageDeliveryLogic;
     42 + 
     43 + @Override
     44 + protected void registerBeans(Kernel kernel) {
     45 + super.registerBeans(kernel);
     46 + kernel.registerBean(MessageDeliveryLogic.class).exec();
     47 + }
     48 + 
     49 + @Before
     50 + @Override
     51 + public void setUp() throws Exception {
     52 + super.setUp();
     53 + messageDeliveryLogic = getInstance(MessageDeliveryLogic.class);
     54 + var vHostManager = getInstance(DummyVHostManager.class);
     55 + vHostManager.addVhost(domain);
     56 + }
     57 + 
     58 + @Test
     59 + public void testProcessingErrorMessageBareJidOffline() throws Exception {
     60 + var destinationUserJid = BareJID.bareJIDInstance("user1", domain);
     61 + var packetElelement = new Element("message", new String[]{"type", "from", "to"},
     62 + new String[]{"error", "remote-user@test.com/res1",
     63 + destinationUserJid.toString()});
     64 + var packet = Packet.packetInstance(packetElelement);
     65 + final boolean block = messageDeliveryLogic.preProcessFilter(packet, null);
     66 + assertTrue("BareJID: No Available or Connected Resources > 8.5.2.2.1. Message: drop message", block);
     67 + }
     68 + 
     69 + @Test
     70 + public void testProcessingErrorMessageBareJidOnline() throws Exception {
     71 + var destinationUserJid = BareJID.bareJIDInstance("user1", domain);
     72 + var fullDestinationJid = JID.jidInstance(destinationUserJid, "res1");
     73 + var session = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID()),
     74 + fullDestinationJid);
     75 + 
     76 + var packetElelement = new Element("message", new String[]{"type", "from", "to"},
     77 + new String[]{"error", "remote-user@test.com/res1",
     78 + destinationUserJid.toString()});
     79 + var packet = Packet.packetInstance(packetElelement);
     80 + final boolean block = messageDeliveryLogic.preProcessFilter(packet, session);
     81 + assertTrue("BareJID: Available or Connected Resources > 8.5.2.1.1. Message: drop message", block);
     82 + }
     83 + 
     84 + @Test
     85 + public void testProcessingErrorMessageFullJidOnlineWithMatchingResource() throws Exception {
     86 + var destinationUserJid = BareJID.bareJIDInstance("user1", domain);
     87 + var fullDestinationJid = JID.jidInstance(destinationUserJid, "res1");
     88 + var session = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID()),
     89 + fullDestinationJid);
     90 + 
     91 + var packetElelement = new Element("message", new String[]{"type", "from", "to"},
     92 + new String[]{"error", "remote-user@test.com/res1",
     93 + fullDestinationJid.toString()});
     94 + var packet = Packet.packetInstance(packetElelement);
     95 + final boolean block = messageDeliveryLogic.preProcessFilter(packet, session);
     96 + assertFalse("FullJID: 8.5.3.1. Resource Matches. Message: deliver message", block);
     97 + }
     98 + 
     99 + @Test
     100 + public void testProcessingErrorMessageFullJidOnlineWithouthMatchingResource() throws Exception {
     101 + var destinationUserJid = BareJID.bareJIDInstance("user1", domain);
     102 + var fullDestinationJidPacketTo = JID.jidInstance(destinationUserJid, "res1");
     103 + var fullDestinationJidSession = JID.jidInstance(destinationUserJid, "res2");
     104 + var session = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID()),
     105 + fullDestinationJidSession);
     106 + 
     107 + var packetElelement = new Element("message", new String[]{"type", "from", "to"},
     108 + new String[]{"error", "remote-user@test.com/res1",
     109 + fullDestinationJidPacketTo.toString()});
     110 + var packet = Packet.packetInstance(packetElelement);
     111 + final boolean block = messageDeliveryLogic.preProcessFilter(packet, session);
     112 + assertTrue("FullJID: No Resource Matches > 8.5.3.2.1. Message: drop message", block);
     113 + }
     114 + 
     115 + @Test
     116 + public void testProcessingErrorMessagePubSubPayload() throws Exception {
     117 + 
     118 + var destinationChannelJid = JID.jidInstance("channel", "mix." + domain, UUID.randomUUID().toString());
     119 + var session = getSession(JID.jidInstance("c2s@example.com/" + UUID.randomUUID()),
     120 + JID.jidInstance("user1@example.com/res1"));
     121 + 
     122 + var packetElelement = new Element("message", new String[]{"type", "from", "to"},
     123 + new String[]{"error", "remote-user@test.com/res1",
     124 + destinationChannelJid.toString()});
     125 + var packet = Packet.packetInstance(packetElelement);
     126 + boolean block = messageDeliveryLogic.preProcessFilter(packet, session);
     127 + assertFalse("Message error addressed to PubSub/MIX should be correctly forwarded to the component", block);
     128 + 
     129 + var destinationChannelFullJid = BareJID.bareJIDInstance("channel", "mix." + domain);
     130 + packetElelement = new Element("message", new String[]{"type", "from", "to"},
     131 + new String[]{"error", "remote-user@test.com/res1",
     132 + destinationChannelFullJid.toString()});
     133 + packet = Packet.packetInstance(packetElelement);
     134 + block = messageDeliveryLogic.preProcessFilter(packet, session);
     135 + assertFalse("Message error addressed to PubSub/MIX should be correctly forwarded to the component", block);
     136 + }
     137 +}
     138 + 
  • src/test/java/tigase/xmpp/impl/ProcessorTestCase.java
    ■ ■ ■ ■ ■ ■
    skipped 20 lines
    21 21  import org.junit.Before;
    22 22  import tigase.TestLogger;
    23 23  import tigase.kernel.AbstractKernelWithUserRepositoryTestCase;
     24 +import tigase.kernel.core.Kernel;
    24 25  import tigase.server.Packet;
    25 26  import tigase.server.PacketWriterWithTimeout;
    26 27  import tigase.server.xmppsession.SessionManagerHandler;
    27 28  import tigase.util.stringprep.TigaseStringprepException;
     29 +import tigase.vhosts.DummyVHostManager;
    28 30  import tigase.vhosts.VHostItemImpl;
    29 31  import tigase.xmpp.NotAuthorizedException;
    30 32  import tigase.xmpp.XMPPResourceConnection;
    skipped 24 lines
    55 57   @Before
    56 58   public void setSessionManager() throws Exception {
    57 59   loginHandler = new SessionManagerHandlerImpl();
     60 + }
     61 + 
     62 + @Override
     63 + protected void registerBeans(Kernel kernel) {
     64 + super.registerBeans(kernel);
     65 + kernel.registerBean("vHostManager")
     66 + .asClass(DummyVHostManager.class)
     67 + .exportable()
     68 + .setActive(true)
     69 + .exec();
    58 70   }
    59 71   
    60 72   @After
    skipped 118 lines
Please wait...
Page is in error, reload to recover