25 #include <QCryptographicHash> 48 static QHash<QString,TorcHTTPServerNonce> nonces;
49 static QByteArray token = QUuid::createUuid().toByteArray();
50 static quint64 nonceCounter = 0;
51 static QMutex lock(QMutex::Recursive);
53 QDateTime current = QDateTime::currentDateTime();
59 QByteArray tag = QByteArray::number(current.toMSecsSinceEpoch()) + Request.
GetCache().toLocal8Bit() + token;
63 QMutexLocker locker(&lock);
66 QByteArray hash(tag + QByteArray::number(++nonceCounter));
67 nonce = QString(QCryptographicHash::hash(hash, QCryptographicHash::Md5).toHex());
68 }
while (nonces.contains(nonce));
73 nonces.insert(nonce, nonceobj);
76 QString auth = QStringLiteral(
"Digest realm=\"%1\", qop=\"auth\", algorithm=MD5, nonce=\"%2\", opaque=\"%3\"%4")
87 QMutexLocker locker(&lock);
88 QMutableHashIterator<QString,TorcHTTPServerNonce> it(nonces);
92 if (it.value().IsOutOfDate(current))
98 QStringList authentication = Request.
Headers().value(QStringLiteral(
"Authorization")).mid(6).trimmed().split(
',', QString::SkipEmptyParts);
101 QHash<QString,QString> params;
102 foreach (
const QString &auth, authentication)
105 QString key = auth.section(
'=', 0, 0).trimmed().toLower();
106 QString value = auth.section(
'=', 1).trimmed();
107 value.remove(QStringLiteral(
"\""));
108 params.insert(key, value);
112 if (params.size() < 10)
114 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Digest response received too few parameters"));
119 if (!params.contains(QStringLiteral(
"username")) || !params.contains(QStringLiteral(
"realm")) || !params.contains(QStringLiteral(
"nonce")) ||
120 !params.contains(QStringLiteral(
"uri")) || !params.contains(QStringLiteral(
"qop")) || !params.contains(QStringLiteral(
"algorithm")) ||
121 !params.contains(QStringLiteral(
"nc")) || !params.contains(QStringLiteral(
"cnonce")) || !params.contains(QStringLiteral(
"response")) ||
122 !params.contains(QStringLiteral(
"opaque")))
124 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Did not receive expected paramaters"));
131 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Expected '%1' username, got '%2'").arg(
TorcUser::GetName(), params.value(QStringLiteral(
"username"))));
140 QString URI = Request.
GetUrl();
141 QString noncestr = params.value(QStringLiteral(
"nonce"));
142 QString ncstr = params.value(QStringLiteral(
"nc"));
145 QByteArray hash2 = QCryptographicHash::hash(second.toLatin1(), QCryptographicHash::Md5).toHex();
146 QString third = QStringLiteral(
"%1:%2:%3:%4:%5:%6").arg(QString(hash1), noncestr, ncstr, params.value(QStringLiteral(
"cnonce")), QStringLiteral(
"auth"), QString(hash2));
147 QByteArray hash3 = QCryptographicHash::hash(third.toLatin1(), QCryptographicHash::Md5).toHex();
149 if (hash3 != params.value(QStringLiteral(
"response")))
151 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"Digest hash failed"));
157 if (URI != params.value(QStringLiteral(
"uri")))
159 LOG(VB_GENERAL, LOG_WARNING, QStringLiteral(
"URI mismatch between HTTP request and WWW-Authenticate header"));
168 QMutexLocker locker(&lock);
171 QHash<QString,TorcHTTPServerNonce>::const_iterator it = nonces.constFind(noncestr);
172 if (it == nonces.constEnd())
174 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Failed to find nonce '%1'").arg(noncestr));
183 if (it.value().GetOpaque() != params.value(QStringLiteral(
"opaque")))
186 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Failed to match opaque"));
192 quint64 nc = ncstr.toInt(&ok, 16);
195 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Failed to parse nonce count"));
200 if (!nonce.
UseOnce(nc, current))
203 LOG(VB_NETWORK, LOG_DEBUG, QStringLiteral(
"Nonce count use failed"));
218 m_lifetimeInSeconds(0),
219 m_lifetimeInRequests(0)
221 LOG(VB_GENERAL, LOG_ERR, QStringLiteral(
"Invalid TorcHTTPServerNonce"));
226 m_opaque(QCryptographicHash::hash(QByteArray::number(qrand()), QCryptographicHash::Md5).toHex()),
227 m_startMs(Time.time().msecsSinceStartOfDay()),
254 if (m_useCount > 0xffffffff)
261 if (m_useCount <= ClientCount)
264 m_useCount = ClientCount;
267 if (m_lifetimeInRequests > 0 && m_useCount >= m_lifetimeInRequests)
274 m_startTime = Current;
288 if (Current > m_startTime.addSecs(m_lifetimeInSeconds))
A class to encapsulate an incoming HTTP request.
HTTPRequestType GetHTTPRequestType(void) const
static QString RequestTypeToString(HTTPRequestType Type)
QString GetCache(void) const
bool IsOutOfDate(const QDateTime &Current)
static void ProcessDigestAuth(TorcHTTPRequest &Request, bool Check=false)
A server nonce for Digest Access Authentication.
HTTPAuthorisation IsAuthorised(void) const
QString GetOpaque(void) const
#define DEFAULT_NONCE_LIFETIME_REQUESTS
const QMap< QString, QString > & Headers(void) const
static QByteArray GetCredentials(void)
#define DEFAULT_NONCE_LIFETIME_SECONDS
static QString GetName(void)
void SetResponseHeader(const QString &Header, const QString &Value)
#define LOG(_MASK_, _LEVEL_, _STRING_)
QString GetUrl(void) const
bool UseOnce(quint64 ClientCount, const QDateTime &Current)
void Authorise(HTTPAuthorisation Authorisation)