/** * Returns a newly created session between the server and a client. The session will be created * and returned only if correct name/prefix (i.e. 'stream' or 'flash') and namespace were provided * by the client. * * @param serverName the name of the server where the session is connecting to. * @param xpp the parser that is reading the provided XML through the connection. * @param connection the connection with the client. * @return a newly created session between the server and a client. * @throws org.xmlpull.v1.XmlPullParserException if an error occurs while parsing incoming data. */ public static LocalClientSession createSession( String serverName, XmlPullParser xpp, Connection connection) throws XmlPullParserException { boolean isFlashClient = xpp.getPrefix().equals("flash"); connection.setFlashClient(isFlashClient); // Conduct error checking, the opening tag should be 'stream' // in the 'etherx' namespace if (!xpp.getName().equals("stream") && !isFlashClient) { throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-stream")); } if (!xpp.getNamespace(xpp.getPrefix()).equals(ETHERX_NAMESPACE) && !(isFlashClient && xpp.getNamespace(xpp.getPrefix()).equals(FLASH_NAMESPACE))) { throw new XmlPullParserException(LocaleUtils.getLocalizedString("admin.error.bad-namespace")); } if (!allowedIPs.isEmpty()) { String hostAddress = "Unknown"; // The server is using a whitelist so check that the IP address of the client // is authorized to connect to the server try { hostAddress = connection.getHostAddress(); } catch (UnknownHostException e) { // Do nothing } if (!isAllowed(connection)) { // Client cannot connect from this IP address so end the stream and // TCP connection Log.debug( "LocalClientSession: Closed connection to client attempting to connect from: " + hostAddress); // Include the not-authorized error in the response StreamError error = new StreamError(StreamError.Condition.not_authorized); connection.deliverRawText(error.toXML()); // Close the underlying connection connection.close(); return null; } } // Default language is English ("en"). String language = "en"; // Default to a version of "0.0". Clients written before the XMPP 1.0 spec may // not report a version in which case "0.0" should be assumed (per rfc3920 // section 4.4.1). int majorVersion = 0; int minorVersion = 0; for (int i = 0; i < xpp.getAttributeCount(); i++) { if ("lang".equals(xpp.getAttributeName(i))) { language = xpp.getAttributeValue(i); } if ("version".equals(xpp.getAttributeName(i))) { try { int[] version = decodeVersion(xpp.getAttributeValue(i)); majorVersion = version[0]; minorVersion = version[1]; } catch (Exception e) { Log.error(e.getMessage(), e); } } } // If the client supports a greater major version than the server, // set the version to the highest one the server supports. if (majorVersion > MAJOR_VERSION) { majorVersion = MAJOR_VERSION; minorVersion = MINOR_VERSION; } else if (majorVersion == MAJOR_VERSION) { // If the client supports a greater minor version than the // server, set the version to the highest one that the server // supports. if (minorVersion > MINOR_VERSION) { minorVersion = MINOR_VERSION; } } // Store language and version information in the connection. connection.setLanaguage(language); connection.setXMPPVersion(majorVersion, minorVersion); // Indicate the TLS policy to use for this connection if (!connection.isSecure()) { boolean hasCertificates = false; try { hasCertificates = SSLConfig.getKeyStore().size() > 0; } catch (Exception e) { Log.error(e.getMessage(), e); } Connection.TLSPolicy tlsPolicy = getTLSPolicy(); if (Connection.TLSPolicy.required == tlsPolicy && !hasCertificates) { Log.error( "Client session rejected. TLS is required but no certificates " + "were created."); return null; } // Set default TLS policy connection.setTlsPolicy(hasCertificates ? tlsPolicy : Connection.TLSPolicy.disabled); } else { // Set default TLS policy connection.setTlsPolicy(Connection.TLSPolicy.disabled); } // Indicate the compression policy to use for this connection connection.setCompressionPolicy(getCompressionPolicy()); // Create a ClientSession for this user. LocalClientSession session = SessionManager.getInstance().createClientSession(connection); // Build the start packet response StringBuilder sb = new StringBuilder(200); sb.append("<?xml version='1.0' encoding='"); sb.append(CHARSET); sb.append("'?>"); if (isFlashClient) { sb.append("<flash:stream xmlns:flash=\"http://www.jabber.com/streams/flash\" "); } else { sb.append("<stream:stream "); } sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\" from=\""); sb.append(serverName); sb.append("\" id=\""); sb.append(session.getStreamID().toString()); sb.append("\" xml:lang=\""); sb.append(language); // Don't include version info if the version is 0.0. if (majorVersion != 0) { sb.append("\" version=\""); sb.append(majorVersion).append(".").append(minorVersion); } sb.append("\">"); connection.deliverRawText(sb.toString()); // If this is a "Jabber" connection, the session is now initialized and we can // return to allow normal packet parsing. if (majorVersion == 0) { return session; } // Otherwise, this is at least XMPP 1.0 so we need to announce stream features. sb = new StringBuilder(490); sb.append("<stream:features>"); if (connection.getTlsPolicy() != Connection.TLSPolicy.disabled) { sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">"); if (connection.getTlsPolicy() == Connection.TLSPolicy.required) { sb.append("<required/>"); } sb.append("</starttls>"); } // Include available SASL Mechanisms sb.append(SASLAuthentication.getSASLMechanisms(session)); // Include Stream features String specificFeatures = session.getAvailableStreamFeatures(); if (specificFeatures != null) { sb.append(specificFeatures); } sb.append("</stream:features>"); connection.deliverRawText(sb.toString()); return session; }
public void close() { if (conn != null) { conn.close(); } }