Search in sources :

Example 11 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
 * {@code null}.<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.
 * @param directTLS true of connections are immediately encrypted (as opposed to plain text / startls).
 * @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, boolean directTLS) 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 (!directTLS && 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) UnauthorizedException(org.jivesoftware.openfire.auth.UnauthorizedException) IOException(java.io.IOException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException)

Example 12 with StreamID

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

the class ClientSessionConnection method deliverRawText.

/**
 * Delivers the stanza to the Connection Manager that in turn will forward it to the
 * target user. Connection Managers may have one or many connections to the server so
 * just get any connection to the Connection Manager (uses a random) and use it.<p>
 *
 * The stanza to send wrapped with a special IQ packet. The wrapper IQ packet will be
 * sent to the Connection Manager and the stream ID of this Client Session will be used
 * for identifying that the wrapped stanza must be sent to the connected user.
 *
 * @param text the stanza to send to the user.
 */
@Override
public void deliverRawText(String text) {
    StreamID streamID = session.getStreamID();
    ConnectionMultiplexerSession multiplexerSession = multiplexerManager.getMultiplexerSession(connectionManagerName, streamID);
    if (multiplexerSession != null) {
        // Wrap packet so that the connection manager can figure out the target session
        StringBuilder sb = new StringBuilder(200 + text.length());
        sb.append("<route from=\"").append(serverName);
        sb.append("\" to=\"").append(connectionManagerName);
        sb.append("\" streamid=\"").append(streamID.getID()).append("\">");
        sb.append(text);
        sb.append("</route>");
        // Deliver the wrapped stanza
        multiplexerSession.deliverRawText(sb.toString());
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) ConnectionMultiplexerSession(org.jivesoftware.openfire.session.ConnectionMultiplexerSession)

Example 13 with StreamID

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

the class ClientSessionConnection method closeVirtualConnection.

/**
 * If the Connection Manager or the Client requested to close the connection then just do
 * nothing. But if the server originated the request to close the connection then we need
 * to send to the Connection Manager a packet letting him know that the Client Session needs
 * to be terminated.
 */
@Override
public void closeVirtualConnection() {
    // Figure out who requested the connection to be closed
    StreamID streamID = session.getStreamID();
    if (multiplexerManager.getClientSession(connectionManagerName, streamID) == null) {
    // Client or Connection manager requested to close the session
    // Do nothing since it has already been removed and closed
    } else {
        ConnectionMultiplexerSession multiplexerSession = multiplexerManager.getMultiplexerSession(connectionManagerName, streamID);
        if (multiplexerSession != null) {
            // Server requested to close the client session so let the connection manager
            // know that he has to finish the client session
            IQ closeRequest = new IQ(IQ.Type.set);
            closeRequest.setFrom(serverName);
            closeRequest.setTo(connectionManagerName);
            Element child = closeRequest.setChildElement("session", "http://jabber.org/protocol/connectionmanager");
            child.addAttribute("id", streamID.getID());
            child.addElement("close");
            multiplexerSession.process(closeRequest);
        }
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) ConnectionMultiplexerSession(org.jivesoftware.openfire.session.ConnectionMultiplexerSession) Element(org.dom4j.Element) IQ(org.xmpp.packet.IQ)

Example 14 with StreamID

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

the class ClientSessionConnection method deliver.

/**
 * Delivers the packet to the Connection Manager that in turn will forward it to the
 * target user. Connection Managers may have one or many connections to the server so
 * just get any connection to the Connection Manager (uses a random) and use it.<p>
 *
 * If the packet to send does not have a TO attribute then wrap the packet with a
 * special IQ packet. The wrapper IQ packet will be sent to the Connection Manager
 * and the stream ID of this Client Session will be used for identifying that the wrapped
 * packet must be sent to the connected user. Since some packets can be exchanged before
 * the user has a binded JID we need to use the stream ID as the unique identifier.
 *
 * @param packet the packet to send to the user.
 */
@Override
public void deliver(Packet packet) {
    StreamID streamID = session.getStreamID();
    ConnectionMultiplexerSession multiplexerSession = multiplexerManager.getMultiplexerSession(connectionManagerName, streamID);
    if (multiplexerSession != null) {
        // Wrap packet so that the connection manager can figure out the target session
        Route wrapper = new Route(streamID);
        wrapper.setFrom(serverName);
        wrapper.setTo(connectionManagerName);
        wrapper.setChildElement(packet.getElement().createCopy());
        // Deliver wrapper
        multiplexerSession.process(wrapper);
        session.incrementServerPacketCount();
    }
}
Also used : StreamID(org.jivesoftware.openfire.StreamID) ConnectionMultiplexerSession(org.jivesoftware.openfire.session.ConnectionMultiplexerSession)

Example 15 with StreamID

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

the class HttpSession method forwardRequest.

/**
 * Forwards a client request, which is related to a session, to the server. A connection is
 * created and queued up in the provided session. When a connection reaches the top of a queue
 * any pending packets bound for the client will be forwarded to the client through the
 * connection.
 *
 * @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.
 *
 * @throws org.jivesoftware.openfire.http.HttpBindException for several reasons: if the encoding inside of an auth packet is
 * not recognized by the server, or if the packet type is not recognized.
 * @throws org.jivesoftware.openfire.http.HttpConnectionClosedException if the session is no longer available.
 * @throws IOException if an input or output exception occurred
 */
public void forwardRequest(HttpBindBody body, AsyncContext context) throws HttpBindException, HttpConnectionClosedException, IOException {
    final HttpConnection connection = this.createConnection(body, context);
    final long rid = body.getRid();
    final StreamID streamid = getStreamID();
    // Check if security restraints are observed.
    if (isSecure && !connection.isSecure()) {
        throw new HttpBindException("Session was started from secure connection, all " + "connections on this session must be secured.", BoshBindingError.badRequest);
    }
    synchronized (connectionQueue) {
        // Check if the provided RID is in the to-be-expected window.
        if (rid > (lastSequentialRequestID + maxRequests)) {
            Log.warn("Request {} > {}, ending session {}", body.getRid(), (lastSequentialRequestID + maxRequests), getStreamID());
            throw new HttpBindException("Unexpected RID error.", BoshBindingError.itemNotFound);
        }
        // Check for retransmission.
        if (rid <= lastAnsweredRequestID) {
            redeliver(connection);
            return;
        }
        // TODO is there overlap with the retransmission logic above? Can this be simplified?
        for (HttpConnection queuedConnection : connectionQueue) {
            if (queuedConnection.getRequestId() == rid) {
                Log.debug("Found previous connection in queue with rid {}", rid);
                if (queuedConnection.isClosed()) {
                    Log.debug("It's closed - copying deliverables");
                    Delivered deliverable = retrieveDeliverable(rid);
                    if (deliverable == null) {
                        Log.warn("In session {} deliverable unavailable for {}", streamid, rid);
                        throw new HttpBindException("Unexpected RID error.", BoshBindingError.itemNotFound);
                    }
                    connection.deliverBody(asBodyText(deliverable.deliverables), true);
                } else {
                    Log.debug("For session {} queued connection is still open - calling close() on the old connection (as the new connection will replace it).", streamid);
                    // TODO implement section 14.3 of XEP 0124 instead of this!
                    deliver(queuedConnection, Collections.singletonList(new Deliverable("")), true);
                    connection.close();
                }
                break;
            }
        }
    }
    checkOveractivity(connection);
    // Schedule the connection for consumption.
    processConnection(connection, context);
    resetInactivityTimeout();
}
Also used : StreamID(org.jivesoftware.openfire.StreamID)

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