Add QLocalAuth class.

This commit is contained in:
Nathan Osman
2016-10-15 20:50:11 -07:00
parent 482a67733f
commit cf3932529a
7 changed files with 314 additions and 0 deletions

View File

@@ -0,0 +1 @@
#include "qlocalauth.h"

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2015 Nathan Osman
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef QHTTPENGINE_QLOCALAUTH_H
#define QHTTPENGINE_QLOCALAUTH_H
#include <QVariantMap>
#include <QHttpEngine/QHttpMiddleware>
#include "qhttpengine_global.h"
class QHTTPENGINE_EXPORT QLocalAuthPrivate;
/**
* @brief Middleware for local file-based authentication
*
* This class is intended for authenticating applications running under the
* same user account as the server. QLocalFile is used to expose a token to
* connecting applications. The client passes the token in a special header
* and the request is permitted.
*
* The file consists of a JSON object in the following format:
*
* @code
* {
* "token": "{8a34d0f0-29d0-4e54-b3aa-ce8f8ad65527}"
* }
* @endcode
*
* Additional data can be added to the object using the setData() method.
*/
class QHTTPENGINE_EXPORT QLocalAuth : public QHttpMiddleware
{
Q_OBJECT
public:
/**
* @brief Initialize local authentication
*
* To determine whether the local file was created successfully, call the
* exists() method.
*/
explicit QLocalAuth(QObject *parent = Q_NULLPTR);
/**
* @brief Determine whether the file exists
*/
bool exists() const;
/**
* @brief Retrieve the name of the file used for storing the token
*/
QString filename() const;
/**
* @brief Set additional data to include with the token
*/
void setData(const QVariantMap &data);
/**
* @brief Set the name of the custom header used for confirming the token
*
* The default value is "X-Auth-Token".
*/
void setHeaderName(const QByteArray &name);
/**
* @brief Process the request
*
* If the token supplied by the client matches, the request is allowed.
* Otherwise, an HTTP 403 error is returned.
*/
virtual bool process(QHttpSocket *socket);
private:
QLocalAuthPrivate *const d;
};
#endif // QHTTPENGINE_QLOCALAUTH_H

View File

@@ -12,6 +12,7 @@ set(SRC
qhttpserver.cpp
qhttpsocket.cpp
qiodevicecopier.cpp
qlocalauth.cpp
qlocalfile.cpp
qobjecthandler.cpp
)

84
src/qlocalauth.cpp Normal file
View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2015 Nathan Osman
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <QJsonDocument>
#include <QJsonObject>
#include <QUuid>
#include <QHttpEngine/QHttpSocket>
#include <QHttpEngine/QLocalAuth>
#include "qlocalauth_p.h"
QLocalAuthPrivate::QLocalAuthPrivate(QObject *parent)
: QObject(parent),
tokenHeader("X-Auth-Token"),
token(QUuid::createUuid().toString())
{
updateFile();
}
void QLocalAuthPrivate::updateFile()
{
if (file.open()) {
file.write(QJsonDocument(QJsonObject::fromVariantMap(data)).toJson());
file.close();
}
}
QLocalAuth::QLocalAuth(QObject *parent)
: QHttpMiddleware(parent),
d(new QLocalAuthPrivate(this))
{
}
bool QLocalAuth::exists() const
{
return d->file.exists();
}
QString QLocalAuth::filename() const
{
return d->file.fileName();
}
void QLocalAuth::setData(const QVariantMap &data)
{
d->data = data;
d->data.insert("token", d->token);
d->updateFile();
}
void QLocalAuth::setHeaderName(const QByteArray &name)
{
d->tokenHeader = name;
}
bool QLocalAuth::process(QHttpSocket *socket)
{
if (socket->headers().value(d->tokenHeader) != d->token) {
socket->writeError(QHttpSocket::Forbidden);
return false;
}
return true;
}

47
src/qlocalauth_p.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 2015 Nathan Osman
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef QHTTPENGINE_QLOCALAUTHPRIVATE_H
#define QHTTPENGINE_QLOCALAUTHPRIVATE_H
#include <QObject>
#include <QVariantMap>
#include <QHttpEngine/QLocalFile>
class QLocalAuthPrivate : public QObject
{
Q_OBJECT
public:
explicit QLocalAuthPrivate(QObject *parent);
void updateFile();
QLocalFile file;
QVariantMap data;
QByteArray tokenHeader;
QString token;
};
#endif // QHTTPENGINE_QLOCALAUTHPRIVATE_H

View File

@@ -13,6 +13,7 @@ set(TESTS
TestQHttpSocket
TestQIByteArray
TestQIODeviceCopier
TestQLocalAuth
TestQLocalFile
TestQObjectHandler
)

79
tests/TestQLocalAuth.cpp Normal file
View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2015 Nathan Osman
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTest>
#include <QVariantMap>
#include <QHttpEngine/QHttpSocket>
#include <QHttpEngine/QLocalAuth>
#include "common/qsimplehttpclient.h"
#include "common/qsocketpair.h"
const QByteArray HeaderName = "X-Test";
const QByteArray CustomName = "Name";
const QByteArray CustomData = "Data";
class TestQLocalAuth : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testAuth();
};
void TestQLocalAuth::testAuth()
{
QSocketPair pair;
QTRY_VERIFY(pair.isConnected());
QSimpleHttpClient client(pair.client());
QHttpSocket socket(pair.server(), &pair);
QLocalAuth localAuth;
localAuth.setData(QVariantMap{
{CustomName, CustomData}
});
localAuth.setHeaderName(HeaderName);
QVERIFY(localAuth.exists());
QFile file(localAuth.filename());
QVERIFY(file.open(QIODevice::ReadOnly));
QVariantMap data = QJsonDocument::fromJson(file.readAll()).object().toVariantMap();
QVERIFY(data.contains("token"));
QCOMPARE(data.value(CustomName).toByteArray(), CustomData);
client.sendHeaders("GET", "/", QHttpSocket::HeaderMap{
{HeaderName, data.value("token").toByteArray()}
});
QTRY_VERIFY(socket.isHeadersParsed());
QVERIFY(localAuth.process(&socket));
}
QTEST_MAIN(TestQLocalAuth)
#include "TestQLocalAuth.moc"