use of org.dom4j.io.XMPPPacketReader in project Openfire by igniterealtime.
the class LocalOutgoingServerSession method createOutgoingSession.
/**
* Establishes a new outgoing session to a remote domain. If the remote domain supports TLS and SASL then the new
* outgoing connection will be secured with TLS and authenticated using SASL. However, if TLS or SASL is not
* supported by the remote domain or if an error occurred while securing or authenticating the connection using SASL
* then server dialback will be used.
*
* @param localDomain the local domain to authenticate with the remote domain.
* @param remoteDomain the remote domain.
* @param port default port to use to establish the connection.
* @return new outgoing session to a remote domain, or null.
*/
private static LocalOutgoingServerSession createOutgoingSession(String localDomain, String remoteDomain, int port) {
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Create outgoing session for: " + localDomain + " to " + remoteDomain + "]");
log.debug("Creating new session...");
// Connect to remote server using XMPP 1.0 (TLS + SASL EXTERNAL or TLS + server dialback or server dialback)
log.debug("Creating plain socket connection to a host that belongs to the remote XMPP domain.");
final Socket socket = SocketUtil.createSocketToXmppDomain(remoteDomain, port);
if (socket == null) {
log.info("Unable to create new session: Cannot create a plain socket connection with any applicable remote host.");
return null;
}
SocketConnection connection = null;
try {
connection = new SocketConnection(XMPPServer.getInstance().getPacketDeliverer(), socket, false);
log.debug("Send the stream header and wait for response...");
StringBuilder openingStream = new StringBuilder();
openingStream.append("<stream:stream");
openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\"");
// OF-673
openingStream.append(" from=\"").append(localDomain).append("\"");
openingStream.append(" to=\"").append(remoteDomain).append("\"");
openingStream.append(" version=\"1.0\">");
connection.deliverRawText(openingStream.toString());
// Set a read timeout (of 5 seconds) so we don't keep waiting forever
int soTimeout = socket.getSoTimeout();
socket.setSoTimeout(5000);
XMPPPacketReader reader = new XMPPPacketReader();
reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
// Get the answer from the Receiving Server
XmlPullParser xpp = reader.getXPPParser();
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG; ) {
eventType = xpp.next();
}
String serverVersion = xpp.getAttributeValue("", "version");
String id = xpp.getAttributeValue("", "id");
log.debug("Got a response (stream ID: {}, version: {}). Check if the remote server is XMPP 1.0 compliant...", id, serverVersion);
if (serverVersion != null && decodeVersion(serverVersion)[0] >= 1) {
log.debug("The remote server is XMPP 1.0 compliant (or at least reports to be).");
// Restore default timeout
socket.setSoTimeout(soTimeout);
log.debug("Processing stream features of the remote domain...");
Element features = reader.parseDocument().getRootElement();
if (features != null) {
log.debug("Check if both us as well as the remote server have enabled STARTTLS and/or dialback ...");
final boolean useTLS = JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ENABLED, true);
if (useTLS && features.element("starttls") != null) {
log.debug("Both us and the remote server support the STARTTLS feature. Secure and authenticate the connection with TLS & SASL...");
LocalOutgoingServerSession answer = secureAndAuthenticate(remoteDomain, connection, reader, openingStream, localDomain);
if (answer != null) {
log.debug("Successfully secured/authenticated the connection with TLS/SASL)!");
// Everything went fine so return the secured and
// authenticated connection
log.debug("Successfully created new session!");
return answer;
}
log.debug("Unable to secure and authenticate the connection with TLS & SASL.");
} else if (connection.getTlsPolicy() == Connection.TLSPolicy.required) {
log.debug("I have no StartTLS yet I must TLS");
connection.close();
return null;
} else // Check if we are going to try server dialback (XMPP 1.0)
if (ServerDialback.isEnabled() && features.element("dialback") != null) {
log.debug("Both us and the remote server support the 'dialback' feature. Authenticate the connection with dialback...");
ServerDialback method = new ServerDialback(connection, localDomain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, localDomain, remoteDomain, id)) {
log.debug("Successfully authenticated the connection with dialback!");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(localDomain, connection, newSocketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, remoteDomain, null));
log.debug("Successfully created new session!");
return session;
} else {
log.debug("Unable to authenticate the connection with dialback.");
}
}
} else {
log.debug("Error! No data from the remote server (expected a 'feature' element).");
}
} else {
log.debug("The remote server is not XMPP 1.0 compliant.");
}
log.debug("Something went wrong so close the connection and try server dialback over a plain connection");
if (connection.getTlsPolicy() == Connection.TLSPolicy.required) {
log.debug("I have no StartTLS yet I must TLS");
connection.close();
return null;
}
connection.close();
} catch (SSLHandshakeException e) {
// This is a failure as described in RFC3620, section 5.4.3.2 "STARTTLS Failure".
log.info("STARTTLS negotiation failed. Closing connection (without sending any data such as <failure/> or </stream>).", e);
// It is probably (see OF-794) best if we, as the initiating entity, therefor don't send any data either.
if (connection != null) {
connection.forceClose();
}
} catch (Exception e) {
// This might be RFC3620, section 5.4.2.2 "Failure Case" or even an unrelated problem. Handle 'normally'.
log.warn("An exception occurred while creating an encrypted session. Closing connection.", e);
if (connection != null) {
connection.close();
}
}
if (ServerDialback.isEnabled()) {
log.debug("Unable to create a new session. Going to try connecting using server dialback as a fallback.");
// Use server dialback (pre XMPP 1.0) over a plain connection
final LocalOutgoingServerSession outgoingSession = new ServerDialback().createOutgoingSession(localDomain, remoteDomain, port);
if (outgoingSession != null) {
// TODO this success handler behaves differently from a similar success handler above. Shouldn't those be the same?
log.debug("Successfully created new session (using dialback as a fallback)!");
return outgoingSession;
} else {
log.warn("Unable to create a new session: Dialback (as a fallback) failed.");
return null;
}
} else {
log.warn("Unable to create a new session: exhausted all options (not trying dialback as a fallback, as server dialback is disabled by configuration.");
return null;
}
}
use of org.dom4j.io.XMPPPacketReader in project Openfire by igniterealtime.
the class ServerDialback method createOutgoingSession.
/**
* Creates a new connection from the Originating Server to the Receiving Server for
* authenticating the specified domain.
*
* @param localDomain domain of the Originating Server to authenticate with the Receiving Server.
* @param remoteDomain IP address or hostname of the Receiving Server.
* @param port port of the Receiving Server.
* @return an OutgoingServerSession if the domain was authenticated or <tt>null</tt> if none.
*/
public LocalOutgoingServerSession createOutgoingSession(String localDomain, String remoteDomain, int port) {
final Logger log = LoggerFactory.getLogger(Log.getName() + "[Acting as Originating Server: Create Outgoing Session from: " + localDomain + " to RS at: " + remoteDomain + " (port: " + port + ")]");
log.debug("Creating new outgoing session...");
String hostname = null;
int realPort = port;
try {
// Establish a TCP connection to the Receiving Server
final Socket socket = SocketUtil.createSocketToXmppDomain(remoteDomain, port);
if (socket == null) {
log.info("Unable to create new outgoing session: Cannot create a plain socket connection with any applicable remote host.");
return null;
}
connection = new SocketConnection(XMPPServer.getInstance().getPacketDeliverer(), socket, false);
log.debug("Send the stream header and wait for response...");
StringBuilder stream = new StringBuilder();
stream.append("<stream:stream");
stream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
stream.append(" xmlns=\"jabber:server\"");
stream.append(" to=\"").append(remoteDomain).append("\"");
stream.append(" from=\"").append(localDomain).append("\"");
stream.append(" xmlns:db=\"jabber:server:dialback\"");
stream.append(">");
connection.deliverRawText(stream.toString());
// Set a read timeout (of 5 seconds) so we don't keep waiting forever
int soTimeout = socket.getSoTimeout();
socket.setSoTimeout(RemoteServerManager.getSocketTimeout());
XMPPPacketReader reader = new XMPPPacketReader();
reader.setXPPFactory(FACTORY);
reader.getXPPParser().setInput(new InputStreamReader(ServerTrafficCounter.wrapInputStream(socket.getInputStream()), CHARSET));
// Get the answer from the Receiving Server
XmlPullParser xpp = reader.getXPPParser();
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG; ) {
eventType = xpp.next();
}
log.debug("Got a response. Check if the remote server supports dialback...");
if ("jabber:server:dialback".equals(xpp.getNamespace("db"))) {
log.debug("Dialback seems to be supported by the remote server.");
// Restore default timeout
socket.setSoTimeout(soTimeout);
String id = xpp.getAttributeValue("", "id");
OutgoingServerSocketReader socketReader = new OutgoingServerSocketReader(reader);
if (authenticateDomain(socketReader, localDomain, remoteDomain, id)) {
log.debug("Successfully authenticated the connection with dialback.");
// Domain was validated so create a new OutgoingServerSession
StreamID streamID = BasicStreamIDFactory.createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(localDomain, connection, socketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, remoteDomain, null));
log.debug("Successfully created new outgoing session!");
return session;
} else {
log.debug("Failed to authenticate the connection with dialback.");
// Close the connection
connection.close();
}
} else {
log.debug("Error! Invalid namespace in packet: '{}'. Closing connection.", xpp.getText());
// Send an invalid-namespace stream error condition in the response
connection.deliverRawText(new StreamError(StreamError.Condition.invalid_namespace).toXML());
// Close the connection
connection.close();
}
} catch (Exception e) {
log.error("An exception occurred while creating outgoing session to remote server:", e);
// Close the connection
if (connection != null) {
connection.close();
}
}
log.warn("Unable to create a new outgoing session");
return null;
}
use of org.dom4j.io.XMPPPacketReader in project Openfire by igniterealtime.
the class HttpBindServlet method getPacketReader.
private XMPPPacketReader getPacketReader() {
// Reader is associated with a new XMPPPacketReader
XMPPPacketReader reader = localReader.get();
if (reader == null) {
reader = new XMPPPacketReader();
reader.setXPPFactory(factory);
localReader.set(reader);
}
return reader;
}
use of org.dom4j.io.XMPPPacketReader in project Openfire by igniterealtime.
the class XMPPPPacketReaderFactory method create.
//-- BasePooledObjectFactory implementation
@Override
public XMPPPacketReader create() throws Exception {
XMPPPacketReader parser = new XMPPPacketReader();
parser.setXPPFactory(xppFactory);
return parser;
}
use of org.dom4j.io.XMPPPacketReader in project Openfire by igniterealtime.
the class XmppWebSocket method onTextMethod.
@OnWebSocketMessage
public void onTextMethod(String stanza) {
XMPPPacketReader reader = null;
try {
reader = readerPool.borrowObject();
Document doc = reader.read(new StringReader(stanza));
if (xmppSession == null) {
initiateSession(doc.getRootElement());
} else {
processStanza(doc.getRootElement());
}
} catch (Exception ex) {
Log.error("Failed to process XMPP stanza", ex);
} finally {
if (reader != null) {
readerPool.returnObject(reader);
}
}
}
Aggregations