add authorization structure to core methods

This commit is contained in:
Evgenii Alekseev 2017-03-01 23:12:17 +03:00
parent dc46039a53
commit de3d7c10c3
11 changed files with 539 additions and 71 deletions

View File

@ -1,10 +1,12 @@
set (SUBPROJECT "queued") set (SUBPROJECT "queued")
message (STATUS "Subproject ${SUBPROJECT}") message (STATUS "Subproject ${SUBPROJECT}")
configure_file ("QueuedConfig.h.in" "${CMAKE_BINARY_DIR}/QueuedConfig.h")
add_subdirectory ("src") add_subdirectory ("src")
# headers # headers
install (DIRECTORY "include/${SUBPROJECT}" DESTINATION "${INCLUDE_INSTALL_DIR}") install (DIRECTORY "include/${SUBPROJECT}" DESTINATION "${INCLUDE_INSTALL_DIR}")
install (FILES "${CMAKE_BINARY_DIR}/config.h" DESTINATION "${INCLUDE_INSTALL_DIR}/${SUBPROJECT}") install (FILES "${CMAKE_BINARY_DIR}/QueuedConfig.h" DESTINATION "${INCLUDE_INSTALL_DIR}/${SUBPROJECT}")
# documentation # documentation
if (BUILD_DOCS) if (BUILD_DOCS)
include ("docs.cmake") include ("docs.cmake")

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2016 Evgeniy Alekseev
*
* 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.
*/
/**
* @file QueuedConfig.h
* Source code of queued library
* @author Evgeniy Alekseev
* @copyright GPLv3
* @bug https://github.com/arcan1s/queued/issues
*/
#ifndef QUEUEDCONFIG_H
#define QUEUEDCONFIG_H
/**
* @defgroup QueuedConfig
* @brief Queued configuration constants
*/
namespace QueuedConfig
{
// dbus configuration
/**
* @brief DBus service name for library and application
* @remark required by Qt macro
*/
#define DBUS_SERVICE_NAME "org.quadro.core"
/**
* @ingroup QueuedConfig
* @brief DBus service name for library and application
*/
const char DBUS_SERVICE[] = DBUS_SERVICE_NAME;
/**
* @ingroup QueuedConfig
* @brief DBus object path for library
*/
const char DBUS_OBJECT_PATH[] = "/queued";
// path configuration
// common paths
/**
* @ingroup QueuedConfig
* @brief installation directory for executables
*/
const char BIN_INSTALL_DIR[] = "@BIN_INSTALL_DIR@";
/**
* @ingroup QueuedConfig
* @brief installation directory for data
*/
const char DATA_INSTALL_DIR[] = "@DATA_INSTALL_DIR@";
/**
* @ingroup QueuedConfig
* @brief installation directory for headers
*/
const char INCLUDE_INSTALL_DIR[] = "@INCLUDE_INSTALL_DIR@";
/**
* @ingroup QueuedConfig
* @brief installation directory for libraries
*/
const char LIB_INSTALL_DIR[] = "@LIB_INSTALL_DIR@";
/**
* @ingroup QueuedConfig
* @brief the same as CMAKE_INSTALL_PREFIX
*/
const char ROOT_INSTALL_DIR[] = "@CMAKE_INSTALL_PREFIX@";
// plugin interfaces
/**
* @brief plugin interface name
* @remark required by Qt macro
*/
#define PLUGIN_INTERFACE_NAME \
"queued.plugin/@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@"
/**
* @ingroup QueuedConfig
* @brief plugin interface name
*/
const char PLUGIN_INTERFACE[] = PLUGIN_INTERFACE_NAME;
}
#endif /* QUEUEDCONFIG_H */

View File

@ -28,6 +28,7 @@
#include "QueuedEnums.h" #include "QueuedEnums.h"
#include "QueuedLimits.h" #include "QueuedLimits.h"
#include "QueuedUserManager.h"
class QueuedAdvancedSettings; class QueuedAdvancedSettings;
@ -36,7 +37,6 @@ class QueuedProcessManager;
class QueuedReportManager; class QueuedReportManager;
class QueuedSettings; class QueuedSettings;
class QueuedTokenManager; class QueuedTokenManager;
class QueuedUserManager;
/** /**
* @brief aggregator of queued classes * @brief aggregator of queued classes
@ -69,11 +69,14 @@ public:
* task owner user ID * task owner user ID
* @param _limits * @param _limits
* task defined limits * task defined limits
* @param _auth
* user auth structure
* @return true on successfully addition * @return true on successfully addition
*/ */
bool addTask(const QString &_command, const QStringList &_arguments, bool addTask(const QString &_command, const QStringList &_arguments,
const QString &_workingDirectory, const unsigned int _nice, const QString &_workingDirectory, const unsigned int _nice,
const long long _userId, const QueuedLimits::Limits &_limits); const long long _userId, const QueuedLimits::Limits &_limits,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief add new user * @brief add new user
* @param _name * @param _name
@ -86,42 +89,65 @@ public:
* user permissions * user permissions
* @param _limits * @param _limits
* user limits * user limits
* @param _auth
* user auth structure
* @return true on successfully addition * @return true on successfully addition
*/ */
bool addUser(const QString &_name, const QString &_email, bool addUser(const QString &_name, const QString &_email,
const QString &_password, const unsigned int _permissions, const QString &_password, const unsigned int _permissions,
const QueuedLimits::Limits &_limits); const QueuedLimits::Limits &_limits,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/**
* @brief authorize and create new token for user
* @param _name
* user name
* @param _password
* user password
* @return authorization structure. Token field will be empty in case if no
* authorization occurs
*/
QueuedUserManager::QueuedUserAuthorization
authorization(const QString &_name, const QString &_password);
/** /**
* @brief edit advanced settings * @brief edit advanced settings
* @param _key * @param _key
* advanced settings key * advanced settings key
* @param _value * @param _value
* advanced settings value * advanced settings value
* @param _auth
* user auth structure
* @return true on successful option edition * @return true on successful option edition
*/ */
bool editOption(const QString &_key, const QVariant &_value); bool editOption(const QString &_key, const QVariant &_value,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief edit task * @brief edit task
* @param _id * @param _id
* task ID to edit * task ID to edit
* @param _taskData * @param _taskData
* task data to edit * task data to edit
* @param _auth
* user auth structure
* @remark _taskData should contain only fields defined in schema, any other * @remark _taskData should contain only fields defined in schema, any other
* fields will be ignored. No need to pass all properties here * fields will be ignored. No need to pass all properties here
* @return true on successful task edition * @return true on successful task edition
*/ */
bool editTask(const long long _id, const QVariantHash &_taskData); bool editTask(const long long _id, const QVariantHash &_taskData,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief edit user * @brief edit user
* @param _id * @param _id
* user ID to edit * user ID to edit
* @param _userData * @param _userData
* user data to edit * user data to edit
* @param _auth
* user auth structure
* @remark _userData should contain only fields defined in schema, any other * @remark _userData should contain only fields defined in schema, any other
* fields will be ignored. No need to pass all properties here * fields will be ignored. No need to pass all properties here
* @return true on successful user edition * @return true on successful user edition
*/ */
bool editUser(const long long _id, const QVariantHash &_userData); bool editUser(const long long _id, const QVariantHash &_userData,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/** /**
* @brief edit user permissions * @brief edit user permissions
* @param _id * @param _id
@ -130,11 +156,35 @@ public:
* permission to add or remove * permission to add or remove
* @param _add * @param _add
* indicates whether it should be added or removed * indicates whether it should be added or removed
* @param _auth
* user auth structure
* @return true on successful user permission edition * @return true on successful user permission edition
*/ */
bool editUserPermission(const long long _id, bool
editUserPermission(const long long _id,
const QueuedEnums::Permission &_permission, const QueuedEnums::Permission &_permission,
const bool _add); const bool _add,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/**
* @brief force start task
* @param _id
* task ID
* @param _auth
* user auth structure
* @return true on successful task start
*/
bool startTask(const long long _id,
const QueuedUserManager::QueuedUserAuthorization &_auth);
/**
* @brief force stop task
* @param _id
* task ID
* @param _auth
* user auth structure
* @return true on successful task stop
*/
bool stopTask(const long long _id,
const QueuedUserManager::QueuedUserAuthorization &_auth);
// control methods // control methods
/** /**
* @brief deinit subclasses * @brief deinit subclasses
@ -207,6 +257,16 @@ private:
* @brief connection list * @brief connection list
*/ */
QList<QMetaObject::Connection> m_connections; QList<QMetaObject::Connection> m_connections;
/**
* @brief drop non-admin fields from database payload
* @param _table
* table name
* @param _payload
* initial database payload
* @return payload with dropped keys
*/
QVariantHash dropAdminFields(const QString &_table,
const QVariantHash &_payload);
/** /**
* @brief init processes * @brief init processes
*/ */

View File

@ -64,11 +64,14 @@ const char USERS_TABLE[] = "users";
* description to create column * description to create column
* @var type * @var type
* Qt type of column for cast * Qt type of column for cast
* @var adminField
* is admin permissions required to edit or not
*/ */
typedef struct { typedef struct {
QString name; QString name;
QString sqlDescription; QString sqlDescription;
QVariant::Type type; QVariant::Type type;
bool adminField;
} QueuedDBField; } QueuedDBField;
/** /**
* @ingroup QueuedDB * @ingroup QueuedDB
@ -83,39 +86,46 @@ typedef QHash<QString, QHash<QString, QueuedDBField>> QueuedDBSchema;
const QueuedDBSchema DBSchema = { const QueuedDBSchema DBSchema = {
{SETTINGS_TABLE, {SETTINGS_TABLE,
{{"_id", {{"_id",
{"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong,
{"key", {"key", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String}}, true}},
{"value", {"value", "TEXT", QVariant::String}}}}, {"key",
{"key", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String, true}},
{"value", {"value", "TEXT", QVariant::String, true}}}},
{TASKS_TABLE, {TASKS_TABLE,
{{"_id", {{"_id",
{"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong,
{"user", {"user", "INT NOT NULL DEFAULT 0", QVariant::LongLong}}, true}},
{"command", {"command", "TEXT", QVariant::String}}, {"user", {"user", "INT NOT NULL DEFAULT 0", QVariant::LongLong, false}},
{"commandArguments", {"commandArguments", "TEXT", QVariant::String}}, {"command", {"command", "TEXT", QVariant::String, false}},
{"workDirectory", {"workDirectory", "TEXT", QVariant::String}}, {"commandArguments",
{"nice", {"nice", "INT", QVariant::UInt}}, {"commandArguments", "TEXT", QVariant::String, false}},
{"uid", {"uid", "INT", QVariant::UInt}}, {"workDirectory", {"workDirectory", "TEXT", QVariant::String, false}},
{"gid", {"gid", "INT", QVariant::UInt}}, {"nice", {"nice", "INT", QVariant::UInt, false}},
{"state", {"state", "INT", QVariant::UInt}}, {"uid", {"uid", "INT", QVariant::UInt, false}},
{"limits", {"limits", "TEXT", QVariant::String}}, {"gid", {"gid", "INT", QVariant::UInt, false}},
{"startTime", {"startTime", "INT", QVariant::LongLong}}, {"state", {"state", "INT", QVariant::UInt, true}},
{"endTime", {"endTime", "INT", QVariant::LongLong}}}}, {"limits", {"limits", "TEXT", QVariant::String, false}},
{"startTime", {"startTime", "INT", QVariant::LongLong, true}},
{"endTime", {"endTime", "INT", QVariant::LongLong, true}}}},
{TOKENS_TABLE, {TOKENS_TABLE,
{{"_id", {{"_id",
{"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong,
true}},
{"token", {"token",
{"token", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String}}, {"token", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String, true}},
{"validUntil", {"validUntil",
{"validUntil", "TEXT NOT NULL DEFAULT '0'", QVariant::String}}}}, {"validUntil", "TEXT NOT NULL DEFAULT '0'", QVariant::String, true}}}},
{USERS_TABLE, {USERS_TABLE,
{{"_id", {{"_id",
{"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong,
{"name", {"name", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String}}, true}},
{"password", {"password", "TEXT", QVariant::String}}, {"name",
{"email", {"email", "TEXT", QVariant::String}}, {"name", "TEXT NOT NULL UNIQUE DEFAULT '0'", QVariant::String, true}},
{"lastLogin", {"lastLogin", "TEXT", QVariant::String}}, {"password", {"password", "TEXT", QVariant::String, false}},
{"limits", {"limits", "TEXT", QVariant::String}}, {"email", {"email", "TEXT", QVariant::String, false}},
{"permissions", {"permissions", "INT", QVariant::UInt}}}}}; {"lastLogin", {"lastLogin", "TEXT", QVariant::String, true}},
{"limits", {"limits", "TEXT", QVariant::String, true}},
{"permissions", {"permissions", "INT", QVariant::UInt, true}}}}};
}; };
#endif /* QUEUEDDATABASESCHEMA_H */ #endif /* QUEUEDDATABASESCHEMA_H */

View File

@ -63,8 +63,6 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(LimitTypes)
* administrative permissions * administrative permissions
* @var Permissions::JobOwner * @var Permissions::JobOwner
* owner job related permissions * owner job related permissions
* @var Permissions::JobGlobal
* other users job control
* @var Permissions::User * @var Permissions::User
* user related permissions * user related permissions
* @var Permissions::Web * @var Permissions::Web
@ -76,10 +74,9 @@ enum class Permission {
SuperAdmin = 1 << 0, SuperAdmin = 1 << 0,
Admin = 1 << 1, Admin = 1 << 1,
JobOwner = 1 << 2, JobOwner = 1 << 2,
JobGlobal = 1 << 3, User = 1 << 3,
User = 1 << 4, Web = 1 << 4,
Web = 1 << 5, Reports = 1 << 5
Reports = 1 << 6
}; };
Q_DECLARE_FLAGS(Permissions, Permission) Q_DECLARE_FLAGS(Permissions, Permission)
Q_DECLARE_OPERATORS_FOR_FLAGS(Permissions) Q_DECLARE_OPERATORS_FOR_FLAGS(Permissions)

View File

@ -98,6 +98,28 @@ struct Limits {
storage = limits.at(4).toLongLong(); storage = limits.at(4).toLongLong();
valid = true; valid = true;
}; };
/**
* @brief structure constructor from fields
* @param _cpuLimit
* limit by CPU cores
* @param _gpuLimit
* limit by GPU cores
* @param _memory
* limit by memory
* @param _gpumemory
* limit by GPU memory
* @param _storage
* limit by storage
*/
Limits(const long long _cpuLimit, const long long _gpuLimit,
const long long _memoryLimit, const long long _gpumemoryLimit,
const long long _storage)
: cpu(_cpuLimit)
, gpu(_gpuLimit)
, memory(_memoryLimit)
, gpumemory(_gpumemoryLimit)
, storage(_storage)
, valid(true){};
}; };
/** /**
* @ingroup QueuedLimits * @ingroup QueuedLimits
@ -108,7 +130,7 @@ struct Limits {
* conversion status * conversion status
* @return converted integer * @return converted integer
*/ */
long long convertMemory(QString _value, bool *_status); long long convertMemory(QString _value, bool *_status = nullptr);
/** /**
* @ingroup QueuedLimits * @ingroup QueuedLimits
* @brief compare two limits * @brief compare two limits

View File

@ -52,7 +52,7 @@ public:
* token ID * token ID
* @return true if token is valid otherwise return false * @return true if token is valid otherwise return false
*/ */
bool isTokenValid(const QString &_token); bool isTokenValid(const QString &_token) const;
/** /**
* @brief upload tokens from database * @brief upload tokens from database
* @param _value * @param _value
@ -66,6 +66,14 @@ public:
* @return new generated token * @return new generated token
*/ */
QString registerToken(const QDateTime _validUntil); QString registerToken(const QDateTime _validUntil);
/**
* @brief token expiration
* @param _token
* token ID
* @return token expiration if token found, otherwise return default
* QDateTime constructor
*/
QDateTime tokenExpiration(const QString &_token) const;
public slots: public slots:
/** /**

View File

@ -55,7 +55,7 @@ public:
typedef struct { typedef struct {
QString token; QString token;
QString user; QString user;
} UserAuthorization; } QueuedUserAuthorization;
/** /**
* @brief QueuedUserManager class constructor * @brief QueuedUserManager class constructor
@ -86,6 +86,16 @@ public:
*/ */
QueuedUser *add(const QueuedUser::QueuedUserDefinitions &_definitions, QueuedUser *add(const QueuedUser::QueuedUserDefinitions &_definitions,
const long long _id); const long long _id);
/**
* @brief build user auth structure
* @param _user
* user name
* @param _token
* user token
* @return generated structure
*/
static QueuedUserAuthorization auth(const QString &_user,
const QString &_token);
/** /**
* @brief authorize user * @brief authorize user
* @param _user * @param _user
@ -103,8 +113,17 @@ public:
* service to authorize * service to authorize
* @return true if user allowed to do it otherwise return false * @return true if user allowed to do it otherwise return false
*/ */
bool authorize(const UserAuthorization &_auth, bool authorize(const QueuedUserAuthorization &_auth,
const QueuedEnums::Permission _service); const QueuedEnums::Permission _service);
/**
* @brief check token expiration
* @param _token
* token string
* @param _valid
* optional output parameter, will set to true if token is valid
* @return token expiration or default constructor
*/
QDateTime checkToken(const QString &_token, bool *_valid = nullptr) const;
/** /**
* @brief get UID and GID from user ID * @brief get UID and GID from user ID
* @param _id * @param _id

View File

@ -22,6 +22,8 @@
#include "queued/Queued.h" #include "queued/Queued.h"
#include <queued/Queued.h>
#include <queued/QueuedDatabaseSchema.h>
#include "queued/QueuedDatabaseSchema.h" #include "queued/QueuedDatabaseSchema.h"
@ -53,14 +55,38 @@ QueuedCore::~QueuedCore()
/** /**
* @addTask * @addTask
*/ */
bool QueuedCore::addTask(const QString &_command, const QStringList &_arguments, bool QueuedCore::addTask(
const QString &_workingDirectory, const QString &_command, const QStringList &_arguments,
const unsigned int _nice, const long long _userId, const QString &_workingDirectory, const unsigned int _nice,
const QueuedLimits::Limits &_limits) const long long _userId, const QueuedLimits::Limits &_limits,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Add task" << _command << "with arguments" << _arguments qCDebug(LOG_LIB) << "Add task" << _command << "with arguments" << _arguments
<< "from user" << _userId; << "from user" << _userId;
long long userAuthId = m_users->user(_auth.user)->index();
long long actualUserId = (_userId == -1) ? userAuthId : _userId;
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
bool isUser = m_users->authorize(_auth, QueuedEnums::Permission::JobOwner);
if (userAuthId == actualUserId) {
// it means that user places task as own one
if (!isUser) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to add task";
return false;
}
} else {
// user tries to place task as another one
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to add task";
return false;
}
}
// add to database
auto ids = m_users->ids(_userId); auto ids = m_users->ids(_userId);
auto taskLimits = QueuedLimits::minimalLimits( auto taskLimits = QueuedLimits::minimalLimits(
_limits, m_users->user(_userId)->limits(), _limits, m_users->user(_userId)->limits(),
@ -80,6 +106,7 @@ bool QueuedCore::addTask(const QString &_command, const QStringList &_arguments,
return false; return false;
} }
// add to child object
m_processes->add(properties, id); m_processes->add(properties, id);
return true; return true;
} }
@ -88,14 +115,22 @@ bool QueuedCore::addTask(const QString &_command, const QStringList &_arguments,
/** /**
* @fn addUser * @fn addUser
*/ */
bool QueuedCore::addUser(const QString &_name, const QString &_email, bool QueuedCore::addUser(
const QString &_password, const QString &_name, const QString &_email, const QString &_password,
const unsigned int _permissions, const unsigned int _permissions, const QueuedLimits::Limits &_limits,
const QueuedLimits::Limits &_limits) const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Add user" << _name << "with email" << _email qCDebug(LOG_LIB) << "Add user" << _name << "with email" << _email
<< "and permissions" << _permissions; << "and permissions" << _permissions;
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user << "not allowed to add user";
return false;
}
// add to dababase
QVariantHash properties QVariantHash properties
= {{"name", _name}, = {{"name", _name},
{"password", QueuedUser::hashFromPassword(_password)}, {"password", QueuedUser::hashFromPassword(_password)},
@ -108,22 +143,52 @@ bool QueuedCore::addUser(const QString &_name, const QString &_email,
return false; return false;
} }
// add to child object
m_users->add(properties, id); m_users->add(properties, id);
return true; return true;
} }
QueuedUserManager::QueuedUserAuthorization
QueuedCore::authorization(const QString &_name, const QString &_password)
{
qCDebug(LOG_LIB) << "Authorize user" << _name;
QString token = m_users->authorize(_name, _password);
QueuedUserManager::QueuedUserAuthorization auth;
auth.user = _name;
if (!token.isEmpty()) {
QVariantHash payload = {
{"token", token},
{"validUntil", m_users->checkToken(token).toString(Qt::ISODate)}};
m_database->add(QueuedDB::TOKENS_TABLE, payload);
}
return auth;
}
/** /**
* @fn editOption * @fn editOption
*/ */
bool QueuedCore::editOption(const QString &_key, const QVariant &_value) bool QueuedCore::editOption(
const QString &_key, const QVariant &_value,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Set key" << _key << "to" << _value; qCDebug(LOG_LIB) << "Set key" << _key << "to" << _value;
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit options";
return false;
}
// add to database
long long id = m_advancedSettings->id(_key); long long id = m_advancedSettings->id(_key);
QVariantHash payload = { QVariantHash payload = {{"key", _key}, {"value", _value}};
{"key", _key}, {"value", _value},
};
bool status = false; bool status = false;
if (id == -1) { if (id == -1) {
@ -136,6 +201,7 @@ bool QueuedCore::editOption(const QString &_key, const QVariant &_value)
<< "has been modified with status" << status; << "has been modified with status" << status;
} }
// add to child objectm
if (status) if (status)
m_advancedSettings->set(_key, _value); m_advancedSettings->set(_key, _value);
return status; return status;
@ -145,7 +211,9 @@ bool QueuedCore::editOption(const QString &_key, const QVariant &_value)
/** /**
* @fn editTask * @fn editTask
*/ */
bool QueuedCore::editTask(const long long _id, const QVariantHash &_taskData) bool QueuedCore::editTask(
const long long _id, const QVariantHash &_taskData,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Edit task with ID" << _id; qCDebug(LOG_LIB) << "Edit task with ID" << _id;
@ -155,8 +223,41 @@ bool QueuedCore::editTask(const long long _id, const QVariantHash &_taskData)
return false; return false;
} }
// check permissions
long long userAuthId = m_users->user(_auth.user)->index();
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
bool isUser = m_users->authorize(_auth, QueuedEnums::Permission::JobOwner);
if (userAuthId == task->user()) {
// it means that user edits own task
if (!isUser) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit task";
return false;
}
} else {
// user tries to edit random task
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit task";
return false;
}
}
// only admin can edit run/stopped task
if (task->pstate() != QueuedEnums::ProcessState::NotRunning) {
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit run/exited task";
return false;
}
}
// drop admin fields
QVariantHash payload
= isAdmin ? _taskData
: dropAdminFields(QueuedDB::TASKS_TABLE, _taskData);
// modify record in database first // modify record in database first
bool status = m_database->modify(QueuedDB::TASKS_TABLE, _id, _taskData); bool status = m_database->modify(QueuedDB::TASKS_TABLE, _id, payload);
if (!status) { if (!status) {
qCWarning(LOG_LIB) << "Could not modify task record" << _id qCWarning(LOG_LIB) << "Could not modify task record" << _id
<< "in database, do not edit it in memory"; << "in database, do not edit it in memory";
@ -164,9 +265,9 @@ bool QueuedCore::editTask(const long long _id, const QVariantHash &_taskData)
} }
// modify values stored in memory // modify values stored in memory
for (auto &property : _taskData.keys()) for (auto &property : payload.keys())
task->setProperty(property.toLocal8Bit().constData(), task->setProperty(property.toLocal8Bit().constData(),
_taskData[property]); payload[property]);
return true; return true;
} }
@ -175,7 +276,9 @@ bool QueuedCore::editTask(const long long _id, const QVariantHash &_taskData)
/** /**
* @fn editUser * @fn editUser
*/ */
bool QueuedCore::editUser(const long long _id, const QVariantHash &_userData) bool QueuedCore::editUser(
const long long _id, const QVariantHash &_userData,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Edit user with ID" << _id; qCDebug(LOG_LIB) << "Edit user with ID" << _id;
@ -185,8 +288,24 @@ bool QueuedCore::editUser(const long long _id, const QVariantHash &_userData)
return false; return false;
} }
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
long long userAuthId = m_users->user(_auth.user)->index();
if (userAuthId != _id) {
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit user";
return false;
}
}
// drop admin fields
QVariantHash payload
= isAdmin ? _userData
: dropAdminFields(QueuedDB::USERS_TABLE, _userData);
// modify record in database first // modify record in database first
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, _userData); bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, payload);
if (!status) { if (!status) {
qCWarning(LOG_LIB) << "Could not modify user record" << _id qCWarning(LOG_LIB) << "Could not modify user record" << _id
<< "in database, do not edit it in memory"; << "in database, do not edit it in memory";
@ -194,9 +313,9 @@ bool QueuedCore::editUser(const long long _id, const QVariantHash &_userData)
} }
// modify values stored in memory // modify values stored in memory
for (auto &property : _userData.keys()) for (auto &property : payload.keys())
user->setProperty(property.toLocal8Bit().constData(), user->setProperty(property.toLocal8Bit().constData(),
_userData[property]); payload[property]);
return true; return true;
} }
@ -205,9 +324,9 @@ bool QueuedCore::editUser(const long long _id, const QVariantHash &_userData)
/** /**
* @fn editUserPermission * @fn editUserPermission
*/ */
bool QueuedCore::editUserPermission(const long long _id, bool QueuedCore::editUserPermission(
const QueuedEnums::Permission &_permission, const long long _id, const QueuedEnums::Permission &_permission,
const bool _add) const bool _add, const QueuedUserManager::QueuedUserAuthorization &_auth)
{ {
qCDebug(LOG_LIB) << "Edit permissions" << static_cast<int>(_permission) qCDebug(LOG_LIB) << "Edit permissions" << static_cast<int>(_permission)
<< "for user" << _id << "add" << _add; << "for user" << _id << "add" << _add;
@ -218,6 +337,18 @@ bool QueuedCore::editUserPermission(const long long _id,
return false; return false;
} }
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
long long userAuthId = m_users->user(_auth.user)->index();
if (userAuthId != _id) {
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to edit permissions";
return false;
}
}
// edit runtime permissions to get value
if (_add) if (_add)
user->addPermissions(_permission); user->addPermissions(_permission);
else else
@ -243,6 +374,73 @@ bool QueuedCore::editUserPermission(const long long _id,
} }
/**
* @fn startTask
*/
bool QueuedCore::startTask(
const long long _id,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{
qCDebug(LOG_LIB) << "Force start task with ID" << _id;
// check permissions
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
long long userAuthId = m_users->user(_auth.user)->index();
if (userAuthId != _id) {
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to start tasks";
return false;
}
}
m_processes->start(_id);
return true;
}
/**
* @fn stopTask
*/
bool QueuedCore::stopTask(
const long long _id,
const QueuedUserManager::QueuedUserAuthorization &_auth)
{
qCDebug(LOG_LIB) << "Force stop task with ID" << _id;
auto task = m_processes->process(_id);
if (!task) {
qCWarning(LOG_LIB) << "Could not find task with ID" << _id;
return false;
}
// check permissions
long long userAuthId = m_users->user(_auth.user)->index();
bool isAdmin = m_users->authorize(_auth, QueuedEnums::Permission::Admin);
bool isUser = m_users->authorize(_auth, QueuedEnums::Permission::JobOwner);
if (userAuthId == task->user()) {
// it means that user edits own task
if (!isUser) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to stop task";
return false;
}
} else {
// user tries to edit random task
if (!isAdmin) {
qCInfo(LOG_LIB) << "User" << _auth.user
<< "not allowed to stop task";
return false;
}
}
m_processes->stop(_id);
return true;
}
/** /**
* @fn deinit * @fn deinit
*/ */
@ -351,6 +549,26 @@ void QueuedCore::updateUserLoginTime(const long long _id,
} }
/**
* @fn dropAdminFields
*/
QVariantHash QueuedCore::dropAdminFields(const QString &_table,
const QVariantHash &_payload)
{
qCDebug(LOG_LIB) << "Drop admin fields from" << _payload << "in table"
<< _table;
QVariantHash payload;
for (auto &key : _payload.keys()) {
if (QueuedDB::DBSchema[_table][key].adminField)
continue;
payload[key] = _payload[key];
}
return payload;
}
/** /**
* @fn initProcesses * @fn initProcesses
*/ */

View File

@ -52,11 +52,12 @@ QueuedTokenManager::~QueuedTokenManager()
/** /**
* @fn isTokenValid * @fn isTokenValid
*/ */
bool QueuedTokenManager::isTokenValid(const QString &_token) bool QueuedTokenManager::isTokenValid(const QString &_token) const
{ {
qCDebug(LOG_LIB) << "Check token on validity" << _token; qCDebug(LOG_LIB) << "Check token on validity" << _token;
return m_tokens.contains(_token); return m_tokens.contains(_token)
&& (tokenExpiration(_token) > QDateTime::currentDateTimeUtc());
} }
@ -101,6 +102,15 @@ QString QueuedTokenManager::registerToken(const QDateTime _validUntil)
} }
/**
* @fn tokenExpiration
*/
QDateTime QueuedTokenManager::tokenExpiration(const QString &_token) const
{
return m_tokens[_token];
}
/** /**
* @fn expireToken * @fn expireToken
*/ */

View File

@ -94,6 +94,22 @@ QueuedUserManager::add(const QueuedUser::QueuedUserDefinitions &_definitions,
} }
/**
* @fn auth
*/
QueuedUserManager::QueuedUserAuthorization
QueuedUserManager::auth(const QString &_user, const QString &_token)
{
qCDebug(LOG_LIB) << "Generate auth structure for user" << _user;
QueuedUserAuthorization authObj;
authObj.user = _user;
authObj.token = _token;
return authObj;
}
/** /**
* @fn authorize * @fn authorize
*/ */
@ -124,7 +140,7 @@ QString QueuedUserManager::authorize(const QString &_user,
/** /**
* @fn authorize * @fn authorize
*/ */
bool QueuedUserManager::authorize(const UserAuthorization &_auth, bool QueuedUserManager::authorize(const QueuedUserAuthorization &_auth,
const QueuedEnums::Permission _service) const QueuedEnums::Permission _service)
{ {
qCDebug(LOG_LIB) << "Authorize user" << _auth.user << "for" qCDebug(LOG_LIB) << "Authorize user" << _auth.user << "for"
@ -146,6 +162,19 @@ bool QueuedUserManager::authorize(const UserAuthorization &_auth,
} }
/**
* @fn checkToken
*/
QDateTime QueuedUserManager::checkToken(const QString &_token,
bool *_valid) const
{
if (_valid)
*_valid = m_tokens->isTokenValid(_token);
return m_tokens->tokenExpiration(_token);
}
/** /**
* @fn ids * @fn ids
*/ */