⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qauthenticator.cpp

📁 奇趣公司比较新的qt/emd版本
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtNetwork module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file.  Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include <qauthenticator.h>#include <qauthenticator_p.h>#include <qdebug.h>#include <qhash.h>#include <qbytearray.h>#include <qcryptographichash.h>#include <qhttp.h>#include <qdatastream.h>#include <qendian.h>#include <qstring.h>#include <../3rdparty/des/des.cpp>static QByteArray qNtlmPhase1();static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);/*!  \class QAuthenticator  \brief The QAuthenticator class provides an authentication object.  \since 4.3  \reentrant  \ingroup io  \module network  The QAuthenticator class is usually used in the  \l{QHttp::}{authenticationRequired()} and  \l{QHttp::}{proxyAuthenticationRequired()} signals of QHttp and  QAbstractSocket. The class provides a way to pass back the required  authentication information to the socket when accessing services that  require authentication.  \sa QSslSocket*//*!  Constructs an empty authentication object*/QAuthenticator::QAuthenticator()    : d(0){}/*!  Destructs the object*/QAuthenticator::~QAuthenticator(){    if (d && !d->ref.deref())        delete d;}/*!    Constructs a copy of \a other.*/QAuthenticator::QAuthenticator(const QAuthenticator &other)    : d(other.d){    if (d)        d->ref.ref();}/*!    Assigns the contents of \a other to this authenticator.*/QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other){    if (d == other.d)        return *this;    detach();    d->user = other.d->user;    d->password = other.d->password;    return *this;}/*!    Returns true if this authenticator is identical to \a other; otherwise    returns false.*/bool QAuthenticator::operator==(const QAuthenticator &other) const{    if (d == other.d)        return true;    return d->user == other.d->user        && d->password == other.d->password        && d->realm == other.d->realm        && d->method == other.d->method;}/*!    \fn bool QAuthenticator::operator!=(const QAuthenticator &other) const    Returns true if this authenticator is different from \a other; otherwise    returns false.*//*!  returns the user used for authentication.*/QString QAuthenticator::user() const{    return d ? d->user : QString();}/*!  Sets the \a user used for authentication.*/void QAuthenticator::setUser(const QString &user){    detach();    d->user = user;}/*!  returns the password used for authentication.*/QString QAuthenticator::password() const{    return d ? d->password : QString();}/*!  Sets the \a password used for authentication.*/void QAuthenticator::setPassword(const QString &password){    detach();    d->password = password;}/*!  \internal*/void QAuthenticator::detach(){    if (!d) {        d = new QAuthenticatorPrivate;        d->ref.ref();        return;    }        if (d->ref.ref() != 1) {        QAuthenticatorPrivate *x = new QAuthenticatorPrivate(*d);        x = qAtomicSetPtr(&d, x);        if (!x->ref.deref())            delete x;    }    d->phase = QAuthenticatorPrivate::Start;}/*!  returns the realm requiring authentication.*/QString QAuthenticator::realm() const{    return d->realm;}/*!  returns true if the authenticator is null.*/bool QAuthenticator::isNull() const{    return !d;}QAuthenticatorPrivate::QAuthenticatorPrivate()    : ref(0)    , method(None)    , phase(Start)    , nonceCount(0){    cnonce = QCryptographicHash::hash(QByteArray::number(qrand(), 16) + QByteArray::number(qrand(), 16),                                      QCryptographicHash::Md5).toHex();    nonceCount = 0;}#ifndef QT_NO_HTTPvoid QAuthenticatorPrivate::parseHttpResponse(const QHttpResponseHeader &header, bool isProxy){    QList<QPair<QString, QString> > values = header.values();    const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";    method = None;    /*      Fun from the HTTP 1.1 specs, that we currently ignore:      User agents are advised to take special care in parsing the WWW-      Authenticate field value as it might contain more than one challenge,      or if more than one WWW-Authenticate header field is provided, the      contents of a challenge itself can contain a comma-separated list of      authentication parameters.    */    QString headerVal;    for (int i = 0; i < values.size(); ++i) {        const QPair<QString, QString> &current = values.at(i);        if (current.first.toLower() != QLatin1String(search))            continue;        QString str = current.second;        if (method < Basic && str.startsWith(QLatin1String("Basic"), Qt::CaseInsensitive)) {            method = Basic; headerVal = str.mid(6);        } else if (method < Ntlm && str.startsWith(QLatin1String("NTLM"), Qt::CaseInsensitive)) {            method = Ntlm;            headerVal = str.mid(5);        } else if (method < DigestMd5 && str.startsWith(QLatin1String("Digest"), Qt::CaseInsensitive)) {            method = DigestMd5;            headerVal = str.mid(7);        }    }    challenge = headerVal.trimmed().toLatin1();    QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);    switch(method) {    case Basic:        realm = QString::fromLatin1(options.value("realm"));        if (user.isEmpty())            phase = Done;        break;    case Ntlm:        // #### extract from header        realm = QString();        break;    case DigestMd5: {        realm = QString::fromLatin1(options.value("realm"));        if (options.value("stale").toLower() == "true")            phase = Start;        if (user.isEmpty())            phase = Done;        break;    }    default:        realm = QString();        challenge = QByteArray();    }}#endifQByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path){    QByteArray response;    const char *methodString = 0;    switch(method) {    case QAuthenticatorPrivate::None:        methodString = "";        phase = Done;        break;    case QAuthenticatorPrivate::Plain:        response = '\0' + user.toUtf8() + '\0' + password.toUtf8();        phase = Done;        break;    case QAuthenticatorPrivate::Basic:        methodString = "Basic ";        response = user.toLatin1() + ':' + password.toLatin1();        response = response.toBase64();        phase = Done;        break;    case QAuthenticatorPrivate::Login:        if (challenge.contains("VXNlciBOYW1lAA==")) {            response = user.toUtf8().toBase64();            phase = Phase2;        } else if (challenge.contains("UGFzc3dvcmQA")) {            response = password.toUtf8().toBase64();            phase = Done;        }        break;    case QAuthenticatorPrivate::CramMd5:        break;    case QAuthenticatorPrivate::DigestMd5:        methodString = "Digest ";        response = digestMd5Response(challenge, requestMethod, path);        phase = Done;        break;    case QAuthenticatorPrivate::Ntlm:        methodString = "NTLM ";        if (challenge.isEmpty()) {            response = qNtlmPhase1().toBase64();            if (user.isEmpty())                phase = Done;            else                phase = Phase2;        } else {            response = qNtlmPhase3(this, QByteArray::fromBase64(challenge)).toBase64();            phase = Done;        }                    break;    }    return QByteArray(methodString) + response;}// ---------------------------- Digest Md5 code ----------------------------------------QHash<QByteArray, QByteArray> QAuthenticatorPrivate::parseDigestAuthenticationChallenge(const QByteArray &challenge){    QHash<QByteArray, QByteArray> options;    // parse the challenge    const char *d = challenge.constData();    const char *end = d + challenge.length();    while (d < end) {        while (d < end && (*d == ' ' || *d == '\n' || *d == '\r'))            ++d;        const char *start = d;        while (d < end && *d != '=')            ++d;        QByteArray key = QByteArray(start, d - start);        ++d;        if (d >= end)            break;        bool quote = (*d == '"');        if (quote)             ++d;        if (d >= end)            break;        start = d;        QByteArray value;        while (d < end) {            bool backslash = false;            if (*d == '\\' && d < end - 1) {                ++d;                backslash = true;            }            if (!backslash) {                if (quote) {                    if (*d == '"')                        break;                } else {                    if (*d == ',')                        break;                }            }            value += *d;            ++d;        }        while (d < end && *d != ',')            ++d;        ++d;        options[key] = value;    }    QByteArray qop = options.value("qop");    if (!qop.isEmpty()) {        QList<QByteArray> qopoptions = qop.split(',');        if (!qopoptions.contains("auth"))            return QHash<QByteArray, QByteArray>();        // #### can't do auth-int currently//         if (qop.contains("auth-int"))//             qop = "auth-int";//         else if (qop.contains("auth"))//             qop = "auth";//         else//             qop = QByteArray();        options["qop"] = "auth";    }        return options;}/*  Digest MD5 implementation    Code taken from RFC 2617  Currently we don't support the full SASL authentication mechanism (which includes cyphers)*//* calculate request-digest/response-digest as per HTTP Digest spec */static QByteArray digestMd5Response(    const QByteArray &alg,    const QByteArray &userName,    const QByteArray &realm,    const QByteArray &password,    const QByteArray &nonce,       /* nonce from server */    const QByteArray &nonceCount,  /* 8 hex digits */    const QByteArray &cNonce,      /* client nonce */    const QByteArray &qop,         /* qop-value: "", "auth", "auth-int" */    const QByteArray &method,      /* method from the request */    const QByteArray &digestUri,   /* requested URL */    const QByteArray &hEntity       /* H(entity body) if qop="auth-int" */    ){    QCryptographicHash hash(QCryptographicHash::Md5);    hash.addData(userName);    hash.addData(":", 1);    hash.addData(realm);    hash.addData(":", 1);    hash.addData(password);    QByteArray ha1 = hash.result();    if (alg.toLower() == "md5-sess") {        hash.reset();        hash.addData(ha1);        hash.addData(":", 1);        hash.addData(nonce);        hash.addData(":", 1);        hash.addData(cNonce);        ha1 = hash.result();    };    ha1 = ha1.toHex();          // calculate H(A2)    hash.reset();    hash.addData(method);    hash.addData(":", 1);    hash.addData(digestUri);    if (qop.toLower() == "auth-int") {        hash.addData(":", 1);        hash.addData(hEntity);    }    QByteArray ha2hex = hash.result().toHex();    // calculate response    hash.reset();    hash.addData(ha1);    hash.addData(":", 1);    hash.addData(nonce);    hash.addData(":", 1);    if (!qop.isNull()) {        hash.addData(nonceCount);        hash.addData(":", 1);        hash.addData(cNonce);        hash.addData(":", 1);        hash.addData(qop);        hash.addData(":", 1);    }    hash.addData(ha2hex);    return hash.result().toHex();}QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path){    QHash<QByteArray,QByteArray> options = parseDigestAuthenticationChallenge(challenge);    ++nonceCount;    QByteArray nonceCountString = QByteArray::number(nonceCount, 16);    while (nonceCountString.length() < 8)        nonceCountString.prepend('0');        QByteArray nonce = options.value("nonce");    QByteArray opaque = options.value("opaque");    QByteArray qop = options.value("qop");        qDebug() << "calculating digest: method=" << method << "path=" << path;    QByteArray response = ::digestMd5Response(options.value("algorithm"), user.toLatin1(),                                              realm.toLatin1(), password.toLatin1(),                                              nonce, nonceCountString,                                              cnonce, qop, method,                                              path, QByteArray());    QByteArray credentials;    credentials += "username=\"" + user.toLatin1() + "\", ";    credentials += "realm=\"" + realm.toLatin1() + "\", ";    credentials += "nonce=\"" + nonce + "\", ";    credentials += "uri=\"" + path + "\", ";    if (!opaque.isEmpty())        credentials += "opaque=\"" + opaque + "\", ";    credentials += "response=\"" + response + "\"";    if (!options.value("algorithm").isEmpty())        credentials += ", algorithm=" + options.value("algorithm");    if (!options.value("qop").isEmpty()) {        credentials += ", qop=" + qop + ", ";        credentials += "nc=" + nonceCountString + ", ";        credentials += "cnonce=\"" + cnonce + "\"";    }    return credentials;}// ---------------------------- Digest Md5 code ----------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -