use new user in login

This commit is contained in:
Dario 2020-06-09 12:14:51 +02:00
parent 2078705a80
commit 7d826fcacd
11 changed files with 166 additions and 25 deletions

View File

@ -47,6 +47,9 @@ public:
std::shared_lock<std::shared_mutex> _lock(mWorkingMutex);
return mEncryptionKeyHash == b.getKeyHashed();
}
inline bool operator == (const KeyHashed& hash) const {
return mEncryptionKeyHash == hash;
}
inline bool hasKey() const { std::shared_lock<std::shared_mutex> _lock(mWorkingMutex); return mEncryptionKey != nullptr; }

View File

@ -13,7 +13,8 @@ KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey)
{
//memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES);
// read pubkey from private key, so we are sure it is the correct pubkey for the private key
crypto_sign_ed25519_sk_to_pk(*privateKey, mSodiumPublic);
crypto_sign_ed25519_sk_to_pk(mSodiumPublic, *privateKey);
}
KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey)
@ -95,6 +96,7 @@ KeyPairEd25519* KeyPairEd25519::create(const Passphrase* passphrase)
}
crypto_sign_seed_keypair(key_pair->mSodiumPublic, *key_pair->mSodiumSecret, hash);
return key_pair;
// print hex for all keys for debugging

View File

@ -121,6 +121,9 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
}
response.redirect(ServerConfig::g_serverPath + "/passphrase");
return;
case USER_KEYS_DONT_MATCH:
addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it.")));
break;
case USER_NO_PRIVATE_KEY:
case USER_COMPLETE:
auto referer = request.find("Referer");
@ -222,20 +225,20 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
responseStream << " <div class=\"row\">\n";
responseStream << " <div class=\"col-12 logo-section\">\n";
responseStream << " <a href=\"";
#line 152 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "\" class=\"logo\">\n";
responseStream << "\t\t\t<picture>\n";
responseStream << "\t\t\t\t<source srcset=\"";
#line 154 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 157 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.webp\" type=\"image/webp\">\n";
responseStream << "\t\t\t\t<source srcset=\"";
#line 155 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 158 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" type=\"image/png\"> \n";
responseStream << "\t\t\t\t<img src=\"";
#line 156 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 159 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "img/logo_schrift.png\" alt=\"logo\" />\n";
responseStream << "\t\t\t</picture>\n";
@ -247,14 +250,14 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
responseStream << " <div class=\"grid\">\n";
responseStream << "\t\t\t<div class=\"center-ul-container\">\n";
responseStream << "\t\t\t\t";
#line 165 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 168 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( getErrorsHtml() );
responseStream << "\t \n";
responseStream << "\t\t\t</div>\n";
responseStream << " <div class=\"grid-body\">\n";
responseStream << " \n";
responseStream << "\t\t\t <!--<input type=\"hidden\" name=\"lang\" value=\"";
#line 169 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 172 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( LanguageManager::keyForLanguage(lang) );
responseStream << "\">-->\n";
responseStream << "\t\t\t ";
@ -294,46 +297,46 @@ void LoginPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::
// end include flags.cpsp
responseStream << "\n";
responseStream << "\t\t\t <form action=\"";
#line 171 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 174 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_serverPath );
responseStream << "/\" method=\"POST\">\n";
responseStream << " <div class=\"row display-block\">\n";
responseStream << " <div class=\"col-lg-7 col-md-8 col-sm-9 col-12 mx-auto form-wrapper\">\n";
responseStream << " <div class=\"form-group input-rounded\">\n";
responseStream << " <input type=\"text\" class=\"form-control\" name=\"login-email\" placeholder=\"";
#line 175 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("E-Mail") );
responseStream << "\" value=\"";
#line 175 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( presetEmail );
responseStream << "\"/>\n";
responseStream << " </div>\n";
responseStream << " <div class=\"form-group input-rounded\">\n";
responseStream << " <input type=\"password\" class=\"form-control\" name=\"login-password\" placeholder=\"";
#line 178 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 181 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Password") );
responseStream << "\" />\n";
responseStream << " </div>\n";
responseStream << " <button type=\"submit\" name=\"submit\" class=\"btn btn-primary btn-block\">";
#line 180 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 183 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext(" Login ") );
responseStream << "</button>\n";
responseStream << " <div class=\"signup-link\">\n";
responseStream << " <p>";
#line 182 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 185 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("You haven't any account yet? Please follow the link to create one.") );
responseStream << "</p>\n";
responseStream << " <a href=\"https://gradido.com\">";
#line 183 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Create New Account") );
responseStream << "</a>\n";
responseStream << " </div>\n";
responseStream << "\t\t\t\t\t<div class=\"reset-pwd-link\">\n";
responseStream << "\t\t\t\t\t\t<a href=\"";
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 189 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( ServerConfig::g_serverPath );
responseStream << "/resetPassword\">";
#line 186 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
#line 189 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\login.cpsp"
responseStream << ( langCatalog->gettext("Passwort vergessen") );
responseStream << "</a>\n";
responseStream << "\t\t\t\t\t</div>\n";

View File

@ -122,6 +122,42 @@ namespace controller {
return json;
}
int User::login(const std::string& password)
{
if (mPassword && mPassword->hasKey()) {
return 2;
}
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
auto authenticated_encryption = new AuthenticatedEncryption();
auto model = getModel();
assert(authenticated_encryption && model);
authenticated_encryption->createKey(model->getEmail(), password);
if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed()) {
MemoryBin* clear_private_key = nullptr;
auto priv_key_encrypted = model->getPrivateKeyEncrypted();
auto priv_key_bin = MemoryManager::getInstance()->getFreeMemory(priv_key_encrypted.size());
memcpy(*priv_key_bin, priv_key_encrypted.data(), priv_key_encrypted.size());
if (AuthenticatedEncryption::AUTH_DECRYPT_OK == authenticated_encryption->decrypt(priv_key_bin, &clear_private_key)) {
auto gradido_key_pair = new KeyPairEd25519(clear_private_key);
if (*gradido_key_pair != model->getPublicKey()) {
delete authenticated_encryption;
delete gradido_key_pair;
return -1;
}
if (mGradidoKeyPair) delete mGradidoKeyPair;
mGradidoKeyPair = gradido_key_pair;
if (mPassword) delete mPassword;
mPassword = authenticated_encryption;
return 1;
}
}
delete authenticated_encryption;
// password didn't match
return 0;
}
int User::setPassword(AuthenticatedEncryption* passwd)
{
std::unique_lock<std::shared_mutex> _lock(mSharedMutex);
@ -130,7 +166,14 @@ namespace controller {
if (mPassword)
{
if (mPassword == passwd) return 0;
// if keys matched
if (*mPassword == *passwd) {
// but separate objects
if (mPassword != passwd) {
delete passwd;
}
return 0;
}
// if password exist but gradido key pair not, try to load key pair
if ((!mGradidoKeyPair || !mGradidoKeyPair->hasPrivateKey()) && model->hasPrivateKeyEncrypted()) {
//if (!mGradidoKeyPair) mGradidoKeyPair = new KeyPairEd25519;
@ -143,24 +186,33 @@ namespace controller {
if (*mGradidoKeyPair != model->getPublicKey()) {
delete mGradidoKeyPair;
mGradidoKeyPair = nullptr;
delete passwd;
return -1;
}
}
}
delete passwd;
}
// replace old password with new
if (mPassword && mPassword != passwd) {
delete mPassword;
}
mPassword = passwd;
// set new encrypted password and hash
model->setPasswordHashed(mPassword->getKeyHashed());
auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword);
model->setPrivateKey(encryptedPrivateKey);
MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey);
int result = 2;
if (mGradidoKeyPair && mGradidoKeyPair->hasPrivateKey()) {
auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword);
model->setPrivateKey(encryptedPrivateKey);
MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey);
result = model->updatePrivkeyAndPasswordHash();
}
else {
model->updateIntoDB("password", mPassword->getKeyHashed());
}
// save changes to db
return model->updatePrivkeyAndPasswordHash();
return result;
}
}

View File

@ -40,13 +40,23 @@ namespace controller {
std::string getEmailWithNames();
const std::string& getPublicHex();
//! \brief check if password match saved password, long duration
//! \return 1 logged in
//! \return 2 already logged in
//! \return 0 password didn't match
//! \return -1 error saved public key didn't match with private key
//! - create authenticated encryption key from password and email
//! - compare hash with in db saved hash
int login(const std::string& password);
// ***********************************************************************************
// password related
//! \brief set authenticated encryption and save hash in db, should also re encrypt private key if exist
//! \brief set authenticated encryption and save hash in db, also re encrypt private key if exist
//! \param passwd take owner ship
//! \return 0 = new and current passwords are the same
//! \return 1 = password changed, private key re-encrypted and saved into db
//! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption
//! \return -1 = stored pubkey and private key didn't match
int setPassword(AuthenticatedEncryption* passwd);
@ -54,8 +64,14 @@ namespace controller {
std::shared_lock<std::shared_mutex> _lock(mSharedMutex);
return mPassword;
}
inline const KeyPairEd25519* getGradidoKeyPair() {
std::shared_lock<std::shared_mutex> _lock(mSharedMutex);
return mGradidoKeyPair;
}
protected:
User(model::table::User* dbModel);
std::string mPublicHex;

View File

@ -631,6 +631,7 @@ bool Session::isPwdValid(const std::string& pwd)
UserStates Session::loadUser(const std::string& email, const std::string& password)
{
static const char* functionName = "Session::loadUser";
auto observer = SingletonTaskObserver::getInstance();
if (email != "") {
if (observer->getTaskCount(email, TASK_OBSERVER_PASSWORD_CREATION) > 0) {
@ -638,7 +639,7 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo
}
}
//Profiler usedTime;
lock("Session::loadUser");
lock(functionName);
if (mSessionUser && mSessionUser->getEmail() != email) {
mSessionUser.assign(nullptr);
mNewUser.assign(nullptr);
@ -653,6 +654,20 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo
//mSessionUser = new User(email.data());
}
if (mSessionUser->getUserState() >= USER_LOADED_FROM_DB) {
int loginResult = mNewUser->login(password);
if (-1 == loginResult) {
addError(new Error(functionName, "error in user data set, saved pubkey didn't match extracted pubkey from private key"));
addError(new ParamError(functionName, "user email", mNewUser->getModel()->getEmail()));
sendErrorsAsEmail();
//unlock();
//return USER_KEYS_DONT_MATCH;
}
if (0 == loginResult) {
unlock();
return USER_PASSWORD_INCORRECT;
}
// can be removed if session user isn't used any more
if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) {
unlock();
return USER_PASSWORD_INCORRECT;

View File

@ -35,6 +35,7 @@ enum UserStates
USER_EMAIL_NOT_ACTIVATED,
USER_NO_KEYS,
USER_NO_PRIVATE_KEY,
USER_KEYS_DONT_MATCH,
USER_COMPLETE
};

View File

@ -0,0 +1,10 @@
#include "TestUser.h"
namespace controller {
void TestUser::SetUp()
{
}
//TEST_F(TestUser, )
}

View File

@ -0,0 +1,16 @@
#ifndef __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H
#define __GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H
#include "gtest/gtest.h"
namespace controller {
class TestUser : public ::testing::Test {
protected:
void SetUp() override;
};
}
#endif //__GRADIDO_LOGIN_SERVER_TEST_CONTROLLER_USER_H

View File

@ -4,7 +4,9 @@
#include "gtest/gtest.h"
#include "Poco/Util/PropertyFileConfiguration.h"
#include "Poco/Environment.h"
#include "../SingletonManager/ConnectionManager.h"
std::list<Test*> gTests;
@ -35,6 +37,24 @@ int load() {
return -2;
}
// start cpu scheduler
uint8_t worker_count = Poco::Environment::processorCount();
ServerConfig::g_CPUScheduler = new UniLib::controller::CPUSheduler(worker_count, "Default Worker");
ServerConfig::g_CryptoCPUScheduler = new UniLib::controller::CPUSheduler(2, "Crypto Worker");
// load up connection configs
// register MySQL connector
Poco::Data::MySQL::Connector::registerConnector();
//Poco::Data::MySQL::Connector::KEY;
auto conn = ConnectionManager::getInstance();
//conn->setConnection()
//printf("try connect login server mysql db\n");
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_LOGIN_SERVER);
//printf("try connect php server mysql \n");
conn->setConnectionsFromConfig(*test_config, CONNECTION_MYSQL_PHP_SERVER);
fillTests();
for (std::list<Test*>::iterator it = gTests.begin(); it != gTests.end(); it++)
{

View File

@ -100,6 +100,9 @@
}
response.redirect(ServerConfig::g_serverPath + "/passphrase");
return;
case USER_KEYS_DONT_MATCH:
addError(new Error(langCatalog->gettext("User"), langCatalog->gettext("Error in saved data, the server admin will look at it.")));
break;
case USER_NO_PRIVATE_KEY:
case USER_COMPLETE:
auto referer = request.find("Referer");