All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jivesoftware.openfire.session.LocalConnectionMultiplexerSession Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2004-2009 Jive Software. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.openfire.session;

import java.util.Collection;
import java.util.Locale;

import org.dom4j.Element;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.openfire.SessionManager;
import org.jivesoftware.openfire.StreamID;
import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.auth.UnauthorizedException;
import org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager;
import org.jivesoftware.openfire.multiplex.MultiplexerPacketDeliverer;
import org.jivesoftware.openfire.net.SASLAuthentication;
import org.jivesoftware.openfire.spi.ConnectionConfiguration;
import org.jivesoftware.openfire.spi.ConnectionManagerImpl;
import org.jivesoftware.openfire.spi.ConnectionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet;
import org.xmpp.packet.StreamError;

/**
 * Represents a session between the server and a connection manager.

* * Each Connection Manager has its own domain. Each connection from the same connection manager * uses a different resource. Unlike any other session, connection manager sessions are not * present in the routing table. This means that connection managers are not reachable entities. * In other words, entities cannot send packets to connection managers but clients being hosted * by them. The main reason behind this design decision is that connection managers are private * components of the server so they can only be contacted by the server. Connection Manager * sessions are present in {@link SessionManager} but not in {@link org.jivesoftware.openfire.RoutingTable}. Use * {@link SessionManager#getConnectionMultiplexerSessions(String)} to get all sessions or * {@link org.jivesoftware.openfire.multiplex.ConnectionMultiplexerManager#getMultiplexerSession(String)} * to get a random session to a given connection manager. * * @author Gaston Dombiak */ public class LocalConnectionMultiplexerSession extends LocalSession implements ConnectionMultiplexerSession { private static final Logger Log = LoggerFactory.getLogger(LocalConnectionMultiplexerSession.class); public static LocalConnectionMultiplexerSession createSession(String serverName, XmlPullParser xpp, Connection connection) throws XmlPullParserException { String domain = xpp.getAttributeValue("", "to"); Log.debug("LocalConnectionMultiplexerSession: [ConMng] Starting registration of new connection manager for domain: " + domain); // Default answer header in case of an error StringBuilder sb = new StringBuilder(); sb.append(""); sb.append(""); // Check that a domain was provided in the stream header if (domain == null) { Log.debug("LocalConnectionMultiplexerSession: [ConMng] Domain not specified in stanza: " + xpp.getText()); // Include the bad-format in the response StreamError error = new StreamError(StreamError.Condition.bad_format); sb.append(error.toXML()); connection.deliverRawText(sb.toString()); // Close the underlying connection connection.close(); return null; } // Get the requested domain JID address = new JID(domain); // Check that a secret key was configured in the server String secretKey = ConnectionMultiplexerManager.getDefaultSecret(); if (secretKey == null) { Log.debug("LocalConnectionMultiplexerSession: [ConMng] A shared secret for connection manager was not found."); // Include the internal-server-error in the response StreamError error = new StreamError(StreamError.Condition.internal_server_error); sb.append(error.toXML()); connection.deliverRawText(sb.toString()); // Close the underlying connection connection.close(); return null; } // Check that the requested subdomain is not already in use if (SessionManager.getInstance().getConnectionMultiplexerSession(address) != null) { Log.debug("LocalConnectionMultiplexerSession: [ConMng] Another connection manager is already using domain: " + domain); // Domain already occupied so return a conflict error and close the connection // Include the conflict error in the response StreamError error = new StreamError(StreamError.Condition.conflict); sb.append(error.toXML()); connection.deliverRawText(sb.toString()); // Close the underlying connection connection.close(); return null; } // Indicate the TLS policy to use for this connection connection.setTlsPolicy( connection.getConfiguration().getTlsPolicy() ); // Indicate the compression policy to use for this connection connection.setCompressionPolicy( connection.getConfiguration().getCompressionPolicy() ); // Set the connection manager domain to use delivering a packet fails ((MultiplexerPacketDeliverer) connection.getPacketDeliverer()) .setConnectionManagerDomain(address.getDomain()); // Create a ConnectionMultiplexerSession for the new session originated // from the connection manager LocalConnectionMultiplexerSession session = SessionManager.getInstance().createMultiplexerSession(connection, address); // Set the address of the new session session.setAddress(address); connection.init(session); try { Log.debug("LocalConnectionMultiplexerSession: [ConMng] Send stream header with ID: " + session.getStreamID() + " for connection manager with domain: " + domain); // Build the start packet response sb = new StringBuilder(); sb.append(""); sb.append(""); connection.deliverRawText(sb.toString()); // Announce stream features. sb = new StringBuilder(490); sb.append(""); if (connection.getTlsPolicy() != Connection.TLSPolicy.disabled) { sb.append(""); if (connection.getTlsPolicy() == Connection.TLSPolicy.required) { sb.append(""); } sb.append(""); } // Include Stream features String specificFeatures = session.getAvailableStreamFeatures(); if (specificFeatures != null) { sb.append(specificFeatures); } sb.append(""); connection.deliverRawText(sb.toString()); return session; } catch (Exception e) { Log.error("An error occured while creating a Connection Manager Session", e); // Close the underlying connection connection.close(); return null; } } public LocalConnectionMultiplexerSession(String serverName, Connection connection, StreamID streamID) { super(serverName, connection, streamID, Locale.getDefault()); } @Override public String getAvailableStreamFeatures() { if (conn.getTlsPolicy() == Connection.TLSPolicy.required && !conn.isSecure()) { return null; } // Include Stream Compression Mechanism if (conn.getCompressionPolicy() != Connection.CompressionPolicy.disabled && !conn.isCompressed()) { return "zlib"; } return null; } /** * Authenticates the connection manager. Shared secret is validated with the one provided * by the connection manager. If everything went fine then the session will have a status * of "authenticated" and the connection manager will receive the client configuration * options. * * @param digest the digest provided by the connection manager with the handshake stanza. * @return true if the connection manager was sucessfully authenticated. */ public boolean authenticate(String digest) { // Perform authentication. Wait for the handshake (with the secret key) String anticipatedDigest = AuthFactory.createDigest(getStreamID().getID(), ConnectionMultiplexerManager.getDefaultSecret()); // Check that the provided handshake (secret key + sessionID) is correct if (!anticipatedDigest.equalsIgnoreCase(digest)) { Log.debug("LocalConnectionMultiplexerSession: [ConMng] Incorrect handshake for connection manager with domain: " + getAddress().getDomain()); // The credentials supplied by the initiator are not valid (answer an error // and close the connection) conn.deliverRawText(new StreamError(StreamError.Condition.not_authorized).toXML()); // Close the underlying connection conn.close(); return false; } else { // Component has authenticated fine setStatus(STATUS_AUTHENTICATED); // Send empty handshake element to acknowledge success conn.deliverRawText(""); Log.debug("LocalConnectionMultiplexerSession: [ConMng] Connection manager was AUTHENTICATED with domain: " + getAddress()); sendClientOptions(); return true; } } /** * Send to the Connection Manager the connection options available for clients. The info * to send includes: *

    *
  • if TLS is available, optional or required *
  • SASL mechanisms available before TLS is negotiated *
  • if compression is available *
  • if Non-SASL authentication is available *
  • if In-Band Registration is available *
mechanisms = SASLAuthentication.getSupportedMechanisms(); if (!mechanisms.isEmpty()) { Element sasl = child.addElement("mechanisms", "urn:ietf:params:xml:ns:xmpp-sasl"); for (String mechanism : mechanisms) { sasl.addElement("mechanism").setText(mechanism); } } // Add info about Stream Compression if (configuration.getCompressionPolicy() == Connection.CompressionPolicy.optional) { Element comp = child.addElement("compression", "http://jabber.org/features/compress"); comp.addElement("method").setText("zlib"); } // Add info about Non-SASL authentication if (XMPPServer.getInstance().getIQRouter().supports("jabber:iq:auth")) { child.addElement("auth", "http://jabber.org/features/iq-auth"); } // Add info about In-Band Registration if (XMPPServer.getInstance().getIQRegisterHandler().isInbandRegEnabled()) { child.addElement("register", "http://jabber.org/features/iq-register"); } // Send the options process(options); } @Override boolean canProcess(Packet packet) { return true; } @Override void deliver(Packet packet) throws UnauthorizedException { if (!conn.isClosed()) { conn.deliver(packet); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy