Esempio n. 1
0
void tst_QXmppSasl::testResponse()
{
    QFETCH(QByteArray, xml);
    QFETCH(QByteArray, value);

    // no condition
    QXmppSaslResponse response;
    parsePacket(response, xml);
    QCOMPARE(response.value(), value);
    serializePacket(response, xml);
}
void QXmppIncomingClient::handleStanza (const QDomElement &nodeRecv)
{
    const QString ns = nodeRecv.namespaceURI();

    if (d->idleTimer->interval())
        d->idleTimer->start();

    if (ns == ns_tls && nodeRecv.tagName() == QLatin1String ("starttls"))
    {
        sendData ("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
        socket()->flush();
        socket()->startServerEncryption();
        return;
    }

    else if (ns == ns_sasl)
    {
        if (!d->passwordChecker)
        {
            warning ("Cannot perform authentication, no password checker");
            sendPacket (QXmppSaslFailure ("temporary-auth-failure"));
            disconnectFromHost();
            return;
        }

        if (nodeRecv.tagName() == QLatin1String ("auth"))
        {
            QXmppSaslAuth auth;
            auth.parse (nodeRecv);

            d->saslServer = QXmppSaslServer::create (auth.mechanism(), this);

            if (!d->saslServer)
            {
                sendPacket (QXmppSaslFailure ("invalid-mechanism"));
                disconnectFromHost();
                return;
            }

            d->saslServer->setRealm (d->domain.toUtf8());

            QByteArray challenge;
            QXmppSaslServer::Response result = d->saslServer->respond (auth.value(), challenge);

            if (result == QXmppSaslServer::InputNeeded)
            {
                // check credentials
                d->checkCredentials (auth.value());
            }

            else if (result == QXmppSaslServer::Challenge)
                sendPacket (QXmppSaslChallenge (challenge));

            else
            {
                // FIXME: what condition?
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
                return;
            }
        }

        else if (nodeRecv.tagName() == QLatin1String ("response"))
        {
            QXmppSaslResponse response;
            response.parse (nodeRecv);

            if (!d->saslServer)
            {
                warning ("SASL response received, but no mechanism selected");
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
                return;
            }

            QByteArray challenge;
            QXmppSaslServer::Response result = d->saslServer->respond (response.value(), challenge);

            if (result == QXmppSaslServer::InputNeeded)
            {
                // check credentials
                d->checkCredentials (response.value());
            }

            else if (result == QXmppSaslServer::Succeeded)
            {
                // authentication succeeded
                d->jid = QString ("%1@%2").arg (d->saslServer->username(), d->domain);
                info (QString ("Authentication succeeded for '%1' from %2").arg (d->jid, d->origin()));
                updateCounter ("incoming-client.auth.success");
                sendPacket (QXmppSaslSuccess());
                handleStart();
            }

            else
            {
                // FIXME: what condition?
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
            }
        }
    }

    else if (ns == ns_client)
    {
        if (nodeRecv.tagName() == QLatin1String ("iq"))
        {
            const QString type = nodeRecv.attribute ("type");

            if (QXmppBindIq::isBindIq (nodeRecv) && type == QLatin1String ("set"))
            {
                QXmppBindIq bindSet;
                bindSet.parse (nodeRecv);
                d->resource = bindSet.resource().trimmed();

                if (d->resource.isEmpty())
                    d->resource = QXmppUtils::generateStanzaHash();

                d->jid = QString ("%1/%2").arg (QXmppUtils::jidToBareJid (d->jid), d->resource);

                QXmppBindIq bindResult;
                bindResult.setType (QXmppIq::Result);
                bindResult.setId (bindSet.id());
                bindResult.setJid (d->jid);
                sendPacket (bindResult);

                // bound
                emit connected();
                return;
            }

            else if (QXmppSessionIq::isSessionIq (nodeRecv) && type == QLatin1String ("set"))
            {
                QXmppSessionIq sessionSet;
                sessionSet.parse (nodeRecv);

                QXmppIq sessionResult;
                sessionResult.setType (QXmppIq::Result);
                sessionResult.setId (sessionSet.id());
                sessionResult.setTo (d->jid);
                sendPacket (sessionResult);
                return;
            }
        }

        // check the sender is legitimate
        const QString from = nodeRecv.attribute ("from");

        if (!from.isEmpty() && from != d->jid && from != QXmppUtils::jidToBareJid (d->jid))
        {
            warning (QString ("Received a stanza from unexpected JID %1").arg (from));
            return;
        }

        // process unhandled stanzas
        if (nodeRecv.tagName() == QLatin1String ("iq") ||
                nodeRecv.tagName() == QLatin1String ("message") ||
                nodeRecv.tagName() == QLatin1String ("presence"))
        {
            QDomElement nodeFull (nodeRecv);

            // if the sender is empty, set it to the appropriate JID
            if (nodeFull.attribute ("from").isEmpty())
            {
                if (nodeFull.tagName() == QLatin1String ("presence") &&
                        (nodeFull.attribute ("type") == QLatin1String ("subscribe") ||
                         nodeFull.attribute ("type") == QLatin1String ("subscribed")))
                    nodeFull.setAttribute ("from", QXmppUtils::jidToBareJid (d->jid));

                else
                    nodeFull.setAttribute ("from", d->jid);
            }

            // if the recipient is empty, set it to the local domain
            if (nodeFull.attribute ("to").isEmpty())
                nodeFull.setAttribute ("to", d->domain);

            // emit stanza for processing by server
            emit elementReceived (nodeFull);
        }
    }
}