From 034bd164a278d004b76c5af67f3f914c2a74dfa4 Mon Sep 17 00:00:00 2001 From: brindosch Date: Thu, 29 Aug 2019 18:17:06 +0200 Subject: [PATCH] Add userToken Auth --- include/api/JsonAPI.h | 5 ++++ include/db/AuthTable.h | 46 +++++++++++++++++++++++++++++++++ include/hyperion/AuthManager.h | 21 +++++++++++++++ libsrc/api/JsonAPI.cpp | 32 ++++++++++++++++++++--- libsrc/hyperion/AuthManager.cpp | 13 ++++++++++ 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index 9c8477c4..0cd11274 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -91,6 +91,11 @@ signals: /// void forwardJsonMessage(QJsonObject); + /// + /// @brief The API might decide to block connections for security reasons, this emitter should close the socket + /// + void forceClose(); + private: /// Auth management pointer AuthManager* _authManager; diff --git a/include/db/AuthTable.h b/include/db/AuthTable.h index 0cb7d15e..ddf7f3be 100644 --- a/include/db/AuthTable.h +++ b/include/db/AuthTable.h @@ -80,6 +80,52 @@ public: return false; } + /// + /// @brief Test if a user token is authorized for access. + /// @param usr The user name + /// @param token The token + /// @return True on success else false + /// + inline bool isUserTokenAuthorized(const QString& usr, const QString& token) + { + if(getUserToken(usr) == token.toUtf8()) + { + updateUserUsed(usr); + return true; + } + return false; + } + + /// + /// @brief Update token of a user. It's an alternate login path which is replaced on startup. This token is NOT hashed(!) + /// @param user The user name + /// @return True on success else false + /// + inline bool setUserToken(const QString& user) + { + QVariantMap map; + map["token"] = QCryptographicHash::hash(QUuid::createUuid().toByteArray(), QCryptographicHash::Sha512).toHex(); + + VectorPair cond; + cond.append(CPair("user", user)); + return updateRecord(cond, map); + } + + /// + /// @brief Get token of a user. This token is NOT hashed(!) + /// @param user The user name + /// @return The token + /// + inline const QByteArray getUserToken(const QString& user) + { + QVariantMap results; + VectorPair cond; + cond.append(CPair("user", user)); + getRecord(cond, results, QStringList()<<"token"); + + return results["token"].toByteArray(); + } + /// /// @brief update password of given user. The user should be tested (isUserAuthorized) to verify this change /// @param user The user name diff --git a/include/hyperion/AuthManager.h b/include/hyperion/AuthManager.h index 9349a8b0..c8e73b27 100644 --- a/include/hyperion/AuthManager.h +++ b/include/hyperion/AuthManager.h @@ -61,6 +61,19 @@ public: /// const bool & isLocalAdminAuthRequired() { return _localAdminAuthRequired; }; + /// + /// @brief Check if Hyperion user has default password + /// @return True if so, else false + /// + const bool hasHyperionDefaultPw() { return isUserAuthorized("Hyperion","hyperion"); }; + + /// + /// @brief Get the current valid token for user. Make sure this call is allowed! + /// @param For the defined user + /// @return The token + /// + const QString getUserToken(const QString & usr = "Hyperion"); + /// /// @brief Reset Hyperion user /// @return True on success else false @@ -89,6 +102,14 @@ public: /// bool isTokenAuthorized(const QString& token); + /// + /// @brief Check if token is authorized + /// @param usr The username + /// @param token The token + /// @return True if authorized else false + /// + bool isUserTokenAuthorized(const QString& usr, const QString& token); + /// /// @brief Change password of user /// @param user The username diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index f83ddccc..f83bf6be 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -58,6 +58,12 @@ JsonAPI::JsonAPI(QString peerAddress, Logger* log, const bool& localConnection, { Q_INIT_RESOURCE(JSONRPC_schemas); + // For security we block external connections if default PW is set + if(!localConnection && _authManager->hasHyperionDefaultPw()) + { + emit forceClose(); + } + // if this is localConnection and network allows unauth locals, set authorized flag if(_apiAuthRequired && localConnection) _authorized = !_authManager->isLocalAuthRequired(); @@ -1127,7 +1133,7 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject & message, const QString if(subc == "newPasswordRequired") { QJsonObject req; - req["newPasswordRequired"] = _authManager->isUserAuthorized("Hyperion", "hyperion"); + req["newPasswordRequired"] = _authManager->hasHyperionDefaultPw(); sendSuccessDataReply(QJsonDocument(req), command+"-"+subc, tan); return; } @@ -1287,12 +1293,27 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject & message, const QString // login if(subc == "login") { - // catch token auth const QString& token = message["token"].toString().trimmed(); + // catch token if(!token.isEmpty()) { - if(token.count() >= 36) + // userToken is longer + if(token.count() > 36) + { + if(_authManager->isUserTokenAuthorized("Hyperion",token)) + { + _authorized = true; + _userAuthorized = true; + sendSuccessReply(command+"-"+subc, tan); + } + else + sendErrorReply("No Authorization", command+"-"+subc, tan); + + return; + } + // usual app token is 36 + if(token.count() == 36) { if(_authManager->isTokenAuthorized(token)) { @@ -1317,7 +1338,10 @@ void JsonAPI::handleAuthorizeCommand(const QJsonObject & message, const QString { _authorized = true; _userAuthorized = true; - sendSuccessReply(command+"-"+subc, tan); + // Return the current valid Hyperion user token + QJsonObject obj; + obj["token"] = _authManager->getUserToken(); + sendSuccessDataReply(QJsonDocument(obj),command+"-"+subc, tan); } else sendErrorReply("No Authorization", command+"-"+subc, tan); diff --git a/libsrc/hyperion/AuthManager.cpp b/libsrc/hyperion/AuthManager.cpp index bd825515..f4a524db 100644 --- a/libsrc/hyperion/AuthManager.cpp +++ b/libsrc/hyperion/AuthManager.cpp @@ -32,6 +32,9 @@ AuthManager::AuthManager(QObject* parent) { _authTable->createUser("Hyperion","hyperion"); } + + // update Hyperion user token on startup + _authTable->setUserToken("Hyperion"); } const AuthManager::AuthDefinition AuthManager::createToken(const QString& comment) @@ -67,6 +70,11 @@ const QVector AuthManager::getTokenList() return finalVec; } +const QString AuthManager::getUserToken(const QString & usr) +{ + return QString(_authTable->getUserToken("Hyperion")); +} + bool AuthManager::isUserAuthorized(const QString& user, const QString& pw) { return _authTable->isUserAuthorized(user, pw); @@ -77,6 +85,11 @@ bool AuthManager::isTokenAuthorized(const QString& token) return _authTable->tokenExist(token); } +bool AuthManager::isUserTokenAuthorized(const QString& usr, const QString& token) +{ + return _authTable->isUserTokenAuthorized(usr, token); +} + bool AuthManager::updateUserPassword(const QString& user, const QString& pw, const QString& newPw) { if(isUserAuthorized(user, pw))