Search in sources :

Example 6 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class HttpSession method createConnection.

/**
 * Creates a new connection on this session.
 *
 * @param body the body element that was sent containing the request for a new session.
 * @param context the context of the asynchronous servlet call leading up to this method call.
 * @return the created {@link org.jivesoftware.openfire.http.HttpConnection} which represents
 *         the connection.
 */
@Nonnull
synchronized HttpConnection createConnection(@Nonnull final HttpBindBody body, @Nonnull final AsyncContext context) {
    final HttpConnection connection = new HttpConnection(body, context);
    final StreamID streamID = getStreamID();
    final long rid = body.getRid();
    if (Log.isDebugEnabled()) {
        Log.debug("Creating connection for rid: {} in session {}", rid, streamID);
    }
    connection.setSession(this);
    context.setTimeout(getWait().toMillis());
    context.addListener(new AsyncListener() {

        @Override
        public void onComplete(AsyncEvent asyncEvent) {
            if (Log.isTraceEnabled()) {
                Log.trace("Session {} Request ID {}, event complete: {}", streamID, rid, asyncEvent);
            }
            synchronized (connectionQueue) {
                connectionQueue.remove(connection);
                lastActivity = Instant.now();
            }
            SessionEventDispatcher.dispatchEvent(HttpSession.this, SessionEventDispatcher.EventType.connection_closed, connection, context);
        }

        @Override
        public void onTimeout(AsyncEvent asyncEvent) throws IOException {
            if (Log.isTraceEnabled()) {
                Log.trace("Session {} Request ID {}, event timeout: {}. Returning an empty response.", streamID, rid, asyncEvent);
            }
            try {
                // This is why this body is to be delivered in a non-async fashion.
                synchronized (connectionQueue) {
                    deliver(connection, Collections.singletonList(new Deliverable("")), false);
                    setLastResponseEmpty(true);
                }
            } catch (HttpConnectionClosedException e) {
                Log.warn("Unexpected exception while processing connection timeout.", e);
            }
        // Note that 'onComplete' will be invoked.
        }

        @Override
        public void onError(AsyncEvent asyncEvent) {
            if (Log.isTraceEnabled()) {
                Log.trace("Session {} Request ID {}, event error: {}", streamID, rid, asyncEvent);
            }
            Log.warn("For session {} an unhandled AsyncListener error occurred: ", streamID, asyncEvent.getThrowable());
            synchronized (connectionQueue) {
                connectionQueue.remove(connection);
            }
            SessionEventDispatcher.dispatchEvent(HttpSession.this, SessionEventDispatcher.EventType.connection_closed, connection, context);
        }

        @Override
        public void onStartAsync(AsyncEvent asyncEvent) {
            if (Log.isTraceEnabled()) {
                Log.trace("Session {} Request ID {}, event start: {}", streamID, rid, asyncEvent);
            }
        }
    });
    return connection;
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) AsyncListener(javax.servlet.AsyncListener) IOException(java.io.IOException) AsyncEvent(javax.servlet.AsyncEvent) Nonnull(javax.annotation.Nonnull)

Example 7 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class MultiplexerPacketHandler method handle.

/**
 * Process IQ packet sent by a connection manager indicating that a new session has
 * been created, should be closed or that a packet was failed to be delivered.
 *
 * @param packet the IQ packet.
 */
public void handle(Packet packet) {
    if (packet instanceof IQ) {
        IQ iq = (IQ) packet;
        if (iq.getType() == IQ.Type.result) {
        // Do nothing with result packets
        } else if (iq.getType() == IQ.Type.error) {
            // Log the IQ error packet that the connection manager failed to process
            Log.warn("Connection Manager failed to process IQ packet: " + packet.toXML());
        } else if (iq.getType() == IQ.Type.set) {
            Element child = iq.getChildElement();
            String streamIDValue = child.attributeValue("id");
            if (streamIDValue == null) {
                // No stream ID was included so return a bad_request error
                Element extraError = DocumentHelper.createElement(QName.get("id-required", "http://jabber.org/protocol/connectionmanager#errors"));
                sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
            } else if ("session".equals(child.getName())) {
                StreamID streamID = BasicStreamIDFactory.createStreamID(streamIDValue);
                Element create = child.element("create");
                if (create != null) {
                    // Get the InetAddress of the client
                    Element hostElement = create.element("host");
                    String hostName = hostElement != null ? hostElement.attributeValue("name") : null;
                    String hostAddress = hostElement != null ? hostElement.attributeValue("address") : null;
                    // Connection Manager wants to create a Client Session
                    boolean created = multiplexerManager.createClientSession(connectionManagerDomain, streamID, hostName, hostAddress);
                    if (created) {
                        sendResultPacket(iq);
                    } else {
                        // Send error to CM. The CM should close the new-born connection
                        sendErrorPacket(iq, PacketError.Condition.not_allowed, null);
                    }
                } else {
                    ClientSession session = multiplexerManager.getClientSession(connectionManagerDomain, streamID);
                    if (session == null) {
                        // Specified Client Session does not exist
                        sendErrorPacket(iq, PacketError.Condition.item_not_found, null);
                    } else if (child.element("close") != null) {
                        // Connection Manager wants to close a Client Session
                        multiplexerManager.closeClientSession(connectionManagerDomain, streamID);
                        sendResultPacket(iq);
                    } else if (child.element("failed") != null) {
                        // Connection Manager failed to deliver a message
                        // Connection Manager wrapped a packet from a Client Session.
                        List wrappedElements = child.element("failed").elements();
                        if (wrappedElements.size() != 1) {
                            // Wrapper element is wrapping 0 or many items
                            Element extraError = DocumentHelper.createElement(QName.get("invalid-payload", "http://jabber.org/protocol/connectionmanager#errors"));
                            sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
                        } else {
                            Element wrappedElement = (Element) wrappedElements.get(0);
                            String tag = wrappedElement.getName();
                            if ("message".equals(tag)) {
                                XMPPServer.getInstance().getOfflineMessageStrategy().storeOffline(new Message(wrappedElement));
                                sendResultPacket(iq);
                            } else {
                                Element extraError = DocumentHelper.createElement(QName.get("unknown-stanza", "http://jabber.org/protocol/connectionmanager#errors"));
                                sendErrorPacket(iq, PacketError.Condition.bad_request, extraError);
                            }
                        }
                    } else {
                        // Unknown IQ packet received so return error to sender
                        sendErrorPacket(iq, PacketError.Condition.bad_request, null);
                    }
                }
            } else {
                // Unknown IQ packet received so return error to sender
                sendErrorPacket(iq, PacketError.Condition.bad_request, null);
            }
        } else {
            // Unknown IQ packet received so return error to sender
            sendErrorPacket(iq, PacketError.Condition.bad_request, null);
        }
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) Message(org.xmpp.packet.Message) Element(org.dom4j.Element) LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) ClientSession(org.jivesoftware.openfire.session.ClientSession) IQ(org.xmpp.packet.IQ) List(java.util.List)

Example 8 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class MultiplexerPacketHandler method route.

/**
 * Processes a route packet that is wrapping a stanza sent by a client that is connected
 * to the connection manager.
 *
 * @param route the route packet.
 */
public void route(Route route) {
    StreamID streamID = route.getStreamID();
    if (streamID == null) {
        // No stream ID was included so return a bad_request error
        Element extraError = DocumentHelper.createElement(QName.get("id-required", "http://jabber.org/protocol/connectionmanager#errors"));
        sendErrorPacket(route, PacketError.Condition.bad_request, extraError);
    }
    LocalClientSession session = multiplexerManager.getClientSession(connectionManagerDomain, streamID);
    if (session == null) {
        // Specified Client Session does not exist
        sendErrorPacket(route, PacketError.Condition.item_not_found, null);
        return;
    }
    SessionPacketRouter router = new SessionPacketRouter(session);
    // Connection Manager already validate JIDs so just skip this expensive operation
    router.setSkipJIDValidation(true);
    try {
        router.route(route.getChildElement());
    } catch (UnknownStanzaException use) {
        Element extraError = DocumentHelper.createElement(QName.get("unknown-stanza", "http://jabber.org/protocol/connectionmanager#errors"));
        sendErrorPacket(route, PacketError.Condition.bad_request, extraError);
    } catch (Exception e) {
        Log.error("Error processing wrapped packet: " + route.getChildElement().asXML(), e);
        sendErrorPacket(route, PacketError.Condition.internal_server_error, null);
    }
}
Also used : LocalClientSession(org.jivesoftware.openfire.session.LocalClientSession) StreamID(org.jivesoftware.openfire.StreamID) Element(org.dom4j.Element) SessionPacketRouter(org.jivesoftware.openfire.SessionPacketRouter)

Example 9 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class LocalIncomingServerSession method createSession.

/**
     * Creates a new session that will receive packets. The new session will be authenticated
     * before being returned. If the authentication process fails then the answer will be
     * <tt>null</tt>.<p>
     *
     * @param serverName hostname of this server.
     * @param reader reader on the new established connection with the remote server.
     * @param connection the new established connection with the remote server.
     * @return a new session that will receive packets or null if a problem occured while
     *         authenticating the remote server or when acting as the Authoritative Server during
     *         a Server Dialback authentication process.
     * @throws org.xmlpull.v1.XmlPullParserException if an error occurs while parsing the XML.
     * @throws java.io.IOException if an input/output error occurs while using the connection.
     */
public static LocalIncomingServerSession createSession(String serverName, XMPPPacketReader reader, SocketConnection connection) throws XmlPullParserException, IOException {
    XmlPullParser xpp = reader.getXPPParser();
    String version = xpp.getAttributeValue("", "version");
    String fromDomain = xpp.getAttributeValue("", "from");
    String toDomain = xpp.getAttributeValue("", "to");
    int[] serverVersion = version != null ? decodeVersion(version) : new int[] { 0, 0 };
    if (toDomain == null) {
        toDomain = serverName;
    }
    try {
        // Get the stream ID for the new session
        StreamID streamID = SessionManager.getInstance().nextStreamID();
        // Create a server Session for the remote server
        LocalIncomingServerSession session = SessionManager.getInstance().createIncomingServerSession(connection, streamID, fromDomain);
        // Send the stream header
        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\"");
        openingStream.append(" from=\"").append(toDomain).append("\"");
        if (fromDomain != null) {
            openingStream.append(" to=\"").append(fromDomain).append("\"");
        }
        openingStream.append(" id=\"").append(streamID).append("\"");
        // implementations appears to reduce connection issues with those domains (patch by Marcin Cieślak).
        if (serverVersion[0] >= 1) {
            openingStream.append(" version=\"1.0\">");
        } else {
            openingStream.append('>');
        }
        connection.deliverRawText(openingStream.toString());
        if (serverVersion[0] >= 1) {
            // Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
            // Indicate the TLS policy to use for this connection
            Connection.TLSPolicy tlsPolicy = connection.getTlsPolicy();
            boolean hasCertificates = false;
            try {
                hasCertificates = XMPPServer.getInstance().getCertificateStoreManager().getIdentityStore(ConnectionType.SOCKET_S2S).getStore().size() > 0;
            } catch (Exception e) {
                Log.error(e.getMessage(), e);
            }
            if (Connection.TLSPolicy.required == tlsPolicy && !hasCertificates) {
                Log.error("Server session rejected. TLS is required but no certificates " + "were created.");
                return null;
            }
            connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled);
        }
        // Indicate the compression policy to use for this connection
        connection.setCompressionPolicy(connection.getConfiguration().getCompressionPolicy());
        StringBuilder sb = new StringBuilder();
        if (serverVersion[0] >= 1) {
            // Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
            // Don't offer stream-features to pre-1.0 servers, as it confuses them. Sending features to Openfire < 3.7.1 confuses it too - OF-443) 
            sb.append("<stream:features>");
            if (JiveGlobals.getBooleanProperty(ConnectionSettings.Server.TLS_ENABLED, true)) {
                sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
                if (!ServerDialback.isEnabled()) {
                    // Server dialback is disabled so TLS is required
                    sb.append("<required/>");
                }
                sb.append("</starttls>");
            }
            // Include available SASL Mechanisms
            sb.append(SASLAuthentication.getSASLMechanisms(session));
            if (ServerDialback.isEnabled()) {
                // Also offer server dialback (when TLS is not required). Server dialback may be offered
                // after TLS has been negotiated and a self-signed certificate is being used
                sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"><errors/></dialback>");
            }
            sb.append("</stream:features>");
        }
        connection.deliverRawText(sb.toString());
        // Set the domain or subdomain of the local server targeted by the remote server
        session.setLocalDomain(serverName);
        return session;
    } catch (Exception e) {
        Log.error("Error establishing connection from remote server:" + connection, e);
        connection.close();
        return null;
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) XmlPullParser(org.xmlpull.v1.XmlPullParser) Connection(org.jivesoftware.openfire.Connection) SocketConnection(org.jivesoftware.openfire.net.SocketConnection) KeyStoreException(java.security.KeyStoreException) UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) IOException(java.io.IOException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 10 with StreamID

use of org.jivesoftware.openfire.StreamID in project Openfire by igniterealtime.

the class LocalOutgoingServerSession method attemptDialbackOverTLS.

private static LocalOutgoingServerSession attemptDialbackOverTLS(Connection connection, XMPPPacketReader reader, String localDomain, String remoteDomain, String id) {
    final Logger log = LoggerFactory.getLogger(Log.getName() + "[Dialback over TLS for: " + localDomain + " to: " + remoteDomain + " (Stream ID: " + id + ")]");
    if (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned()) {
        log.debug("Trying to connecting using dialback over TLS.");
        ServerDialback method = new ServerDialback(connection, localDomain);
        OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
        if (method.authenticateDomain(newSocketReader, localDomain, remoteDomain, id)) {
            log.debug("Dialback over TLS was successful.");
            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));
            return session;
        } else {
            log.debug("Dialback over TLS failed");
            return null;
        }
    } else {
        log.debug("Skipping server dialback attempt as it has been disabled by local configuration.");
        return null;
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) OutgoingServerSocketReader(org.jivesoftware.openfire.server.OutgoingServerSocketReader) JID(org.xmpp.packet.JID) BasicStreamIDFactory(org.jivesoftware.openfire.spi.BasicStreamIDFactory) Logger(org.slf4j.Logger) ServerDialback(org.jivesoftware.openfire.server.ServerDialback)

Aggregations

StreamID (org.jivesoftware.openfire.StreamID)20 LocalClientSession (org.jivesoftware.openfire.session.LocalClientSession)7 IOException (java.io.IOException)5 Element (org.dom4j.Element)5 UnauthorizedException (org.jivesoftware.openfire.auth.UnauthorizedException)4 ConnectionMultiplexerSession (org.jivesoftware.openfire.session.ConnectionMultiplexerSession)4 Logger (org.slf4j.Logger)4 XmlPullParserException (org.xmlpull.v1.XmlPullParserException)4 Nonnull (javax.annotation.Nonnull)3 Connection (org.jivesoftware.openfire.Connection)3 OutgoingServerSocketReader (org.jivesoftware.openfire.server.OutgoingServerSocketReader)3 XmlPullParser (org.xmlpull.v1.XmlPullParser)3 JID (org.xmpp.packet.JID)3 InputStreamReader (java.io.InputStreamReader)2 UnknownHostException (java.net.UnknownHostException)2 java.util (java.util)2 Collectors (java.util.stream.Collectors)2 AsyncEvent (javax.servlet.AsyncEvent)2 AsyncListener (javax.servlet.AsyncListener)2 XMPPPacketReader (org.dom4j.io.XMPPPacketReader)2