IoT: Prevent control/read-out from non friends

and make the behavior configurable.
This commit is contained in:
Florian Schmaus 2016-11-17 10:25:35 +01:00
parent 6d74d0383c
commit da58b20b53
4 changed files with 69 additions and 33 deletions

View File

@ -16,27 +16,62 @@
*/ */
package org.jivesoftware.smackx.iot; package org.jivesoftware.smackx.iot;
import java.util.Map; import java.util.logging.Logger;
import java.util.WeakHashMap;
import org.jivesoftware.smack.Manager; import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.IQ.Type;
import org.jivesoftware.smackx.iot.provisioning.IoTProvisioningManager;
import org.jxmpp.jid.Jid;
public final class IoTManager extends Manager { public abstract class IoTManager extends Manager {
private static final Map<XMPPConnection, IoTManager> INSTANCES = new WeakHashMap<>(); private static final Logger LOGGER = Logger.getLogger(IoTManager.class.getName());
public static synchronized IoTManager getInstanceFor(XMPPConnection connection) { private final IoTProvisioningManager ioTProvisioningManager;
IoTManager manager = INSTANCES.get(connection);
if (manager == null) {
manager = new IoTManager(connection);
INSTANCES.put(connection, manager);
}
return manager;
}
private IoTManager(XMPPConnection connection) { private boolean allowNonFriends;
protected IoTManager(XMPPConnection connection) {
super(connection); super(connection);
ioTProvisioningManager = IoTProvisioningManager.getInstanceFor(connection);
} }
/**
* Set whether or not non friends should be able to use the services provided by this manager. Those non-friend
* entities still need to know the full JID for IQ based requests.
*
* @param allowNonFriends true to allow everyone to use the services.
*/
public void setAllowNonFriends(boolean allowNonFriends) {
this.allowNonFriends = allowNonFriends;
}
protected boolean isAllowed(Jid jid) {
if (allowNonFriends) return true;
return ioTProvisioningManager.isMyFriend(jid);
}
protected abstract class IoTIqRequestHandler extends AbstractIqRequestHandler {
protected IoTIqRequestHandler(String element, String namespace, Type type, Mode mode) {
super(element, namespace, type, mode);
}
@Override
public final IQ handleIQRequest(IQ iqRequest) {
if (!isAllowed(iqRequest.getFrom())) {
LOGGER.warning("Ignoring IQ request " + iqRequest);
return null;
}
return handleIoTIqRequest(iqRequest);
}
protected abstract IQ handleIoTIqRequest(IQ iqRequest);
}
} }

View File

@ -22,14 +22,13 @@ import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smackx.iot.IoTManager;
import org.jivesoftware.smackx.iot.Thing; import org.jivesoftware.smackx.iot.Thing;
import org.jivesoftware.smackx.iot.control.element.IoTSetRequest; import org.jivesoftware.smackx.iot.control.element.IoTSetRequest;
import org.jivesoftware.smackx.iot.control.element.IoTSetResponse; import org.jivesoftware.smackx.iot.control.element.IoTSetResponse;
@ -43,7 +42,7 @@ import org.jxmpp.jid.FullJid;
* @author Florian Schmaus {@literal <flo@geekplace.eu>} * @author Florian Schmaus {@literal <flo@geekplace.eu>}
* @see <a href="http://xmpp.org/extensions/xep-0325.html">XEP-0323: Internet of Things - Control</a> * @see <a href="http://xmpp.org/extensions/xep-0325.html">XEP-0323: Internet of Things - Control</a>
*/ */
public final class IoTControlManager extends Manager { public final class IoTControlManager extends IoTManager {
private static final Map<XMPPConnection, IoTControlManager> INSTANCES = new WeakHashMap<>(); private static final Map<XMPPConnection, IoTControlManager> INSTANCES = new WeakHashMap<>();
@ -66,9 +65,10 @@ public final class IoTControlManager extends Manager {
private IoTControlManager(XMPPConnection connection) { private IoTControlManager(XMPPConnection connection) {
super(connection); super(connection);
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTSetRequest.ELEMENT, IoTSetRequest.NAMESPACE, IQ.Type.set, Mode.async) {
connection.registerIQRequestHandler(new IoTIqRequestHandler(IoTSetRequest.ELEMENT, IoTSetRequest.NAMESPACE, IQ.Type.set, Mode.async) {
@Override @Override
public IQ handleIQRequest(IQ iqRequest) { public IQ handleIoTIqRequest(IQ iqRequest) {
// TODO Lookup thing and provide data. // TODO Lookup thing and provide data.
IoTSetRequest iotSetRequest = (IoTSetRequest) iqRequest; IoTSetRequest iotSetRequest = (IoTSetRequest) iqRequest;
@ -101,7 +101,7 @@ public final class IoTControlManager extends Manager {
* *
* @param jid * @param jid
* @param data * @param data
* @return * @return a IoTSetResponse
* @throws NoResponseException * @throws NoResponseException
* @throws XMPPErrorException * @throws XMPPErrorException
* @throws NotConnectedException * @throws NotConnectedException

View File

@ -26,7 +26,6 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
@ -34,10 +33,10 @@ import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry; import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler;
import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode;
import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.iot.IoTManager;
import org.jivesoftware.smackx.iot.Thing; import org.jivesoftware.smackx.iot.Thing;
import org.jivesoftware.smackx.iot.data.element.IoTDataField; import org.jivesoftware.smackx.iot.data.element.IoTDataField;
import org.jivesoftware.smackx.iot.data.element.IoTDataReadOutAccepted; import org.jivesoftware.smackx.iot.data.element.IoTDataReadOutAccepted;
@ -53,7 +52,7 @@ import org.jxmpp.jid.EntityFullJid;
* @author Florian Schmaus {@literal <flo@geekplace.eu>} * @author Florian Schmaus {@literal <flo@geekplace.eu>}
* @see <a href="http://xmpp.org/extensions/xep-0323.html">XEP-0323: Internet of Things - Sensor Data</a> * @see <a href="http://xmpp.org/extensions/xep-0323.html">XEP-0323: Internet of Things - Sensor Data</a>
*/ */
public final class IoTDataManager extends Manager { public final class IoTDataManager extends IoTManager {
private static final Logger LOGGER = Logger.getLogger(IoTDataManager.class.getName()); private static final Logger LOGGER = Logger.getLogger(IoTDataManager.class.getName());
@ -89,13 +88,10 @@ public final class IoTDataManager extends Manager {
private IoTDataManager(XMPPConnection connection) { private IoTDataManager(XMPPConnection connection) {
super(connection); super(connection);
connection.registerIQRequestHandler(new IoTIqRequestHandler(IoTDataRequest.ELEMENT,
connection.registerIQRequestHandler(new AbstractIqRequestHandler(IoTDataRequest.ELEMENT,
IoTDataRequest.NAMESPACE, IQ.Type.get, Mode.async) { IoTDataRequest.NAMESPACE, IQ.Type.get, Mode.async) {
@Override @Override
public IQ handleIQRequest(IQ iqRequest) { public IQ handleIoTIqRequest(IQ iqRequest) {
// TODO Verify that iqRequest.from is friend?
final IoTDataRequest dataRequest = (IoTDataRequest) iqRequest; final IoTDataRequest dataRequest = (IoTDataRequest) iqRequest;
if (!dataRequest.isMomentary()) { if (!dataRequest.isMomentary()) {

View File

@ -350,6 +350,13 @@ public final class IoTProvisioningManager extends Manager {
return isFriend; return isFriend;
} }
public boolean iAmFriendOf(BareJid otherJid) {
RosterEntry entry = roster.getEntry(otherJid);
if (entry == null) return false;
return entry.canSeeHisPresence();
}
public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException { public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException {
Presence presence = new Presence(Presence.Type.subscribe); Presence presence = new Presence(Presence.Type.subscribe);
presence.setTo(bareJid); presence.setTo(bareJid);
@ -360,19 +367,17 @@ public final class IoTProvisioningManager extends Manager {
} }
public void sendFriendshipRequestIfRequired(BareJid jid) throws NotConnectedException, InterruptedException { public void sendFriendshipRequestIfRequired(BareJid jid) throws NotConnectedException, InterruptedException {
RosterEntry entry = roster.getEntry(jid); if (iAmFriendOf(jid)) return;
if (entry != null && entry.canSeeHisPresence()) {
return;
}
sendFriendshipRequest(jid); sendFriendshipRequest(jid);
} }
public boolean isBefriended(Jid friendInQuestion) { public boolean isMyFriend(Jid friendInQuestion) {
return roster.isSubscribedToMyPresence(friendInQuestion); return roster.isSubscribedToMyPresence(friendInQuestion);
} }
public void unfriend(Jid friend) throws NotConnectedException, InterruptedException { public void unfriend(Jid friend) throws NotConnectedException, InterruptedException {
if (isBefriended(friend)) { if (isMyFriend(friend)) {
Presence presence = new Presence(Presence.Type.unsubscribed); Presence presence = new Presence(Presence.Type.unsubscribed);
presence.setTo(friend); presence.setTo(friend);
connection().sendStanza(presence); connection().sendStanza(presence);