Пример #1
0
void QXmppIncomingClientPrivate::checkCredentials (const QByteArray &response)
{
    QXmppPasswordRequest request;
    request.setDomain (domain);
    request.setUsername (saslServer->username());

    if (saslServer->mechanism() == "PLAIN")
    {
        request.setPassword (saslServer->password());

        QXmppPasswordReply *reply = passwordChecker->checkPassword (request);
        reply->setParent (q);
        reply->setProperty ("__sasl_raw", response);
        QObject::connect (reply, SIGNAL (finished()),
                          q, SLOT (onPasswordReply()));
    }

    else if (saslServer->mechanism() == "DIGEST-MD5")
    {
        QXmppPasswordReply *reply = passwordChecker->getDigest (request);
        reply->setParent (q);
        reply->setProperty ("__sasl_raw", response);
        QObject::connect (reply, SIGNAL (finished()),
                          q, SLOT (onDigestReply()));
    }
}
Пример #2
0
void QXmppIncomingClient::onDigestReply()
{
    QXmppPasswordReply *reply = qobject_cast<QXmppPasswordReply *> (sender());

    if (!reply)
        return;

    reply->deleteLater();

    if (reply->error() == QXmppPasswordReply::TemporaryError)
    {
        warning (QString ("Temporary authentication failure for '%1' from %2").arg (d->saslServer->username(), d->origin()));
        updateCounter ("incoming-client.auth.temporary-auth-failure");
        sendPacket (QXmppSaslFailure ("temporary-auth-failure"));
        disconnectFromHost();
        return;
    }

    QByteArray challenge;
    d->saslServer->setPasswordDigest (reply->digest());

    QXmppSaslServer::Response result = d->saslServer->respond (reply->property ("__sasl_raw").toByteArray(), challenge);

    if (result != QXmppSaslServer::Challenge)
    {
        warning (QString ("Authentication failed for '%1' from %2").arg (d->saslServer->username(), d->origin()));
        updateCounter ("incoming-client.auth.not-authorized");
        sendPacket (QXmppSaslFailure ("not-authorized"));
        disconnectFromHost();
        return;
    }

    // send new challenge
    sendPacket (QXmppSaslChallenge (challenge));
}
void QXmppIncomingClient::onPasswordReply()
{
    QXmppPasswordReply *reply = qobject_cast<QXmppPasswordReply*>(sender());
    if (!reply)
        return;
    reply->deleteLater();

    const QString username = reply->property("__sasl_username").toString();
    switch (reply->error()) {
    case QXmppPasswordReply::NoError:
        d->username = username;
        info(QString("Authentication succeeded for '%1'").arg(username));
        sendData("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
        break;
    case QXmppPasswordReply::AuthorizationError:
        warning(QString("Authentication failed for '%1'").arg(username));
        sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>");
        disconnectFromHost();
        break;
    case QXmppPasswordReply::TemporaryError:
        warning(QString("Temporary authentication failure for '%1'").arg(username));
        sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><temporary-auth-failure/></failure>");
        disconnectFromHost();
        break;
    }
}
Пример #4
0
QXmppPasswordReply *QXmppPasswordChecker::checkPassword(const QXmppPasswordRequest &request)
{
    QXmppPasswordReply *reply = new QXmppPasswordReply;

    QString secret;
    QXmppPasswordReply::Error error = getPassword(request, secret);
    if (error == QXmppPasswordReply::NoError) {
        if (request.password() != secret)
            reply->setError(QXmppPasswordReply::AuthorizationError);
    } else {
        reply->setError(error);
    }

    // reply is finished
    reply->finishLater();
    return reply;
}
Пример #5
0
QXmppPasswordReply *QXmppPasswordChecker::getDigest(const QXmppPasswordRequest &request)
{
    QXmppPasswordReply *reply = new QXmppPasswordReply;

    QString secret;
    QXmppPasswordReply::Error error = getPassword(request, secret);
    if (error == QXmppPasswordReply::NoError) {
        reply->setDigest(QCryptographicHash::hash(
            (request.username() + ":" + request.domain() + ":" + secret).toUtf8(),
            QCryptographicHash::Md5));
    } else {
        reply->setError(error);
    }

    // reply is finished
    reply->finishLater();
    return reply;
}
void QXmppIncomingClient::onDigestReply()
{
    QXmppPasswordReply *reply = qobject_cast<QXmppPasswordReply*>(sender());
    if (!reply)
        return;
    reply->deleteLater();

    const QMap<QByteArray, QByteArray> saslResponse = QXmppSaslDigestMd5::parseMessage(reply->property("__sasl_raw").toByteArray());
    const QString username = QString::fromUtf8(saslResponse.value("username"));
    if (reply->error() == QXmppPasswordReply::TemporaryError) {
        warning(QString("Temporary authentication failure for '%1'").arg(username));
        sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><temporary-auth-failure/></failure>");
        disconnectFromHost();
        return;
    }

    d->saslDigest.setSecret(reply->digest());
    d->saslDigest.setDigestUri(saslResponse.value("digest-uri"));
    d->saslDigest.setNc(saslResponse.value("nc"));
    d->saslDigest.setCnonce(saslResponse.value("cnonce"));
    if (saslResponse.value("response") != d->saslDigest.calculateDigest(
            QByteArray("AUTHENTICATE:") + d->saslDigest.digestUri()))
    {
        sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>");
        disconnectFromHost();
        return;
    }

    // send new challenge
    d->username = username;
    d->saslStep = 2;
    QMap<QByteArray, QByteArray> challenge;
    challenge["rspauth"] = d->saslDigest.calculateDigest(
        QByteArray(":") + d->saslDigest.digestUri());
    const QByteArray data = QXmppSaslDigestMd5::serializeMessage(challenge).toBase64();
    sendData("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" + data +"</challenge>");
}
Пример #7
0
void QXmppIncomingClient::onPasswordReply()
{
    QXmppPasswordReply *reply = qobject_cast<QXmppPasswordReply *> (sender());

    if (!reply)
        return;

    reply->deleteLater();

    const QString jid = QString ("%1@%2").arg (d->saslServer->username(), d->domain);

    switch (reply->error())
    {
        case QXmppPasswordReply::NoError:
            d->jid = jid;
            info (QString ("Authentication succeeded for '%1' from %2").arg (d->jid, d->origin()));
            updateCounter ("incoming-client.auth.success");
            sendPacket (QXmppSaslSuccess());
            handleStart();
            break;

        case QXmppPasswordReply::AuthorizationError:
            warning (QString ("Authentication failed for '%1' from %2").arg (jid, d->origin()));
            updateCounter ("incoming-client.auth.not-authorized");
            sendPacket (QXmppSaslFailure ("not-authorized"));
            disconnectFromHost();
            break;

        case QXmppPasswordReply::TemporaryError:
            warning (QString ("Temporary authentication failure for '%1' from %2").arg (jid, d->origin()));
            updateCounter ("incoming-client.auth.temporary-auth-failure");
            sendPacket (QXmppSaslFailure ("temporary-auth-failure"));
            disconnectFromHost();
            break;
    }
}
void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv)
{
    const QString ns = nodeRecv.namespaceURI();

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

    if (ns == ns_tls && nodeRecv.tagName() == "starttls")
    {
        sendData("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
        socket()->flush();
        socket()->startServerEncryption();
        return;
    }
    else if (ns == ns_sasl)
    {
        if (nodeRecv.tagName() == "auth")
        {
            const QString mechanism = nodeRecv.attribute("mechanism");
            if (mechanism == "PLAIN")
            {
                QList<QByteArray> auth = QByteArray::fromBase64(nodeRecv.text().toAscii()).split('\0');
                if (auth.size() != 3)
                {
                    sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><incorrect-encoding/></failure>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordRequest request;
                request.setDomain(d->domain);
                request.setUsername(QString::fromUtf8(auth[1]));
                request.setPassword(QString::fromUtf8(auth[2]));
                if (!d->passwordChecker) {
                    // FIXME: what type of failure?
                    warning(QString("Cannot authenticate '%1', no password checker").arg(request.username()));
                    sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordReply *reply = d->passwordChecker->checkPassword(request);
                reply->setParent(this);
                reply->setProperty("__sasl_username", request.username());
                connect(reply, SIGNAL(finished()), this, SLOT(onPasswordReply()));
            }
            else if (mechanism == "DIGEST-MD5")
            {
                // generate nonce
                d->saslDigest.setNonce(QXmppSaslDigestMd5::generateNonce());
                d->saslDigest.setQop("auth");
                d->saslStep = 1;

                QMap<QByteArray, QByteArray> challenge;
                challenge["nonce"] = d->saslDigest.nonce();
                challenge["realm"] = d->domain.toUtf8();
                challenge["qop"] = d->saslDigest.qop();
                challenge["charset"] = "utf-8";
                challenge["algorithm"] = "md5-sess";

                const QByteArray data = QXmppSaslDigestMd5::serializeMessage(challenge).toBase64();
                sendData("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" + data +"</challenge>");
            }
            else
            {
                // unsupported method
                sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'></failure>");
                disconnectFromHost();
                return;
            }
        }
        else if (nodeRecv.tagName() == "response")
        {
            if (d->saslStep == 1)
            {
                const QByteArray raw = QByteArray::fromBase64(nodeRecv.text().toAscii());
                QMap<QByteArray, QByteArray> saslResponse = QXmppSaslDigestMd5::parseMessage(raw);

                // check credentials
                const QString username = QString::fromUtf8(saslResponse.value("username"));
                if (!d->passwordChecker) {
                    // FIXME: what type of failure?
                    warning(QString("Cannot authenticate '%1', no password checker").arg(username));
                    sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordRequest request;
                request.setUsername(username);
                request.setDomain(d->domain);

                QXmppPasswordReply *reply = d->passwordChecker->getDigest(request);
                reply->setParent(this);
                reply->setProperty("__sasl_raw", raw);
                connect(reply, SIGNAL(finished()), this, SLOT(onDigestReply()));
            }
            else if (d->saslStep == 2)
            {
                // authentication succeeded
                d->saslStep = 3;
                info(QString("Authentication succeeded for '%1'").arg(d->username));
                sendData("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
            }
        }
    }
    else if (ns == ns_client)
    {
        if (nodeRecv.tagName() == "iq")
        {
            const QString type = nodeRecv.attribute("type");
            if (QXmppBindIq::isBindIq(nodeRecv) && type == "set")
            {
                QXmppBindIq bindSet;
                bindSet.parse(nodeRecv);
                d->resource = bindSet.resource().trimmed();
                if (d->resource.isEmpty())
                    d->resource = generateStanzaHash();

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

                // bound
                emit connected();
                return;
            }
            else if (QXmppSessionIq::isSessionIq(nodeRecv) && type == "set")
            {
                QXmppSessionIq sessionSet;
                sessionSet.parse(nodeRecv);

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

        // check the sender is legitimate
        const QString from = nodeRecv.attribute("from");
        if (!from.isEmpty() && from != jid() && from != jidToBareJid(jid()))
        {
            warning(QString("Received a stanza from unexpected JID %1").arg(from));
            return;
        }

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

            // if the sender is empty, set it to the appropriate JID
            if (nodeFull.attribute("from").isEmpty())
            {
                if (nodeFull.tagName() == "presence" &&
                    (nodeFull.attribute("type") == "subscribe" ||
                    nodeFull.attribute("type") == "subscribed"))
                    nodeFull.setAttribute("from", jidToBareJid(jid()));
                else
                    nodeFull.setAttribute("from", 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);
        }
    }
}