Commit 1c07320a authored by Axel Brand's avatar Axel Brand Committed by daeva

Finished Refactoring for GoJara 2.0, testing and finetuning coming up.

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/branches/plugins@13546 b35dd754-fafc-0310-a699-88a17e54d16e
parent a660277a
...@@ -44,6 +44,17 @@ ...@@ -44,6 +44,17 @@
GoJara Plugin Changelog GoJara Plugin Changelog
</h1> </h1>
<p><b>2.0.0</b> -- Mar 07, 2013</p>
<ul>
<li>Major refactoring of the Interceptor- and Processor-Structure used by GoJara</li>
<li>One-Interceptor structure should allow easier Debugging & control of Features</li>
<li>We completely ignore Packets with malformed JIDs now, this should cause less Warnings/Errors</li>
<li>Freezing the Interceptor on Destroy of the Plugin should make GoJara properly shutdown and not cause trouble on reload/update</li>
<li>Optimized Processors have better performance</li>
</ul>
<p><b>1.2.5</b> -- Feb 22, 2013</p> <p><b>1.2.5</b> -- Feb 22, 2013</p>
<ul> <ul>
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
<name>GoJara</name> <name>GoJara</name>
<description>ProtoXEP-xxxx: Remote Roster Management support</description> <description>ProtoXEP-xxxx: Remote Roster Management support</description>
<author>Holger Bergunde and Daniel Henninger</author> <author>Holger Bergunde / Daniel Henninger / Axel-F. Brand</author>
<version>1.2.5</version> <version>2.0.0</version>
<date>02/22/2013</date> <date>03/07/2013</date>
<databaseKey>gojara</databaseKey> <databaseKey>gojara</databaseKey>
<databaseVersion>0</databaseVersion> <databaseVersion>0</databaseVersion>
<minServerVersion>3.7.0</minServerVersion> <minServerVersion>3.7.0</minServerVersion>
......
...@@ -31,6 +31,7 @@ import org.xmpp.packet.JID; ...@@ -31,6 +31,7 @@ import org.xmpp.packet.JID;
/** /**
* @author Holger Bergunde * @author Holger Bergunde
* @author axel.frederik.brand
* *
* This class is the basic reprasentation for the GoJara plugin. It is * This class is the basic reprasentation for the GoJara plugin. It is
* the entry point for openfire to start or stop this plugin. * the entry point for openfire to start or stop this plugin.
...@@ -47,8 +48,6 @@ public class RemoteRosterPlugin implements Plugin { ...@@ -47,8 +48,6 @@ public class RemoteRosterPlugin implements Plugin {
private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class); private static final Logger Log = LoggerFactory.getLogger(RemoteRosterPlugin.class);
private static PluginManager pluginManager; private static PluginManager pluginManager;
// private final SessionManager _sessionManager = SessionManager.getInstance();
// private Map<String, AbstractInterceptorHandler> _interceptors = new HashMap<String, AbstractInterceptorHandler>();
private Set<String> _waitingForIQResponse = new HashSet<String>(); private Set<String> _waitingForIQResponse = new HashSet<String>();
private PropertyEventListener _settingsObserver; private PropertyEventListener _settingsObserver;
private MainInterceptor mainInterceptor = new MainInterceptor(); private MainInterceptor mainInterceptor = new MainInterceptor();
...@@ -62,7 +61,6 @@ public class RemoteRosterPlugin implements Plugin { ...@@ -62,7 +61,6 @@ public class RemoteRosterPlugin implements Plugin {
manageExternalComponents(); manageExternalComponents();
listenToSettings(); listenToSettings();
Log.debug("Started Gojara successfully. Currently running interceptors: "+iManager.getInterceptors().size()); Log.debug("Started Gojara successfully. Currently running interceptors: "+iManager.getInterceptors().size());
} }
/* /*
...@@ -134,9 +132,7 @@ public class RemoteRosterPlugin implements Plugin { ...@@ -134,9 +132,7 @@ public class RemoteRosterPlugin implements Plugin {
} }
public void destroyPlugin() { public void destroyPlugin() {
// for (String key : _interceptors.keySet()) {
// _interceptors.get(key).stop();
// }
mainInterceptor.freeze(); mainInterceptor.freeze();
iManager.removeInterceptor(mainInterceptor); iManager.removeInterceptor(mainInterceptor);
PropertyEventDispatcher.removeListener(_settingsObserver); PropertyEventDispatcher.removeListener(_settingsObserver);
...@@ -147,14 +143,8 @@ public class RemoteRosterPlugin implements Plugin { ...@@ -147,14 +143,8 @@ public class RemoteRosterPlugin implements Plugin {
private void updateInterceptors(String componentJID) { private void updateInterceptors(String componentJID) {
boolean allowed = JiveGlobals.getBooleanProperty("plugin.remoteroster.jids." + componentJID, false); boolean allowed = JiveGlobals.getBooleanProperty("plugin.remoteroster.jids." + componentJID, false);
if (allowed) { if (allowed) {
// if (!_interceptors.containsKey(componentJID)) {
// createNewPackageIntercetor(componentJID);
// }
mainInterceptor.addTransport(componentJID); mainInterceptor.addTransport(componentJID);
} else { } else {
// if (_interceptors.containsKey(componentJID)) {
// removeInterceptor(componentJID);
// }
mainInterceptor.removeTransport(componentJID); mainInterceptor.removeTransport(componentJID);
} }
} }
...@@ -168,25 +158,4 @@ public class RemoteRosterPlugin implements Plugin { ...@@ -168,25 +158,4 @@ public class RemoteRosterPlugin implements Plugin {
return pluginManager; return pluginManager;
} }
// private void removeInterceptor(String initialSubdomain) {
// mainInterceptor.removeTransport(initialSubdomain);
//// AbstractInterceptorHandler interceptor = _interceptors.get(initialSubdomain);
//// if (interceptor != null) {
//// _interceptors.remove(initialSubdomain);
//// interceptor.stop();
//// }
// }
//
// /*
// * We are handling all our gateways in a Map with subdomain, like
// * icq.myserver.com, to ensure that there is only one interceptor for a
// * specified gateway
// */
// private void createNewPackageIntercetor(String initialSubdomain) {
// mainInterceptor.addTransport(initialSubdomain);
//// AbstractInterceptorHandler interceptor = new GatewayInterceptorHandler(initialSubdomain);
//// _interceptors.put(initialSubdomain, interceptor);
//// interceptor.start();
// }
} }
...@@ -24,22 +24,18 @@ public class MainInterceptor implements PacketInterceptor { ...@@ -24,22 +24,18 @@ public class MainInterceptor implements PacketInterceptor {
private Set<String> activeTransports = new ConcurrentHashSet<String>(); private Set<String> activeTransports = new ConcurrentHashSet<String>();
private Map<String, AbstractRemoteRosterProcessor> packetProcessors = new HashMap<String, AbstractRemoteRosterProcessor>(); private Map<String, AbstractRemoteRosterProcessor> packetProcessors = new HashMap<String, AbstractRemoteRosterProcessor>();
private String serverDomain; private String serverDomain;
private Boolean frozen; private Boolean frozen;
public MainInterceptor() { public MainInterceptor() {
Log.debug("Started MainInterceptor for GoJara Plugin."); Log.debug("Started MainInterceptor for GoJara Plugin.");
XMPPServer server = XMPPServer.getInstance(); XMPPServer server = XMPPServer.getInstance();
serverDomain = server.getServerInfo().getXMPPDomain(); serverDomain = server.getServerInfo().getXMPPDomain();
//Now we need to add the PacketProcessors.
RosterManager rosterMananger = server.getRosterManager(); RosterManager rosterMananger = server.getRosterManager();
AbstractRemoteRosterProcessor updateToComponent = new ClientToComponentUpdateProcessor(); AbstractRemoteRosterProcessor updateToComponent = new ClientToComponentUpdateProcessor();
AbstractRemoteRosterProcessor iqRegistered = new DiscoIQRegisteredProcessor(); AbstractRemoteRosterProcessor iqRegistered = new DiscoIQRegisteredProcessor();
AbstractRemoteRosterProcessor iqRosterPayload = new IQRosterPayloadProcessor(rosterMananger); AbstractRemoteRosterProcessor iqRosterPayload = new IQRosterPayloadProcessor(rosterMananger);
AbstractRemoteRosterProcessor nonPersistant = new NonPersistantRosterProcessor(rosterMananger); AbstractRemoteRosterProcessor nonPersistant = new NonPersistantRosterProcessor(rosterMananger);
// Check if we need rostermanager for these....
AbstractRemoteRosterProcessor statisticsProcessor = new StatisticsProcessor(); AbstractRemoteRosterProcessor statisticsProcessor = new StatisticsProcessor();
AbstractRemoteRosterProcessor iqLastProcessor = new IQLastProcessor(); AbstractRemoteRosterProcessor iqLastProcessor = new IQLastProcessor();
AbstractRemoteRosterProcessor whitelistProcessor = new WhitelistProcessor(); AbstractRemoteRosterProcessor whitelistProcessor = new WhitelistProcessor();
...@@ -79,7 +75,6 @@ public class MainInterceptor implements PacketInterceptor { ...@@ -79,7 +75,6 @@ public class MainInterceptor implements PacketInterceptor {
As our Set of Subdomains is a Hash of Strings like icq.domain.tld, if we As our Set of Subdomains is a Hash of Strings like icq.domain.tld, if we
want to check if a jid CONTAINS a watched subdomain we need to iterate over the set. want to check if a jid CONTAINS a watched subdomain we need to iterate over the set.
We also return the subdomain as a string so we can use it if we find it. We also return the subdomain as a string so we can use it if we find it.
*
*/ */
private String searchJIDforSubdomain(String jid) { private String searchJIDforSubdomain(String jid) {
for (String subdomain : activeTransports) { for (String subdomain : activeTransports) {
...@@ -113,48 +108,49 @@ public class MainInterceptor implements PacketInterceptor { ...@@ -113,48 +108,49 @@ public class MainInterceptor implements PacketInterceptor {
from = (packet.getFrom() != null) ? packet.getFrom().toString() : ""; from = (packet.getFrom() != null) ? packet.getFrom().toString() : "";
to = (packet.getTo() != null) ? packet.getTo().toString() : ""; to = (packet.getTo() != null) ? packet.getTo().toString() : "";
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
Log.warn("There was an illegal JID while intercepting Message for GoJara! "+e.getMessage()); Log.warn("There was an illegal JID while intercepting Message for GoJara. Not Intercepting it! "+e.getMessage());
return; return;
} }
//We dont want this to get too packed, so here we test only for stuff we can test on PACKET
//We dont want this to get too packed, so here we test only for stuff we can test on PACKET + Instanceof
if (incoming && processed) { if (incoming && processed) {
Log.debug("Incoming processed Package i might be interested in. I'm "+ this.hashCode() + "\n Package: \n " + packet.toString() + "\n"); Log.debug("Incoming processed Package i might be interested in. I'm "+ this.hashCode() + "\n Package: \n " + packet.toString() + "\n");
//if to is Empty, this might be a Client to Component Update we have to forward. //if to is Empty, this might be a Client to Component Update we have to forward.
if (to.isEmpty()) if (to.isEmpty())
packetProcessors.get("clientToComponentUpdate").process(packet, generateSubdomainString()); packetProcessors.get("clientToComponentUpdate").process(packet, generateSubdomainString(), to, from);
//This might be a Disco IQ from the SERVER itself, so we have to check for Acess-Restriction //if to is equal to a subdomain of a INCOMING package we need to check if its for registering
else if (activeTransports.contains(to) && packet instanceof IQ) else if (activeTransports.contains(to) && packet instanceof IQ)
packetProcessors.get("sparkIQRegistered").process(packet,to); packetProcessors.get("sparkIQRegistered").process(packet,to, to, from);
//If FROM EQUALS a watched subdomain, we test for IQ:ROSTER Payload, we test for "" again as we cant be sure from is not empty //If from EQUALS the subdomain, this is likely a RosterPush or Presence we have to react to.
else if (!from.isEmpty() && activeTransports.contains(from)) { else if (!from.isEmpty() && activeTransports.contains(from)) {
//If from EQUALS the subdomain, this is likely a RosterPush or Presence we have to react to.
if (packet instanceof IQ) if (packet instanceof IQ)
packetProcessors.get("iqRosterPayload").process(packet,from); packetProcessors.get("iqRosterPayload").process(packet,from, to, from);
//it could also be a presence from Transport, so we test for Non-Persistancy //it could also be a presence from Transport, so we test for Non-Persistancy
else if (!JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false) && (packet instanceof Presence)) else if (packet instanceof Presence && !JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false))
packetProcessors.get("handleNonPersistant").process(packet,from); packetProcessors.get("handleNonPersistant").process(packet,from, to, from);
} }
//Functionality Processors for this Case are Done, now Logging. We need to be sure its not //Functionality Processors for this Case are Done, now Logging. We need to be sure its not
//The Ping Spectrum send itself, and one of from or to contains a watched subdomain. //The Ping Spectrum send itself, and one of from or to contains a watched subdomain.
String from_s = searchJIDforSubdomain(from); String from_s = searchJIDforSubdomain(from);
String to_s = searchJIDforSubdomain(to); String to_s = searchJIDforSubdomain(to);
String subdomain = from_s.isEmpty() ? to_s : from_s; String subdomain = from_s.isEmpty() ? to_s : from_s;
if (!from.equals(to) && !subdomain.isEmpty()) if (!from.equals(to) && !subdomain.isEmpty() && !(from.isEmpty() && to.isEmpty()) && packet instanceof IQ)
packetProcessors.get("statisticsProcessor").process(packet,subdomain); packetProcessors.get("statisticsProcessor").process(packet,subdomain, to, from);
} }
else if (incoming && !processed) { else if (incoming && !processed && JiveGlobals.getBooleanProperty("plugin.remoteroster.iqLastFilter", false)) {
Log.debug("Incoming unprocessed Package i might be interested in. I'm "+ this.hashCode() + "\n Package: \n " + packet.toString() + "\n"); Log.debug("Incoming unprocessed Package i might be interested in. I'm "+ this.hashCode() + "\n Package: \n " + packet.toString() + "\n");
// if to is EQUAL to the subdomain or a string containing a subdomain // if to is EQUAL to the subdomain or a string containing a subdomain
String to_s = searchJIDforSubdomain(to); String subdomain = searchJIDforSubdomain(to);
if (!to_s.isEmpty()) if (!subdomain.isEmpty() && packet instanceof IQ)
packetProcessors.get("iqLastProcessor").process(packet,to_s); packetProcessors.get("iqLastProcessor").process(packet,subdomain, to, from);
} }
else if(!incoming && processed) { else if(!incoming && processed) {
Log.debug("Outgoing processed Package i might be interested in. I'm "+ this.hashCode() + "\n Package: \n " + packet.toString() + "\n"); Log.debug("Outgoing processed Package i might be interested in. I'm "+ this.hashCode() + " Package: \n " + packet.toString() + "\n");
if (from.isEmpty() || from.equals(serverDomain)) if ((from.isEmpty() || from.equals(serverDomain)) && packet instanceof IQ)
packetProcessors.get("whiteListProcessor").process(packet); //This might be a Disco IQ from the SERVER itself, so we have to check for Acess-Restriction
packetProcessors.get("whiteListProcessor").process(packet, generateSubdomainString(), to, from);
//If we want the StatisticsProcessor to diff between Outgoing and Incoming, it would go here //If we want the StatisticsProcessor to diff between Outgoing and Incoming, it would go here
} }
} }
......
package org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors;
import java.util.List;
import org.dom4j.Element;
import org.dom4j.Node;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.permissions.PermissionManager;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* If the access to external components or gateways is limited to a special
* group in GoJara settings we have to filter the disco#infos from the server to
* the client. If the user is not on the list we are hiding the specified info
* and remove the item containing the gateways subdomain
*
* @author Holger Bergunde
*
*/
public class DiscoPackageInterceptorHandler implements PacketInterceptor {
private PermissionManager _permissions;
private String _subDomain;
private String _host;
public DiscoPackageInterceptorHandler(String subdomain) {
_permissions = new PermissionManager();
_subDomain = subdomain;
XMPPServer server = XMPPServer.getInstance();
_host = server.getServerInfo().getHostname();
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException {
if (_permissions.isGatewayLimited(_subDomain)) {
if (packet instanceof IQ) {
IQ iqpacket = (IQ) packet;
Element root = iqpacket.getChildElement();
if (root == null)
return;
String ns = root.getNamespaceURI();
if (ns.equals("http://jabber.org/protocol/disco#items") && iqpacket.getType().equals(IQ.Type.result)) {
if (!_permissions.allowedForUser(_subDomain, iqpacket.getTo())) {
if (iqpacket.getFrom().toString().equals(_host)) {
List<Node> nodes = XpathHelper.findNodesInDocument(root.getDocument(), "//discoitems:item");
for (Node node : nodes) {
if (node.valueOf("@jid").equals(_subDomain)) {
root.remove(node);
}
}
}
}
}
}
}
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* Some clients try to check how long a contact is already offline. This feature
* is not supported by spectrum so it won't response to this IQ stanza. To
* prevent the client from waiting for a response we could answer with a
* service-unavailable message as described in XEP-12.
*
* @author Holger Bergunde
*
*/
public class IQLastInterceptor implements PacketInterceptor {
private String _subDomain;
protected static final Logger Log = LoggerFactory.getLogger(IQLastInterceptor.class);
public IQLastInterceptor(String subdomain) {
Log.debug("Createt IQLastInterceptor for " + subdomain);
_subDomain = subdomain;
}
@Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed)
throws PacketRejectedException {
if (!iqLastInterceptorEnabled()) {
Log.debug("Auto repsonse to jabber:iq:last is deactivated. You could enabled it using the webinterface ");
return;
}
if (packet instanceof IQ && incoming && processed) {
IQ iqpacket = (IQ) packet;
if (iqpacket.getTo() == null || !iqpacket.getTo().toString().contains(_subDomain))
return;
Element root = iqpacket.getChildElement();
if (root == null)
return;
String ns = root.getNamespaceURI();
if (ns.equals("jabber:iq:last") && iqpacket.getType().equals(IQ.Type.get)) {
IQ answer = new IQ();
answer.setType(IQ.Type.error);
answer.setFrom(iqpacket.getTo());
answer.setTo(iqpacket.getFrom());
answer.setID(iqpacket.getID());
DefaultElement errorElement = new DefaultElement("error");
errorElement.addAttribute("type", "cancel");
errorElement.addAttribute("code", "503");
DefaultElement serviceElement = new DefaultElement("service-unavailable");
serviceElement.addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
errorElement.add(serviceElement);
answer.setChildElement(errorElement);
Log.debug("Auto response to jabber:iq:last for " + _subDomain);
PacketRouter router = XMPPServer.getInstance().getPacketRouter();
router.route(answer);
}
}
}
private boolean iqLastInterceptorEnabled() {
return JiveGlobals.getBooleanProperty("plugin.remoteroster.iqLastFilter", false);
}
}
...@@ -7,7 +7,6 @@ import org.dom4j.Node; ...@@ -7,7 +7,6 @@ import org.dom4j.Node;
import org.jivesoftware.openfire.PacketRouter; import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.XMPPServer; import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper; import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -20,6 +19,7 @@ import org.xmpp.packet.Packet; ...@@ -20,6 +19,7 @@ import org.xmpp.packet.Packet;
* this processor and redirect packages according to their functionality * this processor and redirect packages according to their functionality
* *
* @author Holger Bergunde * @author Holger Bergunde
* @author axel.frederik.brand
* *
*/ */
abstract public class AbstractRemoteRosterProcessor { abstract public class AbstractRemoteRosterProcessor {
...@@ -35,18 +35,19 @@ abstract public class AbstractRemoteRosterProcessor { ...@@ -35,18 +35,19 @@ abstract public class AbstractRemoteRosterProcessor {
/** /**
* Handles the passed packet. Might throw {@link PacketRejectedException} if * Handles the passed packet. Might throw {@link PacketRejectedException} if
* the package should not be processed by openfire * the package should not be processed by openfire.
* * See actual classes for info about their implementation.
* @param packet * @param packet Packet itself
* @param subdomain String with subdomain contained in either from or to, or string with several watched subdomains that needs to be splitted (see Maininterceptor)
* @param to String with recipient of packet, may be ""
* @param from String with sender of packet, may be ""
* @throws PacketRejectedException * @throws PacketRejectedException
*/ */
abstract public void process(Packet packet,String subdomain) throws PacketRejectedException; abstract public void process(Packet packet,String subdomain, String to, String from) throws PacketRejectedException;
/** /**
* Use this method if you want to send your own packets through openfire * Use this method if you want to send your own packets through openfire
* * @param packet packet to send
* @param packet
* packet to send
*/ */
protected void dispatchPacket(Packet packet) { protected void dispatchPacket(Packet packet) {
Log.debug("Sending package to PacketRouter: \n" + packet.toString() + "\n"); Log.debug("Sending package to PacketRouter: \n" + packet.toString() + "\n");
......
...@@ -3,7 +3,6 @@ package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors; ...@@ -3,7 +3,6 @@ package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.Node; import org.dom4j.Node;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
...@@ -17,9 +16,9 @@ import org.xmpp.packet.Packet; ...@@ -17,9 +16,9 @@ import org.xmpp.packet.Packet;
* >Here</a> * >Here</a>
* *
* @author Holger Bergunde * @author Holger Bergunde
* // Our Query is now a <item jid="Example@subdomain" name="contact"><group></item>iq id="FSwIU-68" type="set" from="axel.brand@lxhamrztst02.ger.win.int.kn/Spark 2.7.0 #272"> <iq id="FSwIU-68" type="set" from="user@example/resource">
// <query xmlns="jabber:iq:roster"> // <query xmlns="jabber:iq:roster">
// <item jid="129443529@icq.lxhamrztst02.ger.win.int.kn" name="wulschti" subscription="both"> // <item jid="123456789@subdomain" name="wulschti" subscription="both">
// <group>General</group> // <group>General</group>
// </item> // </item>
// </query> // </query>
...@@ -38,15 +37,17 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces ...@@ -38,15 +37,17 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces
} }
return ""; return "";
} }
@Override @Override
public void process(Packet packet, String subdomain) throws PacketRejectedException { public void process(Packet packet, String subdomain, String to, String from) throws PacketRejectedException {
Log.debug("Processing packet in ClientToComponentUpdateProcessor"); Log.debug("Processing packet in ClientToComponentUpdateProcessor");
Element query = ((IQ) packet).getChildElement(); Element query = ((IQ) packet).getChildElement();
if (query != null && query.getNamespaceURI().equals("jabber:iq:roster")) { if (query != null && query.getNamespaceURI().equals("jabber:iq:roster")) {
if (findNodesInDocument(query.getDocument(), "//roster:item").size() > 0) { if (findNodesInDocument(query.getDocument(), "//roster:item").size() > 0) {
// We now know we have to check the JID of the to be added User against our valid subdomains. // We now know we have to check the JID of the to be added User against our valid subdomains.
String[] valid_subdomains = subdomain.split("#"); String[] valid_subdomains = subdomain.split("[#]");
for (Node n : findNodesInDocument(query.getDocument(), "//roster:item")) { for (Node n : findNodesInDocument(query.getDocument(), "//roster:item")) {
String jid = n.valueOf("@jid"); String jid = n.valueOf("@jid");
// TODO: We ignore remove iq packets for now. There might be // TODO: We ignore remove iq packets for now. There might be
...@@ -54,6 +55,7 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces ...@@ -54,6 +55,7 @@ public class ClientToComponentUpdateProcessor extends AbstractRemoteRosterProces
// when we remove our legacy network registration. // when we remove our legacy network registration.
String found_subdomain = searchJIDforSubdomain(valid_subdomains, jid); String found_subdomain = searchJIDforSubdomain(valid_subdomains, jid);
if (!found_subdomain.isEmpty() && !n.valueOf("@subscription").equals("remove")) { if (!found_subdomain.isEmpty() && !n.valueOf("@subscription").equals("remove")) {
Log.debug("Mirroring packet from local network to legacy component " + found_subdomain); Log.debug("Mirroring packet from local network to legacy component " + found_subdomain);
IQ forward = (IQ) packet.createCopy(); IQ forward = (IQ) packet.createCopy();
forward.setTo(found_subdomain); forward.setTo(found_subdomain);
......
...@@ -10,7 +10,6 @@ import org.dom4j.tree.DefaultElement; ...@@ -10,7 +10,6 @@ import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.interceptor.InterceptorManager; import org.jivesoftware.openfire.interceptor.InterceptorManager;
import org.jivesoftware.openfire.interceptor.PacketInterceptor; import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.session.Session; import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
...@@ -34,7 +33,7 @@ public class DiscoIQRegisteredProcessor extends AbstractRemoteRosterProcessor { ...@@ -34,7 +33,7 @@ public class DiscoIQRegisteredProcessor extends AbstractRemoteRosterProcessor {
} }
@Override @Override
public void process(Packet packet, final String subdomain) throws PacketRejectedException { public void process(Packet packet, final String subdomain, String to, String from) throws PacketRejectedException {
Log.debug("Processing packet in DiscoIQRegisteredProcessor for " + subdomain); Log.debug("Processing packet in DiscoIQRegisteredProcessor for " + subdomain);
// Check if the jabber:iq:register is enabled in admin panel // Check if the jabber:iq:register is enabled in admin panel
boolean isFeatureEnabled = JiveGlobals.getBooleanProperty("plugin.remoteroster.sparkDiscoInfo", false); boolean isFeatureEnabled = JiveGlobals.getBooleanProperty("plugin.remoteroster.sparkDiscoInfo", false);
...@@ -43,8 +42,6 @@ public class DiscoIQRegisteredProcessor extends AbstractRemoteRosterProcessor { ...@@ -43,8 +42,6 @@ public class DiscoIQRegisteredProcessor extends AbstractRemoteRosterProcessor {
return; return;
} }
String from = packet.getFrom().toString();
String to = packet.getTo().toString();
final InterceptorManager interceptorManager = InterceptorManager.getInstance(); final InterceptorManager interceptorManager = InterceptorManager.getInstance();
final PacketInterceptor interceptor = new PacketInterceptor() { final PacketInterceptor interceptor = new PacketInterceptor() {
......
package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.PacketRouter;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* Some clients try to check how long a contact is already offline. This feature
* is not supported by spectrum so it won't response to this IQ stanza. To
* prevent the client from waiting for a response we could answer with a
* service-unavailable message as described in XEP-12.
*
* @author Holger Bergunde
* @author axel.frederik.brand
*
*/
public class IQLastProcessor extends AbstractRemoteRosterProcessor{
public IQLastProcessor() {
Log.debug("Created IQLastProcessor");
}
/**
* At this point we know:
* IQLastFilter is ACTIVATED
* Packet is incoming and NOT processed
* Packet is instance of IQ
* To contains the watched subdomain represented in String subdomain
*/
@Override
public void process(Packet packet, String subdomain, String to, String from)
throws PacketRejectedException {
IQ iqpacket = (IQ) packet;
Element root = iqpacket.getChildElement();
if (root == null)
return;
String ns = root.getNamespaceURI();
if (ns.equals("jabber:iq:last") && iqpacket.getType().equals(IQ.Type.get)) {
Log.debug("Processing IQLast Packet for " + subdomain);
IQ answer = IQ.createResultIQ(iqpacket);
answer.setType(IQ.Type.error);
DefaultElement errorElement = new DefaultElement("error");
errorElement.addAttribute("type", "cancel");
errorElement.addAttribute("code", "503");
DefaultElement serviceElement = new DefaultElement("service-unavailable");
serviceElement.addNamespace("", "urn:ietf:params:xml:ns:xmpp-stanzas");
errorElement.add(serviceElement);
answer.setChildElement(errorElement);
Log.debug("Auto response to jabber:iq:last for " + subdomain);
PacketRouter router = _server.getPacketRouter();
router.route(answer);
//There is no need for the Server to process this Package if S2 doesn't support it.
throw new PacketRejectedException();
}
}
}
package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors; package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.tree.DefaultAttribute; import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement; import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.roster.Roster; import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem; import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager; import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException; import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
/** /**
...@@ -32,34 +36,49 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor { ...@@ -32,34 +36,49 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager; private RosterManager _rosterManager;
public IQRosterPayloadProcessor(RosterManager rosterMananger) { public IQRosterPayloadProcessor(RosterManager rosterMananger) {
Log.debug("Created SendRosterProcessor"); Log.debug("Created IQRosterPayloadProcessor");
_rosterManager = rosterMananger; _rosterManager = rosterMananger;
} }
@Override @Override
public void process(Packet packet, String subdomain) throws PacketRejectedException { public void process(Packet packet, String subdomain, String to, String from) throws PacketRejectedException {
Log.debug("Processing packet in SendRosterProcessor for " + subdomain); Log.debug("Processing packet in SendRosterProcessor for " + subdomain);
IQ myPacket = (IQ) packet; IQ myPacket = (IQ) packet;
Element query = myPacket.getChildElement();
String username = getUsernameFromJid(to);
if (query != null && query.getNamespaceURI().equals("jabber:iq:roster")) {
if (myPacket.getType().equals(IQ.Type.get)) {
handleIQget(myPacket,subdomain,username);
}
else if (myPacket.getType().equals(IQ.Type.set)) {
handleIQset(myPacket,subdomain,username);
}
}
}
String user = myPacket.getTo().toString();
String username = getUsernameFromJid(user);
Roster roster; private void handleIQget(IQ myPacket, String subdomain, String username){
if(JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false)){ if(JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", false)){
Roster roster;
try { try {
roster = _rosterManager.getRoster(username); roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems(); Collection<RosterItem> items = roster.getRosterItems();
Log.debug("Sending contacts with subdomain " + subdomain + " from user " +username + " to external Component");
sendRosterToComponent(myPacket, items, subdomain); sendRosterToComponent(myPacket, items, subdomain);
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else { } else {
Log.debug("Sending nonpersistant-RemoteRosterResponse to external Component for User: " + username);
sendEmptyRoster(myPacket, subdomain); sendEmptyRoster(myPacket, subdomain);
} }
} }
private void sendRosterToComponent(IQ requestPacket, Collection<RosterItem> items, String subdomain) { private void sendRosterToComponent(IQ requestPacket, Collection<RosterItem> items, String subdomain) {
Log.debug("Sending contacts from user " + requestPacket.getFrom().toString() + " to external Component");
IQ response = IQ.createResultIQ(requestPacket); IQ response = IQ.createResultIQ(requestPacket);
response.setTo(subdomain); response.setTo(subdomain);
Element query = new DefaultElement("query"); Element query = new DefaultElement("query");
...@@ -80,13 +99,12 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor { ...@@ -80,13 +99,12 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor {
} }
} }
query.addNamespace("", "jabber:iq:roster"); query.addNamespace("", "jabber:iq:roster");
response.setChildElement(query); response.setChildElement(query);
dispatchPacket(response); dispatchPacket(response);
} }
private void sendEmptyRoster(Packet requestPacket, String subdomain){ private void sendEmptyRoster(Packet requestPacket, String subdomain){
Log.debug("Sending nonpersistant-RemoteRosterResponse to external Component");
IQ iq = (IQ) requestPacket; IQ iq = (IQ) requestPacket;
IQ response = IQ.createResultIQ(iq); IQ response = IQ.createResultIQ(iq);
response.setTo(subdomain); response.setTo(subdomain);
...@@ -95,5 +113,63 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor { ...@@ -95,5 +113,63 @@ public class IQRosterPayloadProcessor extends AbstractRemoteRosterProcessor {
response.setChildElement(query); response.setChildElement(query);
dispatchPacket(response); dispatchPacket(response);
} }
private void handleIQset(IQ myPacket, String subdomain, String username) {
IQ response = IQ.createResultIQ(myPacket);
List<Node> nodes = findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item");
for (Node n : nodes) {
Roster roster;
String jid = n.valueOf("@jid");
String name = n.valueOf("@name");
String subvalue = n.valueOf("@subscription");
//We dont want to add or delete the subdomain itself
if (jid.equals(subdomain))
continue;
if(subvalue.equals("both")){
try {
roster = _rosterManager.getRoster(username);
List<String> grouplist = new ArrayList<String>();
List<Node> groupnodes = findNodesInDocument(n.getDocument(), "//roster:group");
for (Node ne : groupnodes) {
String groupName = ne.getText();
grouplist.add(groupName);
}
boolean rosterPersistent = JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", true);
Log.debug("Adding/Updating Contact " + jid + " to roster of" + username);
try {
RosterItem item = roster.getRosterItem(new JID(jid));
item.setGroups(grouplist);
roster.updateRosterItem(item);
//dont send iq-result if just updating user
continue;
} catch (UserNotFoundException exc) {
//Then we should add him!
}
RosterItem item = roster.createRosterItem(new JID(jid), name, grouplist, false, rosterPersistent);
item.setSubStatus(RosterItem.SUB_BOTH);
roster.updateRosterItem(item);
} catch (Exception e) {
Log.debug("Could not add user to Roster although no entry should exist..." + username, e);
e.printStackTrace();
}
} else if (subvalue.equals("remove")){
try {
roster = _rosterManager.getRoster(username);
roster.deleteRosterItem(new JID(jid), false);
Log.debug("Removed contact " + jid + " from contact list of " + username);
} catch (UserNotFoundException e) {
Log.debug("Could not find user while cleaning up the roster in GoJara for user " + username, e);
response.setType(IQ.Type.error);
} catch (SharedGroupException e) {
// We should ignore this. External contacts cannot be in
// shared groups
}
}
dispatchPacket(response);
}
}
} }
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors; package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import java.util.Collection; import java.util.Collection;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.roster.Roster; import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem; import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager; import org.jivesoftware.openfire.roster.RosterManager;
...@@ -12,34 +10,29 @@ import org.xmpp.packet.Packet; ...@@ -12,34 +10,29 @@ import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence; import org.xmpp.packet.Presence;
/** /**
* This class is a part of the command pattern used in * When this Processor gets called, it deletes all Contacts of a given User that contain a specific subdomain.
* {@link RemoteRosterInterceptor}. If the remote contacts should not be * We use this to clean up all Contacts of a Users Gateway registration as soon as he logs out. In this case
* saved permanently in the users Roster, this command will delete * the Transport sends a Unavailable Presence without subtext "Connecting" to the user.
* contacts to the corresponding Transport upon receiving unavailable presence
* from transport. This way the Users Roster will not get modified by the automated
* unsubscribe presences triggered by deleting RosterItem in OF-Roster
*
* @author Holger Bergunde * @author Holger Bergunde
* @author axel.frederik.brand
* *
*/ */
public class NonPersistantRosterProcessor extends AbstractRemoteRosterProcessor { public class NonPersistantRosterProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager; private RosterManager _rosterManager;
// private String _subDomain;
public NonPersistantRosterProcessor(RosterManager rostermananger) { public NonPersistantRosterProcessor(RosterManager rostermananger) {
Log.debug("Created NonPersistantProcessor"); Log.debug("Created NonPersistantProcessor");
_rosterManager = rostermananger; _rosterManager = rostermananger;
// _subDomain = subdomain;
} }
@Override @Override
public void process(Packet packet, String subdomain) throws PacketRejectedException { public void process(Packet packet, String subdomain, String to, String from) throws PacketRejectedException {
Log.debug("Processing packet in NonPersistantRosterProcessor for " + subdomain);
Presence myPacket = (Presence) packet; Presence myPacket = (Presence) packet;
String to = myPacket.getTo().toString(); if (myPacket.getType() != null && myPacket.getType().equals(Presence.Type.unavailable) && !myPacket.getElement().getStringValue().equals("Connecting")) {
String username = getUsernameFromJid(to); String username = getUsernameFromJid(to);
if (myPacket.getType() != null && myPacket.getType().equals(Presence.Type.unavailable)) { Log.debug("Processing packet in NonPersistantRosterProcessor for " + subdomain + "and user " + username);
try { try {
Roster roster = _rosterManager.getRoster(username); Roster roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems(); Collection<RosterItem> items = roster.getRosterItems();
...@@ -50,12 +43,12 @@ public class NonPersistantRosterProcessor extends AbstractRemoteRosterProcessor ...@@ -50,12 +43,12 @@ public class NonPersistantRosterProcessor extends AbstractRemoteRosterProcessor
roster.deleteRosterItem(item.getJid(), false); roster.deleteRosterItem(item.getJid(), false);
} }
} }
} catch (Exception e) { } catch (Exception e) {
Log.debug("Execption occured when cleaning up the Roster.", e); Log.debug("Execption occured when cleaning up the Roster.", e);
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
} }
package org.jivesoftware.openfire.plugin.gojara.messagefilter.interceptors; package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.database.DatabaseManager; import org.jivesoftware.openfire.plugin.gojara.database.DatabaseManager;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
/** /**
...@@ -14,36 +11,32 @@ import org.xmpp.packet.Packet; ...@@ -14,36 +11,32 @@ import org.xmpp.packet.Packet;
* (configurable) minutes. * (configurable) minutes.
* *
* @author Holger Bergunde * @author Holger Bergunde
* * @author axel.frederik.brand
*/ */
public class StatisticPackageInterceptor implements PacketInterceptor { public class StatisticsProcessor extends AbstractRemoteRosterProcessor{
private String _subdomain;
private DatabaseManager _db; private DatabaseManager _db;
public StatisticPackageInterceptor(String subdomain) { public StatisticsProcessor() {
_subdomain = subdomain; Log.debug("Created StatisticsProcessor");
_db = DatabaseManager.getInstance(); _db = DatabaseManager.getInstance();
} }
/**
* At this Point we Already know:
* neither of both JIDS is malformed (Package wouldn't have been intercepted)
* Package is incoming & processed
* Either From or To contains the watched,passed subdomain
* From does not Equal To (This way we exclude PING sent by spectrum To spectrum
* From AND To are NOT empty (null), this way we exclude packets sent to server itself...change Maininterceptor if we want to change this
*
*/
@Override @Override
public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) public void process(Packet packet, String subdomain, String to, String from)
throws PacketRejectedException { throws PacketRejectedException {
JID from = packet.getFrom();
JID to = packet.getTo(); String type = packet.getClass().getName();
_db.addNewLogEntry(subdomain, type, from, to);
if (from != null && to != null && processed && incoming) {
if (from.toString().contains(_subdomain) || to.toString().contains(_subdomain)) {
/*
* Spectrum sends a Ping to itself through the server to check
* if the server is alive. We ignore that for statistics
*/
if (to.toString().equals(from.toString()) && to.toString().equals(_subdomain))
return;
String type = packet.getClass().getName();
_db.addNewLogEntry(_subdomain, type, from.toString(), to.toString());
}
}
} }
} }
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors; package org.jivesoftware.openfire.plugin.gojara.messagefilter.processors;
import java.util.List; import java.util.List;
import org.dom4j.Element; import org.dom4j.Element;
import org.dom4j.Node; import org.dom4j.Node;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException; import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.plugin.gojara.permissions.PermissionManager; import org.jivesoftware.openfire.plugin.gojara.permissions.PermissionManager;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper; import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.jivesoftware.openfire.session.Session;
import org.xmpp.packet.IQ; import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
...@@ -23,29 +18,45 @@ import org.xmpp.packet.Packet; ...@@ -23,29 +18,45 @@ import org.xmpp.packet.Packet;
* and remove the item containing the gateways subdomain * and remove the item containing the gateways subdomain
* *
* @author Holger Bergunde * @author Holger Bergunde
* * @author axel.frederik.brand
*/ */
public class DiscoPackageProcessor extends AbstractRemoteRosterProcessor{ public class WhitelistProcessor extends AbstractRemoteRosterProcessor{
private PermissionManager _permissions; private PermissionManager _permissions;
public DiscoPackageProcessor() { public WhitelistProcessor() {
_permissions = new PermissionManager(); _permissions = new PermissionManager();
Log.debug("Created WhitelistProcessor");
} }
/**
* At this point we already know:
* Package is NOT incoming
* Package is processed
* From is either Empty (it was null) or equals the serverDomain.
* Package is a IQ
*
* @param subdomain A String containing several watched subdomains separated by [#]
*/
@Override @Override
public void process (Packet packet, String subdomain) throws PacketRejectedException { public void process (Packet packet, String subdomain, String to, String from) throws PacketRejectedException {
if (_permissions.isGatewayLimited(subdomain)) { IQ myPacket = (IQ) packet;
IQ iqpacket = (IQ) packet; Element root = myPacket.getChildElement();
Element root = iqpacket.getChildElement();
if (root == null) if (root == null)
return; return;
String ns = root.getNamespaceURI();
if (ns.equals("http://jabber.org/protocol/disco#items") && iqpacket.getType().equals(IQ.Type.result)) { String ns = root.getNamespaceURI();
if (!_permissions.allowedForUser(subdomain, iqpacket.getTo())) { if (ns.equals("http://jabber.org/protocol/disco#items") && myPacket.getType().equals(IQ.Type.result)) {
Log.debug("Processing packet in Whitelistprocessor for " + to);
//As some users can be allowed to use only specific Gateways, we have to do this for every subdomain separately
String[] valid_subdomains = subdomain.split("[#]");
for (String single_subdomain : valid_subdomains) {
if (_permissions.isGatewayLimited(single_subdomain) && !_permissions.allowedForUser(single_subdomain, myPacket.getTo())) {
List<Node> nodes = XpathHelper.findNodesInDocument(root.getDocument(), "//discoitems:item"); List<Node> nodes = XpathHelper.findNodesInDocument(root.getDocument(), "//discoitems:item");
for (Node node : nodes) { for (Node node : nodes) {
if (node.valueOf("@jid").equals(subdomain)) { if (node.valueOf("@jid").equals(single_subdomain)) {
root.remove(node); root.remove(node);
} }
} }
...@@ -53,5 +64,6 @@ public class DiscoPackageProcessor extends AbstractRemoteRosterProcessor{ ...@@ -53,5 +64,6 @@ public class DiscoPackageProcessor extends AbstractRemoteRosterProcessor{
} }
} }
} }
} }
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster;
import java.util.HashMap;
import java.util.Map;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.interceptor.PacketInterceptor;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.database.DatabaseManager;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.ClientToComponentUpdateProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.DiscoIQRegisteredProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.IQRosterPayloadProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors.*;
import org.jivesoftware.openfire.plugin.gojara.utils.XpathHelper;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.session.Session;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
import org.xmpp.packet.Presence;
/**
* This intercepter handles the main functionality described in the XEP-xxx
* Remote Roster Management standard. <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html">XEP-xxx</a>
*
* It must be registered as an PacketInterceptor for each gateway. It will check
* the incoming packages for several preconditions and redirects the packages
* using a command pattern to individual packet handles.
*
* @author Holger Bergunde
*
*/
public class RemoteRosterInterceptor {
private static final Logger Log = LoggerFactory
.getLogger(RemoteRosterInterceptor.class);
// private String _mySubdomain;
private Map<String, AbstractRemoteRosterProcessor> _packetProcessor = new HashMap<String, AbstractRemoteRosterProcessor>();
private DatabaseManager _db;
private String _host;
public RemoteRosterInterceptor(String initialSubdomain) {
_db = DatabaseManager.getInstance();
Log.debug("Starting Package Interceptor for " + initialSubdomain);
XMPPServer server = XMPPServer.getInstance();
RosterManager rosterMananger = server.getRosterManager();
AbstractRemoteRosterProcessor sendroster = new IQRosterPayloadProcessor(
rosterMananger);
AbstractRemoteRosterProcessor receiveChanges = new ReceiveComponentUpdatesProcessor(rosterMananger);
AbstractRemoteRosterProcessor iqRegistered = new DiscoIQRegisteredProcessor();
AbstractRemoteRosterProcessor nonPersistant = new NonPersistantRosterProcessor(
rosterMananger);
AbstractRemoteRosterProcessor updateToComponent = new ClientToComponentUpdateProcessor();
_packetProcessor.put("sendRoster", sendroster);
_packetProcessor.put("receiveChanges", receiveChanges);
_packetProcessor.put("sparkIQRegistered", iqRegistered);
_packetProcessor.put("handleNonPersistant", nonPersistant);
_packetProcessor.put("clientToComponentUpdate", updateToComponent);
}
public RemoteRosterInterceptor() {
_db = DatabaseManager.getInstance();
Log.debug("Starting RemoteRosterInterceptor - BINGO");
XMPPServer server = XMPPServer.getInstance();
RosterManager rosterMananger = server.getRosterManager();
AbstractRemoteRosterProcessor sendroster = new IQRosterPayloadProcessor(
rosterMananger);
AbstractRemoteRosterProcessor receiveChanges = new ReceiveComponentUpdatesProcessor(rosterMananger);
AbstractRemoteRosterProcessor iqRegistered = new DiscoIQRegisteredProcessor();
AbstractRemoteRosterProcessor nonPersistant = new NonPersistantRosterProcessor(
rosterMananger);
AbstractRemoteRosterProcessor updateToComponent = new ClientToComponentUpdateProcessor();
AbstractRemoteRosterProcessor discoPackage = new DiscoPackageProcessor();
_packetProcessor.put("sendRoster", sendroster);
_packetProcessor.put("receiveChanges", receiveChanges);
_packetProcessor.put("sparkIQRegistered", iqRegistered);
_packetProcessor.put("handleNonPersistant", nonPersistant);
_packetProcessor.put("clientToComponentUpdate", updateToComponent);
_packetProcessor.put("DiscoPackage",discoPackage);
_host = server.getServerInfo().getHostname();
}
public void interceptPacket(Packet packet, Session session,
boolean incoming, boolean processed, String subdomain)
throws PacketRejectedException {
if (!processed && incoming) {
if (packet instanceof IQ) {
Log.debug("Incoming unprocessed package i might be interested in. I am: "
+ this.hashCode()
+ " my subd: "
+ subdomain
+ " Package: \n" + packet.toString() + "\n");
IQ myPacket = (IQ) packet;
if (myPacket.getTo() == null) {
/*
* If getTo() == null this is maybe a roster update from the
* Client to the Server, check if we should mirror this
* package to external component
*/
if (myPacket.getFrom() != null
&& myPacket.getType().equals(IQ.Type.set)) {
if (XpathHelper.findNodesInDocument(
myPacket.getChildElement().getDocument(),
"//roster:item").size() > 0) {
_packetProcessor.get("clientToComponentUpdate")
.process(myPacket, subdomain);
}
}
return;
}
// String ns = root.getNamespaceURI();
// if (ns.equals("http://jabber.org/protocol/disco#items") && iqpacket.getType().equals(IQ.Type.result)){
//
// }
@SuppressWarnings("unused")
String from = myPacket.getFrom().toString();
String to = myPacket.getTo().toString();
if (from.equals(_host)){
_packetProcessor.get("DiscoPackage").process(packet,subdomain);
} else if (from.equals(subdomain)) {
if (myPacket.getType().equals(IQ.Type.get)
&& XpathHelper.findNodesInDocument(
myPacket.getElement().getDocument(),
"//roster:*").size() == 1) {
// This Package is a roster request by remote component
_packetProcessor.get("sendRoster").process(packet,
subdomain);
} else if (myPacket.getType().equals(IQ.Type.set)
&& XpathHelper.findNodesInDocument(
myPacket.getElement().getDocument(),
"//roster:item").size() >= 1) {
// Component sends roster update
_packetProcessor.get("receiveChanges").process(packet,
subdomain);
}
} else if (to.equals(subdomain)
&& myPacket.getType().equals(IQ.Type.get)
&& myPacket.toString().contains(
"http://jabber.org/protocol/disco#info")) {
/*
* modify the disco#info for spark clients if enabled in
* admin panel
*/
_packetProcessor.get("sparkIQRegistered").process(packet,
subdomain);
}
} else if (!JiveGlobals.getBooleanProperty(
"plugin.remoteroster.persistent", false)) {
if (packet instanceof Presence
&& packet.getFrom().toString().equals(subdomain)
&& !packet.getElement().getStringValue()
.equals("Connecting")) {
System.out
.println("Test for NonPersistant-Roster Cleanup!");
_packetProcessor.get("handleNonPersistant").process(packet,
subdomain);
}
}
}
}
}
// currently we dont need this, and it didnt seem to occur often anyway. Will
// test it later.
// could potentially save some traffic
// else if (packet instanceof Presence){
// String to = packet.getTo().toString();
// if (!to.equals(_mySubdomain) && to.contains(_mySubdomain)){
//
// Presence myPacket = ((Presence) packet);
// if (myPacket.getType().equals(Presence.Type.unavailable) ||
// myPacket.getType().equals(Presence.Type.probe) ||
// myPacket.getType().equals(null)){
// System.out.println("this presence would be wasted");
// throw new PacketRejectedException();
// }
// }
\ No newline at end of file
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors;
import java.util.Collection;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.Packet;
/**
*
* This class cleans up a roster from contacts if the user removes/deletes the
* gateway registration. After deleting a registration there should not be any
* gateway related contacts left
*
* @author holger.bergunde
*
*/
public class CleanUpRosterProcessor extends AbstractRemoteRosterProcessor {
private String _myDomain;
private RosterManager _rosterManager;
public CleanUpRosterProcessor(RosterManager rosterMananger, String mySubdomain) {
Log.debug("Created CleanUpRosterProcessor for " + mySubdomain);
_myDomain = mySubdomain;
_rosterManager = rosterMananger;
}
@Override
public void process(Packet packet, String subdomain) throws PacketRejectedException {
if (packet instanceof IQ) {
IQ iqPacket = (IQ) packet;
if (findNodesInDocument(iqPacket.getElement().getDocument(), "//register:remove").size() > 0) {
String username = getUsernameFromJid(packet.getFrom().toString());
Roster roster;
try {
roster = _rosterManager.getRoster(username);
Collection<RosterItem> items = roster.getRosterItems();
for (RosterItem item : items) {
String itemName = item.getJid().toString();
if (itemName.contains(_myDomain) && !itemName.equals(_myDomain)) {
Log.debug("Removing contact " + username + " from contact list.");
roster.deleteRosterItem(item.getJid(), false);
}
}
} catch (UserNotFoundException e) {
Log.debug("Could not found user while cleaning up the roster in GoJara for user " + username, e);
} catch (SharedGroupException e) {
// We should ignore this. External contacts cannot be in
// shared groups
}
}
}
}
}
\ No newline at end of file
package org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.processors;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.tree.DefaultElement;
import org.jivesoftware.openfire.SharedGroupException;
import org.jivesoftware.openfire.interceptor.PacketRejectedException;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.processors.AbstractRemoteRosterProcessor;
import org.jivesoftware.openfire.plugin.gojara.messagefilter.remoteroster.RemoteRosterInterceptor;
import org.jivesoftware.openfire.roster.Roster;
import org.jivesoftware.openfire.roster.RosterItem;
import org.jivesoftware.openfire.roster.RosterManager;
import org.jivesoftware.openfire.user.UserNotFoundException;
import org.jivesoftware.util.JiveGlobals;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
/**
*
* This class implements the XEP-xxx Remote Roster Management standard
* "2.5 Component sends roster update". Part of command pattern used in
* {@link RemoteRosterInterceptor}
*
* Further information: <a
* href="http://jkaluza.fedorapeople.org/remote-roster.html#sect-id215516"
* >Here</a>
*
* @author Holger Bergunde
*
*/
public class ReceiveComponentUpdatesProcessor extends AbstractRemoteRosterProcessor {
private RosterManager _rosterManager;
// private String _mySubdomain;
public ReceiveComponentUpdatesProcessor(RosterManager rosterManager) {
// _mySubdomain = subdomain;
Log.debug("Created ReceiveComponentUpdatesProcessor");
_rosterManager = rosterManager;
}
@Override
public void process(Packet packet, String subdomain) throws PacketRejectedException {
Log.debug("Processing packet in ClientToComponentUpdateProcessor for " + subdomain);
IQ myPacket = (IQ) packet;
IQ response = IQ.createResultIQ(myPacket);
String to = myPacket.getTo().toString();
String username = getUsernameFromJid(to);
List<Node> nodes = findNodesInDocument(myPacket.getElement().getDocument(), "//roster:item");
for (Node n : nodes) {
Roster roster;
String jid = n.valueOf("@jid");
String name = n.valueOf("@name");
String subvalue = n.valueOf("@subscription");
if(subvalue.equals("both")){
try {
if (jid.equals(myPacket.getFrom().toString())) {
// Do not add the component itself to the contact list
break;
}
roster = _rosterManager.getRoster(username);
List<String> grouplist = new ArrayList<String>();
List<Node> groupnodes = findNodesInDocument(n.getDocument(), "//roster:group");
for (Node ne : groupnodes) {
String groupName = ne.getText();
grouplist.add(groupName);
}
boolean rosterPersisten = JiveGlobals.getBooleanProperty("plugin.remoteroster.persistent", true);
Log.debug("Adding/Updating User " + jid + " to roster " + to);
try {
RosterItem item = roster.getRosterItem(new JID(jid));
item.setGroups(grouplist);
roster.updateRosterItem(item);
//dont send iq-result if just updating user
break;
} catch (UserNotFoundException exc) {
//Then we should add him!
}
RosterItem item = roster.createRosterItem(new JID(jid), name, grouplist, false, rosterPersisten);
item.setSubStatus(RosterItem.SUB_BOTH);
roster.updateRosterItem(item);
} catch (Exception e) {
Log.debug("Could not add user to Roster although no entry should exist..." + username, e);
e.printStackTrace();
}
} else if (subvalue.equals("remove")){
try {
if (jid.equals(myPacket.getFrom().toString())) {
// Do not Try to Remove component itself as its not added.
break;
}
roster = _rosterManager.getRoster(username);
roster.deleteRosterItem(new JID(jid), false);
Log.debug("Removed contact " + jid + " from contact list of " + username);
} catch (UserNotFoundException e) {
Log.debug("Could not find user while cleaning up the roster in GoJara for user " + username, e);
response.setType(IQ.Type.error);
} catch (SharedGroupException e) {
// We should ignore this. External contacts cannot be in
// shared groups
}
}
dispatchPacket(response);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment