From 4595ae8e2d53f921ec80180ed4331471cd0b96b9 Mon Sep 17 00:00:00 2001 From: brindosch Date: Fri, 30 Aug 2019 18:51:07 +0200 Subject: [PATCH] Feat: Protect db against pw/token tests --- include/hyperion/AuthManager.h | 32 ++++++++++++++++ libsrc/hyperion/AuthManager.cpp | 68 +++++++++++++++++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/include/hyperion/AuthManager.h b/include/hyperion/AuthManager.h index c8e73b27..8b12c0e0 100644 --- a/include/hyperion/AuthManager.h +++ b/include/hyperion/AuthManager.h @@ -110,6 +110,18 @@ public: /// bool isUserTokenAuthorized(const QString& usr, const QString& token); + /// + /// @brief Check if user auth is temporary blocked due to failed attempts + /// @return True on blocked and no further Auth requests will be accepted + /// + bool isUserAuthBlocked(){ return (_userAuthAttempts.length() >= 10); }; + + /// + /// @brief Check if token auth is temporary blocked due to failed attempts + /// @return True on blocked and no further Auth requests will be accepted + /// + bool isTokenAuthBlocked(){ return (_tokenAuthAttempts.length() >= 25); }; + /// /// @brief Change password of user /// @param user The username @@ -186,6 +198,12 @@ signals: void tokenResponse(const bool& success, QObject* caller, const QString& token, const QString& comment, const QString& id); private: + /// + /// @brief Increment counter for token/user auth + /// @param user If true we increment USER auth instead of token + /// + void setAuthBlock(const bool& user = false); + /// Database interface for auth table AuthTable* _authTable; @@ -210,9 +228,23 @@ private: /// Timer for counting against pendingRequest timeouts QTimer* _timer; + // Timer which cleans up the block counter + QTimer* _authBlockTimer; + + // Contains timestamps of failed user login attempts + QVector _userAuthAttempts; + + // Contains timestamps of failed token login attempts + QVector _tokenAuthAttempts; + private slots: /// /// @brief Check timeout of pending requests /// void checkTimeout(); + + /// + /// @brief Check if there are timeouts for failed login attempts + /// + void checkAuthBlockTimeout(); }; diff --git a/libsrc/hyperion/AuthManager.cpp b/libsrc/hyperion/AuthManager.cpp index f4a524db..70bc892d 100644 --- a/libsrc/hyperion/AuthManager.cpp +++ b/libsrc/hyperion/AuthManager.cpp @@ -17,9 +17,11 @@ AuthManager::AuthManager(QObject* parent) , _pendingRequests() , _authRequired(true) , _timer(new QTimer(this)) + , _authBlockTimer(new QTimer(this)) { AuthManager::manager = this; + // get uuid _uuid = _metaTable->getUUID(); @@ -27,6 +29,10 @@ AuthManager::AuthManager(QObject* parent) _timer->setInterval(1000); connect(_timer, &QTimer::timeout, this, &AuthManager::checkTimeout); + // setup authBlockTimer + _authBlockTimer->setInterval(60000); + connect(_authBlockTimer, &QTimer::timeout, this, &AuthManager::checkAuthBlockTimeout); + // init with default user and password if(!_authTable->userExist("Hyperion")) { @@ -72,22 +78,54 @@ const QVector AuthManager::getTokenList() const QString AuthManager::getUserToken(const QString & usr) { - return QString(_authTable->getUserToken("Hyperion")); + return QString(_authTable->getUserToken(usr)); +} + +void AuthManager::setAuthBlock(const bool& user) +{ + // current timestamp +10 minutes + if(user) + _userAuthAttempts.append(QDateTime::currentMSecsSinceEpoch()+600000); + else + _tokenAuthAttempts.append(QDateTime::currentMSecsSinceEpoch()+600000); + + QMetaObject::invokeMethod(_authBlockTimer, "start", Qt::QueuedConnection); } bool AuthManager::isUserAuthorized(const QString& user, const QString& pw) { - return _authTable->isUserAuthorized(user, pw); + if(isUserAuthBlocked()) + return false; + + if(!_authTable->isUserAuthorized(user, pw)){ + setAuthBlock(true); + return false; + } + return true; } bool AuthManager::isTokenAuthorized(const QString& token) { - return _authTable->tokenExist(token); + if(isTokenAuthBlocked()) + return false; + + if(!_authTable->tokenExist(token)){ + setAuthBlock(); + return false; + } + return true; } bool AuthManager::isUserTokenAuthorized(const QString& usr, const QString& token) { - return _authTable->isUserTokenAuthorized(usr, token); + if(isUserAuthBlocked()) + return false; + + if(!_authTable->isUserTokenAuthorized(usr, token)){ + setAuthBlock(true); + return false; + } + return true; } bool AuthManager::updateUserPassword(const QString& user, const QString& pw, const QString& newPw) @@ -184,3 +222,25 @@ void AuthManager::checkTimeout() if(_pendingRequests.isEmpty()) _timer->stop(); } + +void AuthManager::checkAuthBlockTimeout(){ + // handle user auth block + for (auto it = _userAuthAttempts.begin(); it != _userAuthAttempts.end(); it++) { + // after 10 minutes, we remove the entry + if (*it < (uint64_t)QDateTime::currentMSecsSinceEpoch()) { + _userAuthAttempts.erase(it--); + } + } + + // handle token auth block + for (auto it = _tokenAuthAttempts.begin(); it != _tokenAuthAttempts.end(); it++) { + // after 10 minutes, we remove the entry + if (*it < (uint64_t)QDateTime::currentMSecsSinceEpoch()) { + _tokenAuthAttempts.erase(it--); + } + } + + // if the lists are empty we stop + if(_userAuthAttempts.empty() && _tokenAuthAttempts.empty()) + _authBlockTimer->stop(); +}