diff --git a/src/cpp/HTTPInterface/LoginPage.cpp b/src/cpp/HTTPInterface/LoginPage.cpp index a70f08f66..37ef25349 100644 --- a/src/cpp/HTTPInterface/LoginPage.cpp +++ b/src/cpp/HTTPInterface/LoginPage.cpp @@ -36,6 +36,12 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: response.redirect(uri_start + "/"); return; } + } else { + // remove old cookies if exist + auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId)) + // max age of 0 delete cookie + keks.setMaxAge(0); + response.addCookie(keks); } std::ostream& _responseStream = response.send(); @@ -72,7 +78,7 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net:: responseStream << "\t
\n"; responseStream << "\t\t

Login

\n"; responseStream << "\t\t"; -#line 56 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\login.cpsp" +#line 62 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\login.cpsp" responseStream << ( session->getErrorsHtml() ); responseStream << "\n"; responseStream << "\t\t
\n"; diff --git a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp index a3a511611..67af9dcc5 100644 --- a/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp +++ b/src/cpp/HTTPInterface/PageRequestHandlerFactory.cpp @@ -28,10 +28,12 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c std::string url_first_part; mRemoveGETParameters.extract(uri, url_first_part); - printf("[PageRequestHandlerFactory] uri: %s, first part: %s\n", uri.data(), url_first_part.data()); - auto referer = request.find("Referer"); - if (referer != request.end()) { - printf("referer: %s\n", referer->second.data()); + if (uri != "/favicon.ico") { + printf("[PageRequestHandlerFactory] uri: %s, first part: %s\n", uri.data(), url_first_part.data()); + auto referer = request.find("Referer"); + if (referer != request.end()) { + printf("referer: %s\n", referer->second.data()); + } } // check if user has valid session @@ -41,18 +43,25 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c int session_id = 0; try { - session_id = atoi(cookies.get("user").data()); + session_id = atoi(cookies.get("GRADIDO_LOGIN").data()); } catch (...) {} auto sm = SessionManager::getInstance(); auto s = sm->getSession(session_id); + + // TODO: count invalid session requests from IP and block IP for some time to prevent brute force session hijacking + // or use log file and configure fail2ban for this to do if (url_first_part == "/checkEmail") { //return new CheckEmailPage(s); - return handleCheckEmail(s, uri, request); + if (!s || s->getSessionState() < SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED) { + return handleCheckEmail(s, uri, request); + } } if (s) { if(url_first_part == "/logout") { sm->releseSession(s); + // remove cookie + printf("session released\n"); return new LoginPage; } @@ -97,15 +106,26 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi // try to get code from form get parameter if (!form.empty()) { try { - verificationCode = stoll(form.get("email-verification-code", "0")); + verificationCode = stoull(form.get("email-verification-code", "0")); } catch (...) {} } // try to get code from uri parameter if (!verificationCode) { size_t pos = uri.find_last_of("/"); try { - verificationCode = stoll(uri.substr(pos + 1)); - } catch (...) {} + auto str = uri.substr(pos + 1); + verificationCode = stoull(uri.substr(pos + 1)); + } catch (const std::invalid_argument& ia) { + std::cerr << "Invalid argument: " << ia.what() << '\n'; + } catch (const std::out_of_range& oor) { + std::cerr << "Out of Range error: " << oor.what() << '\n'; + } + catch (const std::logic_error & ler) { + std::cerr << "Logical error: " << ler.what() << '\n'; + } + catch (...) { + std::cerr << "Unknown error" << '\n'; + } } // if no verification code given or error with given code, show form @@ -138,6 +158,9 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::handleCheckEmail(Sessi } // suitable session found or created if (session) { + auto user_host = request.clientAddress().host(); + session->setClientIp(user_host); + // update session, mark as verified if (session->updateEmailVerification(verificationCode)) { return new PassphrasePage(session); diff --git a/src/cpp/HTTPInterface/PassphrasePage.cpp b/src/cpp/HTTPInterface/PassphrasePage.cpp index d38f888c2..4b34f5bbd 100644 --- a/src/cpp/HTTPInterface/PassphrasePage.cpp +++ b/src/cpp/HTTPInterface/PassphrasePage.cpp @@ -35,10 +35,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: bool hasErrors = mSession->errorCount() > 0; // save login cookie, because maybe we've get an new session - auto cookie_id = mSession->getHandle(); - auto user_host = request.clientAddress().host(); - mSession->setClientIp(user_host); - response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id))); + response.addCookie(mSession->getLoginCookie()); if (!form.empty()) { auto registerKeyChoice = form.get("passphrase", ""); @@ -97,18 +94,18 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\n"; responseStream << "
\n"; responseStream << "\t"; -#line 78 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 75 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" if(mSession && hasErrors) { responseStream << "\n"; responseStream << "\t\t"; -#line 79 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 76 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" responseStream << ( mSession->getErrorsHtml() ); responseStream << "\n"; responseStream << "\t"; -#line 80 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 77 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" } responseStream << "\n"; responseStream << "\t

Einen neuen Account anlegen

\n"; responseStream << "\t"; -#line 82 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 79 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" if(state == PAGE_SHOW_PASSPHRASE) { responseStream << "\n"; responseStream << "\t\t
\n"; responseStream << "\t\t\t
\n"; @@ -116,16 +113,16 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\t\t\t
\n"; responseStream << "\t\t\t
\n"; responseStream << "\t\t\t\t"; -#line 88 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 85 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" responseStream << ( mSession->getPassphrase() ); responseStream << "\n"; responseStream << "\t\t\t
\n"; responseStream << "\t\t\tWeiter\n"; responseStream << "\t\t
\n"; responseStream << "\t"; -#line 92 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 89 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" } else if(state == PAGE_ASK_PASSPHRASE) { responseStream << "\n"; - responseStream << "\t
\n"; + responseStream << "\t\n"; responseStream << "\t\t
\n"; responseStream << "\t\t\tNeue Gradido Adresse anlegen / wiederherstellen\n"; responseStream << "\t\t\t

Hast du schonmal ein Gradido Konto besessen?

\n"; @@ -138,7 +135,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\t\t\t\t\n"; responseStream << "\t\t\t

\n"; responseStream << "\t\t\t\n"; responseStream << "\t\t
\n"; @@ -146,13 +143,13 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\t\t\n"; responseStream << "\t
\n"; responseStream << "\t"; -#line 110 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 107 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" } else { responseStream << "\n"; responseStream << "\t\t
\n"; responseStream << "\t\t\tUngültige Seite, wenn du das siehst stimmt hier etwas nicht. Bitte wende dich an den Server-Admin. \n"; responseStream << "\t\t
\n"; responseStream << "\t"; -#line 114 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" +#line 111 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp" } responseStream << "\n"; responseStream << "
\n"; responseStream << "\n"; diff --git a/src/cpp/ServerConfig.cpp b/src/cpp/ServerConfig.cpp index 6e61d1e2b..975dbb8be 100644 --- a/src/cpp/ServerConfig.cpp +++ b/src/cpp/ServerConfig.cpp @@ -17,12 +17,16 @@ using Poco::Net::ConsoleCertificateHandler; using Poco::SharedPtr; namespace ServerConfig { + +#define SESSION_TIMEOUT_DEFAULT 10 + Mnemonic g_Mnemonic_WordLists[MNEMONIC_MAX]; ObfusArray* g_ServerCryptoKey = nullptr; // std::string g_ServerAdminPublic; UniLib::controller::CPUSheduler* g_CPUScheduler = nullptr; Context::Ptr g_SSL_CLient_Context = nullptr; EmailAccount g_EmailAccount; + int g_SessionTimeout = SESSION_TIMEOUT_DEFAULT; bool loadMnemonicWordLists() { @@ -66,6 +70,8 @@ namespace ServerConfig { g_ServerCryptoKey = new ObfusArray(realBinSize, key); //g_ServerAdminPublic = cfg.getString("crypto.server_admin_public"); + + g_SessionTimeout = cfg.getInt("session.timeout", SESSION_TIMEOUT_DEFAULT); return true; } diff --git a/src/cpp/ServerConfig.h b/src/cpp/ServerConfig.h index d7fc84b69..1c08f3fa0 100644 --- a/src/cpp/ServerConfig.h +++ b/src/cpp/ServerConfig.h @@ -27,6 +27,7 @@ namespace ServerConfig { extern UniLib::controller::CPUSheduler* g_CPUScheduler; extern Poco::Net::Context::Ptr g_SSL_CLient_Context; extern EmailAccount g_EmailAccount; + extern int g_SessionTimeout; bool loadMnemonicWordLists(); bool initServerCrypto(const Poco::Util::LayeredConfiguration& cfg); diff --git a/src/cpp/SingletonManager/SessionManager.cpp b/src/cpp/SingletonManager/SessionManager.cpp index c4764ee14..4b2cede5a 100644 --- a/src/cpp/SingletonManager/SessionManager.cpp +++ b/src/cpp/SingletonManager/SessionManager.cpp @@ -1,4 +1,6 @@ #include "SessionManager.h" +#include "ErrorManager.h" +#include "../ServerConfig.h" #include @@ -33,10 +35,10 @@ bool SessionManager::init() case VALIDATE_EMAIL: mValidations[i] = new Poco::RegularExpression("^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"); break; case VALIDATE_PASSWORD: mValidations[i] = new Poco::RegularExpression("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&+-])[A-Za-z0-9@$!%*?&+-]{8,}$"); break; case VALIDATE_PASSPHRASE: mValidations[i] = new Poco::RegularExpression("^(?:[a-z]* ){23}[a-z]*\s*$"); break; - case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression("[0-9]"); break; - case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression("[@$!%*?&+-]"); break; - case VALIDATE_HAS_UPPERCASE_LETTER: mValidations[i] = new Poco::RegularExpression("[A-Z]"); break; - case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression("[a-z]"); break; + case VALIDATE_HAS_NUMBER: mValidations[i] = new Poco::RegularExpression(".*[0-9].*"); break; + case VALIDATE_HAS_SPECIAL_CHARACTER: mValidations[i] = new Poco::RegularExpression(".*[@$!%*?&+-].*"); break; + case VALIDATE_HAS_UPPERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[A-Z].*"); break; + case VALIDATE_HAS_LOWERCASE_LETTER: mValidations[i] = new Poco::RegularExpression(".*[a-z].*"); break; default: printf("[SessionManager::%s] unknown validation type\n", __FUNCTION__); } } @@ -77,6 +79,25 @@ bool SessionManager::isValid(const std::string& subject, SessionValidationTypes return *mValidations[validationType] == subject; } +int SessionManager::generateNewUnusedHandle() +{ + int newHandle = 0; + int maxTrys = 0; + do { + newHandle = randombytes_random(); + maxTrys++; + } while (mRequestSessionMap.find(newHandle) != mRequestSessionMap.end() && maxTrys < 100); + + if (maxTrys >= 100 || 0 == newHandle) { + auto em = ErrorManager::getInstance(); + em->addError(new ParamError("SessionManager::generateNewUnusedHandle", "can't find new handle, have already ", std::to_string(mRequestSessionMap.size()))); + em->sendErrorsAsEmail(); + //printf("[SessionManager::%s] can't find new handle, have already: %d", + //__FUNCTION__, mRequestSessionMap.size()); + return 0; + } + return newHandle; +} Session* SessionManager::getNewSession(int* handle) { @@ -84,15 +105,22 @@ Session* SessionManager::getNewSession(int* handle) printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__); return nullptr; } + + // first check if we have any timeouted session to directly reuse it + checkTimeoutSession(); + // lock mWorkingMutex.lock(); + //UniLib::controller::TaskPtr checkSessionTimeout(new CheckSessionTimeouted); + //checkSessionTimeout->scheduleTask(checkSessionTimeout); + // check if we have an existing session ready to use - if (mEmptyRequestStack.size() > 0) { + while (mEmptyRequestStack.size() > 0) { int local_handle = mEmptyRequestStack.top(); mEmptyRequestStack.pop(); auto resultIt = mRequestSessionMap.find(local_handle); - if (resultIt != mRequestSessionMap.end()) { + if (resultIt != mRequestSessionMap.end() && !resultIt->second->isActive()) { Session* result = resultIt->second; result->reset(); mWorkingMutex.unlock(); @@ -100,38 +128,34 @@ Session* SessionManager::getNewSession(int* handle) if (handle) { *handle = local_handle; } + result->setActive(true); return result; } } - else { - // else create new RequestSession Object - // calculate random handle - // check if already exist, if get new - int newHandle = 0; - int maxTrys = 0; - do { - newHandle = randombytes_random(); - maxTrys++; - } while (mRequestSessionMap.find(newHandle) != mRequestSessionMap.end() && maxTrys < 100); - - if (maxTrys >= 100 || 0 == newHandle) { - printf("[SessionManager::%s] can't find new handle, have already: %d", - __FUNCTION__, mRequestSessionMap.size()); - return nullptr; - } - - auto requestSession = new Session(newHandle); - mRequestSessionMap.insert(std::pair(newHandle, requestSession)); + + // else create new RequestSession Object + // calculate random handle + // check if already exist, if get new + int newHandle = generateNewUnusedHandle(); + if (!newHandle) { mWorkingMutex.unlock(); - - if (handle) { - *handle = newHandle; - } - - return requestSession; + return nullptr; } - return nullptr; + auto requestSession = new Session(newHandle); + mRequestSessionMap.insert(std::pair(newHandle, requestSession)); + + requestSession->setActive(true); + mWorkingMutex.unlock(); + + if (handle) { + *handle = newHandle; + } + + return requestSession; + + + //return nullptr; } bool SessionManager::releseSession(int requestHandleSession) @@ -147,8 +171,25 @@ bool SessionManager::releseSession(int requestHandleSession) mWorkingMutex.unlock(); return false; } - it->second->reset(); - mEmptyRequestStack.push(requestHandleSession); + Session* session = it->second; + session->reset(); + session->setActive(false); + // change request handle we don't want session hijacking + + int newHandle = generateNewUnusedHandle(); + // erase after generating new number to prevent to getting the same number again + mRequestSessionMap.erase(requestHandleSession); + + if (!newHandle) { + delete session; + mWorkingMutex.unlock(); + return true; + } + + session->setHandle(newHandle); + mRequestSessionMap.insert(std::pair(newHandle, session)); + mEmptyRequestStack.push(newHandle); + mWorkingMutex.unlock(); return true; @@ -181,6 +222,8 @@ Session* SessionManager::getSession(int handle) auto it = mRequestSessionMap.find(handle); if (it != mRequestSessionMap.end()) { result = it->second; + result->setActive(true); + result->updateTimeout(); } mWorkingMutex.unlock(); return result; @@ -188,11 +231,47 @@ Session* SessionManager::getSession(int handle) Session* SessionManager::findByEmailVerificationCode(long long emailVerificationCode) { + Session* result = nullptr; + mWorkingMutex.lock(); for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { if (it->second->getEmailVerificationCode() == emailVerificationCode) { - return it->second; + result = it->second; + break; } } + mWorkingMutex.unlock(); - return nullptr; + return result; +} + +void SessionManager::checkTimeoutSession() +{ + mWorkingMutex.lock(); + auto now = Poco::DateTime(); + // random variance within 10 seconds for timeout to make it harder to get information and hack the server + auto timeout = Poco::Timespan(ServerConfig::g_SessionTimeout * 60, randombytes_random() % 10000000); + std::stack toRemove; + for (auto it = mRequestSessionMap.begin(); it != mRequestSessionMap.end(); it++) { + if (!it->second->isActive()) continue; + Poco::Timespan timeElapsed(now - it->second->getLastActivity()); + if (timeElapsed > timeout) { + toRemove.push(it->first); + } + } + mWorkingMutex.unlock(); + + while (toRemove.size() > 0) { + int handle = toRemove.top(); + toRemove.pop(); + releseSession(handle); + } + +} + + + +int CheckSessionTimeouted::run() +{ + SessionManager::getInstance()->checkTimeoutSession(); + return 0; } \ No newline at end of file diff --git a/src/cpp/SingletonManager/SessionManager.h b/src/cpp/SingletonManager/SessionManager.h index 0b214131a..6998e5cc6 100644 --- a/src/cpp/SingletonManager/SessionManager.h +++ b/src/cpp/SingletonManager/SessionManager.h @@ -46,6 +46,7 @@ public: } bool releseSession(int requestHandleSession); bool isExist(int requestHandleSession); + // try to find existing session, return nullptr if not found Session* getSession(int handle); Session* findByEmailVerificationCode(long long emailVerificationCode); @@ -54,9 +55,12 @@ public: bool isValid(const std::string& subject, SessionValidationTypes validationType); + void checkTimeoutSession(); + protected: SessionManager(); + int generateNewUnusedHandle(); // access mutex std::mutex mWorkingMutex; @@ -71,4 +75,11 @@ protected: Poco::RegularExpression* mValidations[VALIDATE_MAX]; }; +class CheckSessionTimeouted : public UniLib::controller::CPUTask +{ +public: + virtual int run(); + virtual const char* getResourceType() const { return "CheckSessionTimeouted"; }; +}; + #endif //DR_LUA_WEB_MODULE_SESSION_MANAGER_H \ No newline at end of file diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 07067c1fa..def731ba5 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -20,7 +20,7 @@ int WriteEmailVerification::run() { Profiler timeUsed; auto verificationCode = mSession->getEmailVerificationCode(); - printf("{[WriteEmailVerification::run] E-Mail Verification Code: %llu\n", verificationCode); + //printf("[WriteEmailVerification::run] E-Mail Verification Code: %llu\n", verificationCode); auto dbSession = ConnectionManager::getInstance()->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); int user_id = mUser->getDBId(); Poco::Data::Statement insert(dbSession); @@ -30,7 +30,7 @@ int WriteEmailVerification::run() mSession->addError(new Error("WriteEmailVerification", "error inserting email verification code")); return -1; } - printf("[WriteEmailVerification::run] timeUsed: %s\n", timeUsed.string().data()); + printf("[WriteEmailVerification] timeUsed: %s\n", timeUsed.string().data()); return 0; } @@ -63,7 +63,7 @@ int WritePassphraseIntoDB::run() em->sendErrorsAsEmail(); } - printf("[WritePassphraseIntoDB::run] timeUsed: %s\n", timeUsed.string().data()); + printf("[WritePassphraseIntoDB] timeUsed: %s\n", timeUsed.string().data()); return 0; } @@ -71,7 +71,7 @@ int WritePassphraseIntoDB::run() // -------------------------------------------------------------------------------------------------------------- Session::Session(int handle) - : mHandleId(handle), mSessionUser(nullptr), mEmailVerificationCode(0), mState(SESSION_STATE_EMPTY) + : mHandleId(handle), mSessionUser(nullptr), mEmailVerificationCode(0), mState(SESSION_STATE_EMPTY), mActive(false) { } @@ -90,7 +90,10 @@ void Session::reset() mSessionUser = nullptr; } updateTimeout(); + updateState(SESSION_STATE_EMPTY); + mPassphrase = ""; mClientLoginIP = Poco::Net::IPAddress(); + mEmailVerificationCode = 0; } void Session::updateTimeout() @@ -111,6 +114,8 @@ bool Session::createUser(const std::string& name, const std::string& email, cons return false; } if (!sm->isValid(password, VALIDATE_PASSWORD)) { + addError(new Error("Passwort", "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen ein!")); + // @$!%*?&+- if (password.size() < 8) { addError(new Error("Passwort", "Dein Passwort ist zu kurz!")); @@ -127,7 +132,7 @@ bool Session::createUser(const std::string& name, const std::string& email, cons else if (!sm->isValid(password, VALIDATE_HAS_SPECIAL_CHARACTER)) { addError(new Error("Passwort", "Dein Passwort enthält keine Sonderzeichen (@$!%*?&+-)!")); } - addError(new Error("Passwort", "Bitte gebe ein gültiges Password ein mit mindestens 8 Zeichen, Groß- und Kleinbuchstaben, mindestens einer Zahl und einem Sonderzeichen")); + return false; } /*if (passphrase.size() > 0 && !sm->isValid(passphrase, VALIDATE_PASSPHRASE)) { @@ -215,6 +220,7 @@ bool Session::createUser(const std::string& name, const std::string& email, cons bool Session::updateEmailVerification(unsigned long long emailVerificationCode) { + Profiler usedTime; const static char* funcName = "Session::updateEmailVerification"; auto em = ErrorManager::getInstance(); @@ -243,6 +249,7 @@ bool Session::updateEmailVerification(unsigned long long emailVerificationCode) } updateState(SESSION_STATE_EMAIL_VERIFICATION_CODE_CHECKED); printf("[%s] time: %s\n", funcName, usedTime.string().data()); + return true; } else { @@ -347,8 +354,12 @@ void Session::detectSessionState() Poco::Net::HTTPCookie Session::getLoginCookie() { - auto keks = Poco::Net::HTTPCookie("user", std::to_string(mHandleId)); - // TODO: additional config, like js permit + auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId)); + // prevent reading or changing cookie with js + keks.setHttpOnly(); + // send cookie only via https + keks.setSecure(true); + return keks; } @@ -407,7 +418,8 @@ bool Session::loadFromEmailVerificationCode(unsigned long long emailVerification void Session::updateState(SessionStates newState) { lock(); - printf("[Session::%s] newState: %s\n", __FUNCTION__, translateSessionStateToString(newState)); + updateTimeout(); + printf("[%s] newState: %s\n", __FUNCTION__, translateSessionStateToString(newState)); if (newState > mState) { mState = newState; } diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index 76da38605..88867e35b 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -39,11 +39,12 @@ enum SessionStates { SESSION_STATE_COUNT }; - +class SessionManager; class Session : public ErrorList, public UniLib::lib::MultithreadContainer { friend WriteEmailVerification; + friend SessionManager; public: Session(int handle); ~Session(); @@ -63,6 +64,7 @@ public: inline User* getUser() { return mSessionUser; } inline int getHandle() { return mHandleId; } + inline void setPassphrase(const std::string& passphrase) { mPassphrase = passphrase; } inline const std::string& getPassphrase() { return mPassphrase; } bool generatePassphrase(); @@ -81,14 +83,21 @@ public: inline unsigned long long getEmailVerificationCode() { return mEmailVerificationCode; } + inline bool isActive() const { return mActive; } + inline void setActive(bool active) { mActive = active; } + + inline Poco::DateTime getLastActivity() { return mLastActivity; } + protected: void updateTimeout(); + inline void setHandle(int newHandle) { mHandleId = newHandle; } void createEmailVerificationCode(); void detectSessionState(); static const char* translateSessionStateToString(SessionStates state); +private: int mHandleId; User* mSessionUser; std::string mPassphrase; @@ -97,6 +106,8 @@ protected: unsigned long long mEmailVerificationCode; SessionStates mState; + + bool mActive; }; diff --git a/src/cpp/tasks/PrepareEmailTask.cpp b/src/cpp/tasks/PrepareEmailTask.cpp new file mode 100644 index 000000000..6439c24b9 --- /dev/null +++ b/src/cpp/tasks/PrepareEmailTask.cpp @@ -0,0 +1,57 @@ +#include "PrepareEmailTask.h" +#include "../model/Profiler.h" +#include "../ServerConfig.h" +#include "../SingletonManager/ErrorManager.h" + +PrepareEmailTask::PrepareEmailTask(UniLib::controller::CPUSheduler* cpuScheduler) + : UniLib::controller::CPUTask(cpuScheduler), mMailClientSession(nullptr) +{ + +} + +PrepareEmailTask::~PrepareEmailTask() +{ + if (mMailClientSession) { + delete mMailClientSession; + } +} + +int PrepareEmailTask::run() +{ + Profiler timeUsed; + mMailClientSession = new Poco::Net::SecureSMTPClientSession(ServerConfig::g_EmailAccount.url, ServerConfig::g_EmailAccount.port); + mMailClientSession->login(); + mMailClientSession->startTLS(ServerConfig::g_SSL_CLient_Context); + + + mMailClientSession->login(Poco::Net::SMTPClientSession::AUTH_LOGIN, ServerConfig::g_EmailAccount.username, ServerConfig::g_EmailAccount.password); + + printf("[PrepareEmailTask] time: %s\n", timeUsed.string().data()); + /* + session.login(); + session.startTLS(pContext); + if (!username.empty()) + { + session.login(SMTPClientSession::AUTH_LOGIN, username, password); + } + session.sendMessage(message); + session.close(); + */ + + return 0; +} + +int PrepareEmailTask::send(Poco::Net::MailMessage* message) +{ + auto er = ErrorManager::getInstance(); + try { + mMailClientSession->sendMessage(*message); + mMailClientSession->close(); + } + catch (Poco::Exception& exc) { + er->addError(new ParamError("PrepareEmailTask::send", "error sending email", exc.displayText().data())); + printf("[PrepareEmailTask::%s] error sending email: %s\n", __FUNCTION__, exc.displayText().data()); + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/cpp/tasks/PrepareEmailTask.h b/src/cpp/tasks/PrepareEmailTask.h new file mode 100644 index 000000000..f015fcf8a --- /dev/null +++ b/src/cpp/tasks/PrepareEmailTask.h @@ -0,0 +1,23 @@ +#ifndef GRADIDO_LOGIN_SERVER_TASKS_PREPAIRE_EMAIL_TASK_INCLUDE +#define GRADIDO_LOGIN_SERVER_TASKS_PREPAIRE_EMAIL_TASK_INCLUDE + +#include "CPUTask.h" +#include "Poco/Net/SecureSMTPClientSession.h" + +class PrepareEmailTask : public UniLib::controller::CPUTask +{ +public: + PrepareEmailTask(UniLib::controller::CPUSheduler* cpuScheduler); + virtual ~PrepareEmailTask(); + + virtual int run(); + int send(Poco::Net::MailMessage* message); + virtual const char* getResourceType() const { return "PrepareEmailTask"; }; +protected: + +private: + Poco::Net::SecureSMTPClientSession* mMailClientSession; +}; + + +#endif //GRADIDO_LOGIN_SERVER_TASKS_PREPAIRE_EMAIL_TASK_INCLUDE \ No newline at end of file diff --git a/src/cpp/tasks/SendEmailTask.cpp b/src/cpp/tasks/SendEmailTask.cpp index 17dd6750b..6142a4f5a 100644 --- a/src/cpp/tasks/SendEmailTask.cpp +++ b/src/cpp/tasks/SendEmailTask.cpp @@ -1,5 +1,6 @@ #include "SendEmailTask.h" #include "PrepareEmailTask.h" +#include "../model/Profiler.h" #include "../SingletonManager/ErrorManager.h" #include "../ServerConfig.h" @@ -19,6 +20,7 @@ SendEmailTask::~SendEmailTask() int SendEmailTask::run() { + Profiler timeUsed; auto er = ErrorManager::getInstance(); auto parent = getParent(0); @@ -31,5 +33,6 @@ int SendEmailTask::run() if (prepare->send(mMailMessage)) { return -1; } + printf("[SendEmailTask] time: %s\n", timeUsed.string().data()); return 0; } \ No newline at end of file diff --git a/src/cpsp/login.cpsp b/src/cpsp/login.cpsp index 17d8357fe..8ec7d81d0 100644 --- a/src/cpsp/login.cpsp +++ b/src/cpsp/login.cpsp @@ -21,6 +21,12 @@ response.redirect(uri_start + "/"); return; } + } else { + // remove old cookies if exist + auto keks = Poco::Net::HTTPCookie("GRADIDO_LOGIN", std::to_string(mHandleId)) + // max age of 0 delete cookie + keks.setMaxAge(0); + response.addCookie(keks); } %> diff --git a/src/cpsp/passphrase.cpsp b/src/cpsp/passphrase.cpsp index a6d6c71ec..1d956c930 100644 --- a/src/cpsp/passphrase.cpsp +++ b/src/cpsp/passphrase.cpsp @@ -17,10 +17,7 @@ enum PageState bool hasErrors = mSession->errorCount() > 0; // save login cookie, because maybe we've get an new session - auto cookie_id = mSession->getHandle(); - auto user_host = request.clientAddress().host(); - mSession->setClientIp(user_host); - response.addCookie(Poco::Net::HTTPCookie("user", std::to_string(cookie_id))); + response.addCookie(mSession->getLoginCookie()); if (!form.empty()) { auto registerKeyChoice = form.get("passphrase", ""); @@ -90,7 +87,7 @@ label:not(.grd_radio_label) { Weiter
<% } else if(state == PAGE_ASK_PASSPHRASE) { %> -
+
Neue Gradido Adresse anlegen / wiederherstellen

Hast du schonmal ein Gradido Konto besessen?