Пример #1
0
void QXmppOutgoingClient::handleStreamFeaturesOrDisconnect(const QDomElement& nodeRecv)
{
    if (!QXmppStreamFeatures::isStreamFeatures(nodeRecv)) {
        warning("unexpected node received, stream features expected");
        disconnectFromHost();
        return;
    }

    QXmppStreamFeatures features;
    features.parse(nodeRecv);

    if (!socket()->isEncrypted()) {
        // determine TLS mode to use
        const QXmppConfiguration::StreamSecurityMode localSecurity = configuration().streamSecurityMode();
        const QXmppStreamFeatures::Mode remoteSecurity = features.tlsMode();
        if (!socket()->supportsSsl() &&
            (localSecurity == QXmppConfiguration::TLSRequired ||
             remoteSecurity == QXmppStreamFeatures::Required))
        {
            warning("Disconnecting as TLS is required, but SSL support is not available");
            disconnectFromHost();
            return;
        }
        if (localSecurity == QXmppConfiguration::TLSRequired &&
          remoteSecurity == QXmppStreamFeatures::Disabled)
        {
            warning("Disconnecting as TLS is required, but not supported by the server");
            disconnectFromHost();
            return;
        }

        if (socket()->supportsSsl() &&
            localSecurity != QXmppConfiguration::TLSDisabled &&
            remoteSecurity != QXmppStreamFeatures::Disabled)
        {
            // enable TLS as it is support by both parties
            d->state = QXmppOutgoingClientPrivate::StartingTLS;
            sendData("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
            return;
        }
    }

    // handle authentication
    const bool nonSaslAvailable = features.nonSaslAuthMode() != QXmppStreamFeatures::Disabled;
    const bool saslAvailable = !features.authMechanisms().isEmpty();
    if (saslAvailable && configuration().useSASLAuthentication())
    {
        // supported and preferred SASL auth mechanisms
        QStringList supportedMechanisms = QXmppSaslClient::availableMechanisms();
        const QString preferredMechanism = configuration().saslAuthMechanism();
        if (configuration().facebookAppId().isEmpty() || configuration().facebookAccessToken().isEmpty())
            supportedMechanisms.removeAll("X-FACEBOOK-PLATFORM");
        if (configuration().windowsLiveAccessToken().isEmpty())
            supportedMechanisms.removeAll("X-MESSENGER-OAUTH2");
        if (configuration().googleAccessToken().isEmpty())
            supportedMechanisms.removeAll("X-OAUTH2");

        // determine SASL Authentication mechanism to use
        QStringList commonMechanisms;
        QString usedMechanism;
        foreach (const QString &mechanism, features.authMechanisms()) {
            if (supportedMechanisms.contains(mechanism))
                commonMechanisms << mechanism;
        }
        if (commonMechanisms.isEmpty()) {
            warning("No supported SASL Authentication mechanism available");
            disconnectFromHost();
            return;
        } else if (!commonMechanisms.contains(preferredMechanism)) {
            info(QString("Desired SASL Auth mechanism '%1' is not available, selecting first available one").arg(preferredMechanism));
            usedMechanism = commonMechanisms.first();
        } else {
            usedMechanism = preferredMechanism;
        }

        d->saslClient = QXmppSaslClient::create(usedMechanism, this);
        if (!d->saslClient) {
            warning("SASL mechanism negotiation failed");
            disconnectFromHost();
            return;
        }
        info(QString("SASL mechanism '%1' selected").arg(d->saslClient->mechanism()));
        d->saslClient->setHost(d->config.domain());
        d->saslClient->setServiceType("xmpp");
        if (d->saslClient->mechanism() == "X-FACEBOOK-PLATFORM") {
            d->saslClient->setUsername(configuration().facebookAppId());
            d->saslClient->setPassword(configuration().facebookAccessToken());
        } else if (d->saslClient->mechanism() == "X-MESSENGER-OAUTH2") {
            d->saslClient->setPassword(configuration().windowsLiveAccessToken());
        } else if (d->saslClient->mechanism() == "X-OAUTH2") {
            d->saslClient->setUsername(configuration().user());
            d->saslClient->setPassword(configuration().googleAccessToken());
        } else {
            d->saslClient->setUsername(configuration().user());
            d->saslClient->setPassword(configuration().password());
        }

        // send SASL auth request
        QByteArray response;
        if (!d->saslClient->respond(QByteArray(), response)) {
            warning("SASL initial response failed");
            disconnectFromHost();
            return;
        }
        d->state = QXmppOutgoingClientPrivate::Authenticating;
        sendPacket(QXmppSaslAuth(d->saslClient->mechanism(), response));
        return;
    } else if(nonSaslAvailable && configuration().useNonSASLAuthentication()) {
Пример #2
0
void QXmppOutgoingServer::handleStanza(const QDomElement &stanza)
{
    const QString ns = stanza.namespaceURI();

    if(QXmppStreamFeatures::isStreamFeatures(stanza))
    {
        QXmppStreamFeatures features;
        features.parse(stanza);

        if (!socket()->isEncrypted())
        {
            // check we can satisfy TLS constraints
            if (!socket()->supportsSsl() &&
                 features.tlsMode() == QXmppStreamFeatures::Required)
            {
                warning("Disconnecting as TLS is required, but SSL support is not available");
                disconnectFromHost();
                return;
            }

            // enable TLS if possible
            if (socket()->supportsSsl() &&
                features.tlsMode() != QXmppStreamFeatures::Disabled)
            {
                sendData("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
                return;
            }
        }

        // send dialback if needed
        d->dialbackTimer->stop();
        sendDialback();
    }
    else if (ns == ns_tls)
    {
        if (stanza.tagName() == QLatin1String("proceed"))
        {
            debug("Starting encryption");
            socket()->startClientEncryption();
            return;
        }
    }
    else if (QXmppDialback::isDialback(stanza))
    {
        QXmppDialback response;
        response.parse(stanza);

        // check the request is valid
        if (response.from().isEmpty() ||
            response.to() != d->localDomain ||
            response.type().isEmpty())
        {
            warning("Invalid dialback response received");
            return;
        }
        if (response.command() == QXmppDialback::Result)
        {
            if (response.type() == QLatin1String("valid"))
            {
                info(QString("Outgoing server stream to %1 is ready").arg(response.from()));
                d->ready = true;

                // send queued data
                Q_FOREACH (const QByteArray &data, d->dataQueue)
                    sendData(data);
                d->dataQueue.clear();

                // emit signal
                Q_EMIT connected();
            }
        }
        else if (response.command() == QXmppDialback::Verify)