/**
  * Creates a new client session that was established to the specified connection manager. The new
  * session will not be findable through its stream ID.
  *
  * @param connectionManagerDomain the connection manager that is handling the connection of the
  *     session.
  * @param streamID the stream ID created by the connection manager for the new session.
  * @param hostName the address's hostname of the client or null if using old connection manager.
  * @param hostAddress the textual representation of the address of the client or null if using old
  *     CM.
  * @return true if a session was created or false if the client should disconnect.
  */
 public boolean createClientSession(
     String connectionManagerDomain, String streamID, String hostName, String hostAddress) {
   Connection connection =
       new ClientSessionConnection(connectionManagerDomain, hostName, hostAddress);
   // Check if client is allowed to connect from the specified IP address. Ignore the checking if
   // connection
   // manager is old version and is not passing client's address
   byte[] address = null;
   try {
     address = connection.getAddress();
   } catch (UnknownHostException e) {
     // Ignore
   }
   if (address == null || LocalClientSession.isAllowed(connection)) {
     LocalClientSession session =
         SessionManager.getInstance().createClientSession(connection, new BasicStreamID(streamID));
     // Register that this streamID belongs to the specified connection manager
     streamIDs.put(streamID, connectionManagerDomain);
     // Register which sessions are being hosted by the speicifed connection manager
     Map<String, LocalClientSession> sessions = sessionsByManager.get(connectionManagerDomain);
     if (sessions == null) {
       synchronized (connectionManagerDomain.intern()) {
         sessions = sessionsByManager.get(connectionManagerDomain);
         if (sessions == null) {
           sessions = new ConcurrentHashMap<>();
           sessionsByManager.put(connectionManagerDomain, sessions);
         }
       }
     }
     sessions.put(streamID, session);
     return true;
   }
   return false;
 }
 @Override
 boolean createSession(
     String namespace, String serverName, XmlPullParser xpp, Connection connection)
     throws XmlPullParserException {
   if ("jabber:client".equals(namespace)) {
     // The connected client is a regular client so create a ClientSession
     session = LocalClientSession.createSession(serverName, xpp, connection);
     return true;
   }
   return false;
 }
  /**
   * Login to the XMPP server and establish a non-anonymous user session using the given username
   * and resource. When <tt>createIfNotExist</tt> is <tt>true</tt>, a new user with the username
   * will be created and stored in the database if it does not exist. When <tt>false</tt>, and the
   * user does not exist, the method will not attempt the login. Whenever there's an error, the bot
   * will not login.
   *
   * @param username Username to login with.
   * @param resource The resource the user will bind to.
   * @param createIfNotExist When specified as <tt>true</tt>, a new user will be created and stored
   *     in the database if it does not exist.
   * @throws SessionAlreadyExistsException If the bot's session already exists.
   * @throws UserNotFoundException If it fails to create the user.
   */
  public void login(String username, String resource, boolean createIfNotExist)
      throws SessionAlreadyExistsException, UserNotFoundException {
    LOGGER.debug("Bot login with username:{} with resource:{}", username, resource);

    if (isClosed()) throw new SessionAlreadyExistsException();

    JID jid =
        new JID(
            username.toLowerCase(),
            XMPPServer.getInstance().getServerInfo().getXMPPDomain(),
            resource);
    ClientSession oldSession = SessionManager.getInstance().getSession(jid);

    // Check for session conflict
    if (oldSession != null) {
      try {
        int count = oldSession.incrementConflictCount();
        int conflictLimit = SessionManager.getInstance().getConflictKickLimit();
        if (conflictLimit != SessionManager.NEVER_KICK && count > conflictLimit) {
          // Kick out the old connection that is conflicting with the
          // new one
          StreamError error = new StreamError(StreamError.Condition.conflict);
          oldSession.deliverRawText(error.toXML());
          oldSession.close();
        } else throw new SessionAlreadyExistsException();
      } catch (Exception e) {
        LOGGER.error("Error during login", e);
      }
    }

    if (!XMPPServer.getInstance().getUserManager().isRegisteredUser(jid.getNode())) {
      if (createIfNotExist) {
        try {
          // Bot doesn't care of whatever password it is.
          XMPPServer.getInstance()
              .getUserManager()
              .createUser(jid.getNode(), StringUtils.randomString(15), null, null);
        } catch (UserAlreadyExistsException e) {
          // Ignore
        }
      } else {
        throw new UserNotFoundException();
      }
    }

    localClientSession = SessionManager.getInstance().createClientSession(this);

    localClientSession.setAuthToken(new AuthToken(jid.getNode()), jid.getResource());

    if (packetProcessor != null) {
      packetProcessor.initialize(this);
      initProcessor = true;
    }
  }
  private void updateClearspaceClientSettings() {
    String xmppBoshSslPort = "0";
    String xmppBoshPort = "0";
    String xmppPort =
        String.valueOf(XMPPServer.getInstance().getConnectionManager().getClientListenerPort());
    if (JiveGlobals.getBooleanProperty(
        HttpBindManager.HTTP_BIND_ENABLED, HttpBindManager.HTTP_BIND_ENABLED_DEFAULT)) {
      int boshSslPort = HttpBindManager.getInstance().getHttpBindSecurePort();
      int boshPort = HttpBindManager.getInstance().getHttpBindUnsecurePort();
      try {
        if (HttpBindManager.getInstance().isHttpsBindActive()
            && LocalClientSession.getTLSPolicy()
                != org.jivesoftware.openfire.Connection.TLSPolicy.disabled) {
          xmppBoshSslPort = String.valueOf(boshSslPort);
        }
      } catch (Exception e) {
        // Exception while working with certificate
        Log.debug(
            "Error while checking SSL certificate.  Instructing Clearspace not to use SSL port.");
      }
      if (HttpBindManager.getInstance().isHttpBindActive() && boshPort > 0) {
        xmppBoshPort = String.valueOf(boshPort);
      }
    }

    try {
      String path = CHAT_URL_PREFIX + "updateClientSettings/";

      // Creates the XML with the data
      Document groupDoc = DocumentHelper.createDocument();
      Element rootE = groupDoc.addElement("updateClientSettings");
      rootE.addElement("boshSslPort").setText(xmppBoshSslPort);
      rootE.addElement("boshPort").setText(xmppBoshPort);
      rootE.addElement("tcpPort").setText(xmppPort);

      executeRequest(POST, path, groupDoc.asXML());
    } catch (UnauthorizedException ue) {
      Log.error("Error updating the client settings of Clearspace", ue);
    } catch (Exception e) {
      Log.error("Error updating the client settings of Clearspace", e);
    }
  }
  /**
   * 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;
  }
 /**
  * Get the node's portion of the bot's JID.
  *
  * @return Node portion of the bot's JID.
  */
 public String getUsername() {
   if (localClientSession == null) return null;
   return localClientSession.getAddress().getNode();
 }
 /**
  * Get the resource portion of the bot's JID.
  *
  * @return Resource portion of the bot's JID.
  */
 public String getResource() {
   if (localClientSession == null) return null;
   return localClientSession.getAddress().getResource();
 }
 private void stopOfflineFlooding(JID senderJID) {
   LocalClientSession session = (LocalClientSession) sessionManager.getSession(senderJID);
   if (session != null) {
     session.setOfflineFloodStopped(true);
   }
 }