mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
complete session timeout, found bug with session manager mutex and fix, found bug with long email verification code and fixed
This commit is contained in:
parent
3de1e21259
commit
cb47fe568e
@ -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<div class=\"grd_container\">\n";
|
||||
responseStream << "\t\t<h1>Login</h1>\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<fieldset class=\"grd_container_small\">\n";
|
||||
|
||||
@ -28,11 +28,13 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c
|
||||
std::string url_first_part;
|
||||
mRemoveGETParameters.extract(uri, url_first_part);
|
||||
|
||||
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
|
||||
Poco::Net::NameValueCollection cookies;
|
||||
@ -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);
|
||||
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);
|
||||
|
||||
@ -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 << "<body>\n";
|
||||
responseStream << "<div class=\"grd_container\">\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<h1>Einen neuen Account anlegen</h1>\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<div class=\"grd_text-max-width\">\n";
|
||||
responseStream << "\t\t\t<div class=\"grd_text\">\n";
|
||||
@ -116,16 +113,16 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::
|
||||
responseStream << "\t\t\t</div>\n";
|
||||
responseStream << "\t\t\t<div class=\"grd_textarea\">\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</div>\n";
|
||||
responseStream << "\t\t\t<a href=\"/saveKeys\">Weiter</a>\n";
|
||||
responseStream << "\t\t</div>\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<form method=\"POST\">\n";
|
||||
responseStream << "\t<form method=\"POST\" action=\"/passphrase\">\n";
|
||||
responseStream << "\t\t<fieldset class=\"grd_container_small\">\n";
|
||||
responseStream << "\t\t\t<legend>Neue Gradido Adresse anlegen / wiederherstellen</legend>\n";
|
||||
responseStream << "\t\t\t<p>Hast du schonmal ein Gradido Konto besessen?</p>\n";
|
||||
@ -138,7 +135,7 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::
|
||||
responseStream << "\t\t\t\t<label class=\"grd_radio_label\" for=\"passphrase-new-no\">Ja, bitte wiederherstellen!</label>\n";
|
||||
responseStream << "\t\t\t</p>\n";
|
||||
responseStream << "\t\t\t<textarea style=\"width:100%;height:100px\" name=\"passphrase-existing\">";
|
||||
#line 105 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
|
||||
#line 102 "I:\\Code\\C++\\Eigene_Projekte\\Gradido_LoginServer\\src\\cpsp\\passphrase.cpsp"
|
||||
responseStream << ( !form.empty() ? form.get("passphrase-existing", "") : "" );
|
||||
responseStream << "</textarea>\n";
|
||||
responseStream << "\t\t</fieldset>\n";
|
||||
@ -146,13 +143,13 @@ void PassphrasePage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::
|
||||
responseStream << "\t\t\n";
|
||||
responseStream << "\t</form>\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<div class=\"grd_text\">\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</div>\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 << "</div>\n";
|
||||
responseStream << "</body>\n";
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#include "SessionManager.h"
|
||||
#include "ErrorManager.h"
|
||||
#include "../ServerConfig.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
@ -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,36 +79,8 @@ bool SessionManager::isValid(const std::string& subject, SessionValidationTypes
|
||||
return *mValidations[validationType] == subject;
|
||||
}
|
||||
|
||||
|
||||
Session* SessionManager::getNewSession(int* handle)
|
||||
int SessionManager::generateNewUnusedHandle()
|
||||
{
|
||||
if (!mInitalized) {
|
||||
printf("[SessionManager::%s] not initialized any more\n", __FUNCTION__);
|
||||
return nullptr;
|
||||
}
|
||||
// lock
|
||||
mWorkingMutex.lock();
|
||||
|
||||
// check if we have an existing session ready to use
|
||||
if (mEmptyRequestStack.size() > 0) {
|
||||
int local_handle = mEmptyRequestStack.top();
|
||||
mEmptyRequestStack.pop();
|
||||
auto resultIt = mRequestSessionMap.find(local_handle);
|
||||
if (resultIt != mRequestSessionMap.end()) {
|
||||
Session* result = resultIt->second;
|
||||
result->reset();
|
||||
mWorkingMutex.unlock();
|
||||
|
||||
if (handle) {
|
||||
*handle = local_handle;
|
||||
}
|
||||
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 {
|
||||
@ -115,13 +89,63 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
} 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());
|
||||
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)
|
||||
{
|
||||
if (!mInitalized) {
|
||||
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
|
||||
while (mEmptyRequestStack.size() > 0) {
|
||||
int local_handle = mEmptyRequestStack.top();
|
||||
mEmptyRequestStack.pop();
|
||||
auto resultIt = mRequestSessionMap.find(local_handle);
|
||||
if (resultIt != mRequestSessionMap.end() && !resultIt->second->isActive()) {
|
||||
Session* result = resultIt->second;
|
||||
result->reset();
|
||||
mWorkingMutex.unlock();
|
||||
|
||||
if (handle) {
|
||||
*handle = local_handle;
|
||||
}
|
||||
result->setActive(true);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// else create new RequestSession Object
|
||||
// calculate random handle
|
||||
// check if already exist, if get new
|
||||
int newHandle = generateNewUnusedHandle();
|
||||
if (!newHandle) {
|
||||
mWorkingMutex.unlock();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto requestSession = new Session(newHandle);
|
||||
mRequestSessionMap.insert(std::pair<int, Session*>(newHandle, requestSession));
|
||||
|
||||
requestSession->setActive(true);
|
||||
mWorkingMutex.unlock();
|
||||
|
||||
if (handle) {
|
||||
@ -129,9 +153,9 @@ Session* SessionManager::getNewSession(int* handle)
|
||||
}
|
||||
|
||||
return requestSession;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
//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<int, Session*>(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 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<int> 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);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int CheckSessionTimeouted::run()
|
||||
{
|
||||
SessionManager::getInstance()->checkTimeoutSession();
|
||||
return 0;
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
57
src/cpp/tasks/PrepareEmailTask.cpp
Normal file
57
src/cpp/tasks/PrepareEmailTask.cpp
Normal file
@ -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;
|
||||
}
|
||||
23
src/cpp/tasks/PrepareEmailTask.h
Normal file
23
src/cpp/tasks/PrepareEmailTask.h
Normal file
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
%>
|
||||
|
||||
@ -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) {
|
||||
<a href="/saveKeys">Weiter</a>
|
||||
</div>
|
||||
<% } else if(state == PAGE_ASK_PASSPHRASE) { %>
|
||||
<form method="POST">
|
||||
<form method="POST" action="/passphrase">
|
||||
<fieldset class="grd_container_small">
|
||||
<legend>Neue Gradido Adresse anlegen / wiederherstellen</legend>
|
||||
<p>Hast du schonmal ein Gradido Konto besessen?</p>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user