Refactor SDK Core to keep all users from all backends in memory All users for all backend are kept in memory. Added unit tests.
Closes: MAASMOB-63 Project: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/commit/cad661fe Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/cad661fe Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/cad661fe Branch: refs/heads/master Commit: cad661feca828cbc706c477ef660cd2e6b168498 Parents: 0c9b7fa Author: slav.klenov <[email protected]> Authored: Tue Apr 26 18:23:29 2016 +0300 Committer: slav.klenov <[email protected]> Committed: Wed Apr 27 17:00:56 2016 +0300 ---------------------------------------------------------------------- src/mpin_sdk.cpp | 371 +++++++++++++++++++++------------------------- src/mpin_sdk.h | 17 +-- src/version.h | 2 +- tests/unit_tests.cpp | 6 +- 4 files changed, 185 insertions(+), 211 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cad661fe/src/mpin_sdk.cpp ---------------------------------------------------------------------- diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp index 65608aa..41d34b3 100644 --- a/src/mpin_sdk.cpp +++ b/src/mpin_sdk.cpp @@ -121,11 +121,21 @@ User::User(const String& id, const String& deviceName) : m_id(id), m_deviceName( { } +String User::GetKey() const +{ + return String().Format("%s@%s", m_id.c_str(), m_backend.c_str()); +} + const String& User::GetId() const { return m_id; } +const String& User::GetBackend() const +{ + return m_backend; +} + const String& User::GetDeviceName() const { return m_deviceName; @@ -161,6 +171,11 @@ void User::CacheTimePermit(const String& timePermit, int date) m_timePermitCache.Set(timePermit, date); } +void User::SetBackend(const String& backend) +{ + m_backend = backend; +} + void User::SetStartedRegistration(const String& mpinIdHex, const String& regOTT) { m_state = STARTED_REGISTRATION; @@ -193,8 +208,9 @@ void User::Block() m_state = BLOCKED; } -Status User::RestoreState(const String& stateString, const String& mpinIdHex, const String& regOTT) +Status User::RestoreState(const String& stateString, const String& mpinIdHex, const String& regOTT, const String& backend) { + SetBackend(backend); SetStartedRegistration(mpinIdHex, regOTT); State state = StringToState(stateString); @@ -637,6 +653,12 @@ Status MPinSDK::Init(const StringMap& config, IContext* ctx) return Status(Status::FLOW_ERROR, String("CRYPTO_TEE crypto type is currently not supported")); } + Status s = LoadUsersFromStorage(); + if(s != Status::OK) + { + return s; + } + m_state = INITIALIZED; String backend = config.Get(CONFIG_BACKEND); @@ -738,12 +760,6 @@ Status MPinSDK::SetBackend(const String& backend, const String& rpsPrefix) return s; } - s = LoadUsersFromStorage(); - if(s != Status::OK) - { - return s; - } - m_state = BACKEND_SET; return Status(Status::OK); } @@ -828,7 +844,8 @@ Status MPinSDK::RequestRegistration(UserPtr user, const String& activateCode, co bool userIsNew = (user->GetState() == User::INVALID); if(userIsNew) { - AddUser(user); + user->SetBackend(MakeBackendKey(m_RPAServer)); + m_users[user->GetKey()] = user; } String mpinIdHex = response.GetJsonData().GetStringParam("mpinId"); @@ -837,7 +854,7 @@ Status MPinSDK::RequestRegistration(UserPtr user, const String& activateCode, co if(userIsNew || userDataChanged) { - user->SetStartedRegistration(mpinIdHex, regOTT); + user->SetStartedRegistration(mpinIdHex, regOTT); writeUsersToStorage = true; } @@ -1374,53 +1391,69 @@ Status MPinSDK::GetSessionDetails(const String& accessCode, OUT SessionDetails& return Status::OK; } -void MPinSDK::DeleteUser(UserPtr user) +Status MPinSDK::CheckUserState(UserPtr user, User::State expectedState) { - DeleteUser(user, m_RPAServer); -} + UsersMap::iterator i = m_users.find(user->GetKey()); + if(expectedState == User::INVALID) + { + if(i != m_users.end()) + { + return Status(Status::FLOW_ERROR, String().Format("User '%s' was already added", user->GetId().c_str())); + } -void MPinSDK::DeleteUser(INOUT UserPtr user, const String& backend) -{ - if(MakeBackendKey(backend) == MakeBackendKey(m_RPAServer)) + if(user->GetState() != User::INVALID) + { + return Status(Status::FLOW_ERROR, String().Format("Invalid '%s' user state: current state=%s, expected state=%s", + user->GetId().c_str(), User::StateToString( user->GetState() ).c_str(), User::StateToString( expectedState ).c_str())); + } + + return Status(Status::OK); + } + + if(i == m_users.end()) { - DeleteUser(user, m_RPAServer, m_users); + return Status(Status::FLOW_ERROR, String().Format("User '%s' was not added or has been deleted", user->GetId().c_str())); } - else + + if(user != i->second) { - UsersMap usersMap; - LoadUsersFromStorage(backend, usersMap); - DeleteUser(user, backend, usersMap); + return Status(Status::FLOW_ERROR, String().Format("Different user object with the '%s' id was previously added", user->GetId().c_str())); } -} -void MPinSDK::DeleteUser(INOUT UserPtr user, const String& backend, UsersMap& usersMap) -{ - UsersMap::iterator i = usersMap.find(user->GetId()); - //if(i == m_users.end() || user != i->second) - // TODO: Get back to the full user check after the SDK is refactored to store full user list (for all backends) - if(i == m_users.end()) + if(user->GetBackend() != MakeBackendKey(m_RPAServer)) { - return; + return Status(Status::FLOW_ERROR, String().Format("User '%s' is registered within a different backend than the current one", user->GetId().c_str())); } - m_crypto->DeleteRegOTT(i->second->GetMPinId()); - m_crypto->DeleteToken(i->second->GetMPinId()); - i->second->Invalidate(); - m_logoutData.erase(i->second); - usersMap.erase(i); - WriteUsersToStorage(backend, usersMap); + if(user->GetState() != expectedState) + { + return Status(Status::FLOW_ERROR, String().Format("Invalid '%s' user state: current state=%s, expected state=%s", + user->GetId().c_str(), User::StateToString( user->GetState() ).c_str(), User::StateToString( expectedState ).c_str())); + } + + return Status(Status::OK); } -Status MPinSDK::ListUsers(std::vector<UserPtr>& users) const +void MPinSDK::DeleteUser(UserPtr user) { - Status s = CheckIfBackendIsSet(); + Status s = CheckIfIsInitialized(); if(s != Status::OK) { - return s; + return; } - ListUsers(users, m_users); - return Status::OK; + UsersMap::iterator i = m_users.find(user->GetKey()); + if(i == m_users.end() || user != i->second) + { + return; + } + + m_crypto->DeleteRegOTT(i->second->GetMPinId()); + m_crypto->DeleteToken(i->second->GetMPinId()); + i->second->Invalidate(); + m_logoutData.erase(i->second); + m_users.erase(i); + WriteUsersToStorage(); } Status MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const @@ -1431,68 +1464,73 @@ Status MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend return s; } - UsersMap usersMap; - s = LoadUsersFromStorage(backend, usersMap); - if(s != Status::OK) + users.clear(); + users.reserve(m_users.size()); + + String backendKey = MakeBackendKey(backend); + + for(UsersMap::const_iterator i = m_users.begin(); i != m_users.end(); ++i) { - return s; + if(backendKey.empty() || backendKey == i->second->GetBackend()) + { + users.push_back(i->second); + } } - ListUsers(users, usersMap); return Status::OK; } -void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const UsersMap& usersMap) const +Status MPinSDK::ListUsers(OUT std::vector<UserPtr>& users) const { - users.clear(); - users.reserve(usersMap.size()); - for(UsersMap::const_iterator i = usersMap.begin(); i != usersMap.end(); ++i) + Status s = CheckIfBackendIsSet(); + if(s != Status::OK) { - users.push_back(i->second); + return s; } + + return ListUsers(users, m_RPAServer); } -void MPinSDK::AddUser(UserPtr user) +Status MPinSDK::ListAllUsers(OUT std::vector<UserPtr>& users) const { - m_users[user->GetId()] = user; + return ListUsers(users, ""); } -Status MPinSDK::CheckUserState(UserPtr user, User::State expectedState) +Status MPinSDK::ListBackends(OUT std::vector<String>& backends) const { - UsersMap::iterator i = m_users.find(user->GetId()); - if(expectedState == User::INVALID) + Status s = CheckIfIsInitialized(); + if(s != Status::OK) { - if(i != m_users.end()) - { - return Status(Status::FLOW_ERROR, String().Format("User '%s' was already added", user->GetId().c_str())); - } - - if(user->GetState() != User::INVALID) - { - return Status(Status::FLOW_ERROR, String().Format("Invalid '%s' user state: current state=%s, expected state=%s", - user->GetId().c_str(), User::StateToString( user->GetState() ).c_str(), User::StateToString( expectedState ).c_str())); - } - - return Status(Status::OK); + return s; } - if(i == m_users.end()) + backends.clear(); + + String data; + m_context->GetStorage(IStorage::NONSECURE)->GetData(data); + data.Trim(); + if(data.empty()) { - return Status(Status::FLOW_ERROR, String().Format("User '%s' was not added or has been deleted", user->GetId().c_str())); - } + return Status::OK; + } - if(user != i->second) + try { - return Status(Status::FLOW_ERROR, String().Format("Different user with the '%s' id was previously added", user->GetId().c_str())); - } + json::Object allBackendsObject; + std::istringstream str(data); + json::Reader::Read(allBackendsObject, str); - if(user->GetState() != expectedState) + for(json::Object::const_iterator i = allBackendsObject.Begin(); i != allBackendsObject.End(); ++i) + { + backends.push_back(i->name); + } + } + catch(const json::Exception& e) { - return Status(Status::FLOW_ERROR, String().Format("Invalid '%s' user state: current state=%s, expected state=%s", - user->GetId().c_str(), User::StateToString( user->GetState() ).c_str(), User::StateToString( expectedState ).c_str())); + return Status(Status::STORAGE_ERROR, e.what()); } - return Status(Status::OK); + return Status::OK; } String MPinSDK::MakeBackendKey(const String& backendServer) const @@ -1506,31 +1544,10 @@ String MPinSDK::MakeBackendKey(const String& backendServer) const Status MPinSDK::WriteUsersToStorage() const { - return WriteUsersToStorage(m_RPAServer, m_users); -} - -Status MPinSDK::WriteUsersToStorage(const String& backendServer, const UsersMap& usersMap) const -{ - IStorage* storage = m_context->GetStorage(IStorage::NONSECURE); - String data; - storage->GetData(data); - data.Trim(); - try { - json::Object allBackendsObject; - if(!data.empty()) - { - std::istringstream strIn(data); - json::Reader::Read(allBackendsObject, strIn); - } - - String backend = MakeBackendKey(backendServer); - - json::Object& rootObject = (json::Object&) allBackendsObject[backend]; - rootObject.Clear(); - - for (UsersMap::const_iterator i = usersMap.begin(); i != usersMap.end(); ++i) + json::Object rootObject; + for (UsersMap::const_iterator i = m_users.begin(); i != m_users.end(); ++i) { UserPtr user = i->second; @@ -1548,8 +1565,8 @@ Status MPinSDK::WriteUsersToStorage(const String& backendServer, const UsersMap& userObject["state"] = json::String(user->GetStateString()); - rootObject[user->GetMPinIdHex()] = userObject; - + ((json::Object&) rootObject[user->GetBackend()])[user->GetMPinIdHex()] = userObject; + Status s; switch(user->GetState()) { @@ -1567,32 +1584,26 @@ Status MPinSDK::WriteUsersToStorage(const String& backendServer, const UsersMap& { return s; } - } + } std::stringstream strOut; - json::Writer::Write(allBackendsObject, strOut); - storage->SetData(strOut.str()); - + json::Writer::Write(rootObject, strOut); + m_context->GetStorage(IStorage::NONSECURE)->SetData(strOut.str()); } catch(const json::Exception& e) { return Status(Status::STORAGE_ERROR, e.what()); } - - return Status(Status::OK); + + return Status::OK; } Status MPinSDK::LoadUsersFromStorage() { ClearUsers(); - return LoadUsersFromStorage(m_RPAServer, m_users); -} -Status MPinSDK::LoadUsersFromStorage(const String& backendServer, UsersMap& usersMap) const -{ - IStorage* storage = m_context->GetStorage(IStorage::NONSECURE); String data; - storage->GetData(data); + m_context->GetStorage(IStorage::NONSECURE)->GetData(data); data.Trim(); if(data.empty()) { @@ -1601,94 +1612,54 @@ Status MPinSDK::LoadUsersFromStorage(const String& backendServer, UsersMap& user try { - json::Object allBackendsObject; + json::Object rootObject; std::istringstream str(data); - json::Reader::Read(allBackendsObject, str); - - String backend = MakeBackendKey(backendServer); + json::Reader::Read(rootObject, str); - json::Object::const_iterator i = allBackendsObject.Find(backend); - if(i == allBackendsObject.End()) + for(json::Object::const_iterator backendsIter = rootObject.Begin(); backendsIter != rootObject.End(); ++backendsIter) { - return Status(Status::OK); - } + const json::Object& backendObject = (const json::Object&) backendsIter->element; - const json::Object& rootObject = (const json::Object&) i->element; - for(i = rootObject.Begin(); i != rootObject.End(); ++i) - { - const String& mpinIdHex = i->name; - String mpinId = util::HexDecode(mpinIdHex); - util::JsonObject mpinIdJson; - if(!mpinIdJson.Parse(mpinId.c_str())) - { - return Status(Status::STORAGE_ERROR, String().Format("Failed to parse mpinId json: '%s'", mpinId.c_str())); - } - const json::Object& userObject = (const json::Object&) i->element; - const std::string& id = ((const json::String&) mpinIdJson["userID"]).Value(); - std::string deviceName; - json::Object::const_iterator dni = userObject.Find("deviceName"); - if(dni != userObject.End()) + for(json::Object::const_iterator usersIter = backendObject.Begin(); usersIter != backendObject.End(); ++usersIter) { - deviceName = ((const json::String&) dni->element).Value(); + const String& mpinIdHex = usersIter->name; + String mpinId = util::HexDecode(mpinIdHex); + util::JsonObject mpinIdJson; + if(!mpinIdJson.Parse(mpinId.c_str())) + { + return Status(Status::STORAGE_ERROR, String().Format("Failed to parse mpinId json: '%s'", mpinId.c_str())); + } + const json::Object& userObject = (const json::Object&) usersIter->element; + const std::string& id = ((const json::String&) mpinIdJson["userID"]).Value(); + std::string deviceName; + json::Object::const_iterator dni = userObject.Find("deviceName"); + if(dni != userObject.End()) + { + deviceName = ((const json::String&) dni->element).Value(); + } + + String regOTT; + Status s = m_crypto->LoadRegOTT(mpinId, regOTT); + if(s != Status::OK) + { + return s; + } + + UserPtr user = MakeNewUser(id, deviceName); + s = user->RestoreState(((const json::String&) userObject["state"]).Value(), mpinIdHex, regOTT, backendsIter->name); + if(s != Status::OK) + { + return s; + } + + const json::Object& timePermitCacheObject = (const json::Object&) userObject["timePermitCache"]; + int date = (int) ((const json::Number&) timePermitCacheObject["date"]).Value(); + const String& timePermit = util::HexDecode(((const json::String&) timePermitCacheObject["timePermit"]).Value()); + + user->CacheTimePermit(timePermit, date); + + m_users[user->GetKey()] = user; } - - String regOTT; - Status s = m_crypto->LoadRegOTT(mpinId, regOTT); - if(s != Status::OK) - { - return s; - } - - UserPtr user = MakeNewUser(id, deviceName); - s = user->RestoreState(((const json::String&) userObject["state"]).Value(), mpinIdHex, regOTT); - if(s != Status::OK) - { - return s; - } - - const json::Object& timePermitCacheObject = (const json::Object&) userObject["timePermitCache"]; - int date = (int) ((const json::Number&) timePermitCacheObject["date"]).Value(); - const String& timePermit = util::HexDecode(((const json::String&) timePermitCacheObject["timePermit"]).Value()); - - user->CacheTimePermit(timePermit, date); - - usersMap[id] = user; - } - } - catch(const json::Exception& e) - { - return Status(Status::STORAGE_ERROR, e.what()); - } - - return Status(Status::OK); -} - -Status MPinSDK::ListBackends(OUT std::vector<String>& backends) const -{ - Status s = CheckIfIsInitialized(); - if(s != Status::OK) - { - return s; - } - - IStorage* storage = m_context->GetStorage(IStorage::NONSECURE); - String data; - storage->GetData(data); - data.Trim(); - if(data.empty()) - { - return Status::OK; - } - - try - { - json::Object allBackendsObject; - std::istringstream str(data); - json::Reader::Read(allBackendsObject, str); - - for(json::Object::const_iterator i = allBackendsObject.Begin(); i != allBackendsObject.End(); ++i) - { - backends.push_back(i->name); } } catch(const json::Exception& e) @@ -1699,11 +1670,6 @@ Status MPinSDK::ListBackends(OUT std::vector<String>& backends) const return Status::OK; } -const char * MPinSDK::GetVersion() -{ - return MPIN_SDK_V2_VERSION; -} - bool MPinSDK::CanLogout(UserPtr user) { LogoutDataMap::iterator i = m_logoutData.find(user); @@ -1773,3 +1739,8 @@ String MPinSDK::GetClientParam(const String& key) m_clientSettings[key].Accept(sv); return sv.GetData(); } + +const char * MPinSDK::GetVersion() +{ + return MPIN_SDK_V2_VERSION; +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cad661fe/src/mpin_sdk.h ---------------------------------------------------------------------- diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h index bd7a2f1..77ca6f6 100644 --- a/src/mpin_sdk.h +++ b/src/mpin_sdk.h @@ -173,29 +173,33 @@ public: }; const String& GetId() const; + const String& GetBackend() const; const String& GetMPinId() const; State GetState() const; private: friend class MPinSDK; User(const String& id, const String& deviceName); + String GetKey() const; const String& GetDeviceName() const; const String& GetMPinIdHex() const; const String& GetRegOTT() const; const TimePermitCache& GetTimePermitCache() const; void CacheTimePermit(const String& timePermit, int date); + void SetBackend(const String& backend); void SetStartedRegistration(const String& mpinIdHex, const String& regOTT); void SetActivated(); void SetRegistered(); void Invalidate(); void Block(); - Status RestoreState(const String& stateString, const String& mpinIdHex, const String& regOTT); + Status RestoreState(const String& stateString, const String& mpinIdHex, const String& regOTT, const String& backend); String GetStateString() const; static String StateToString(State state); static State StringToState(const String& stateString); private: String m_id; + String m_backend; String m_deviceName; State m_state; String m_mpinId; @@ -256,14 +260,14 @@ public: Status GetSessionDetails(const String& accessCode, OUT SessionDetails& sessionDetails); void DeleteUser(INOUT UserPtr user); - void DeleteUser(INOUT UserPtr user, const String& backend); - Status ListUsers(OUT std::vector<UserPtr>& users) const; Status ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const; + Status ListUsers(OUT std::vector<UserPtr>& users) const; + Status ListAllUsers(OUT std::vector<UserPtr>& users) const; Status ListBackends(OUT std::vector<String>& backends) const; - const char * GetVersion(); bool CanLogout(IN UserPtr user); bool Logout(IN UserPtr user); String GetClientParam(const String& key); + const char * GetVersion(); static const char *CONFIG_BACKEND; static const char *CONFIG_RPS_PREFIX; @@ -361,15 +365,10 @@ private: Status GetCertivoxTimePermitShare(INOUT UserPtr user, const util::JsonObject& cutomerTimePermitData, OUT String& resultTimePermit); bool ValidateAccessNumber(const String& accessNumber); bool ValidateAccessNumberChecksum(const String& accessNumber); - void AddUser(IN UserPtr user); Status CheckUserState(IN UserPtr user, User::State expectedState); - void DeleteUser(INOUT UserPtr user, const String& backend, UsersMap& usersMap); String MakeBackendKey(const String& backendServer) const; Status WriteUsersToStorage() const; - Status WriteUsersToStorage(const String& backendServer, const UsersMap& usersMap) const; Status LoadUsersFromStorage(); - Status LoadUsersFromStorage(const String& backendServer, UsersMap& usersMap) const; - void ListUsers(OUT std::vector<UserPtr>& users, const UsersMap& usersMap) const; static const char *DEFAULT_RPS_PREFIX; static const int AN_WITH_CHECKSUM_LEN = 7; http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cad661fe/src/version.h ---------------------------------------------------------------------- diff --git a/src/version.h b/src/version.h index a9b268d..1ae5af5 100644 --- a/src/version.h +++ b/src/version.h @@ -25,6 +25,6 @@ under the License. #define _MPIN_SDK_VERSION_H_ #define MPIN_SDK_VERSION "1.0.0" -#define MPIN_SDK_V2_VERSION "2.1.0" +#define MPIN_SDK_V2_VERSION "2.2.0" #endif // _MPIN_SDK_VERSION_H_ http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cad661fe/tests/unit_tests.cpp ---------------------------------------------------------------------- diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp index 055d7ee..f963195 100644 --- a/tests/unit_tests.cpp +++ b/tests/unit_tests.cpp @@ -191,10 +191,14 @@ BOOST_AUTO_TEST_CASE(testUsers2) } users.clear(); + sdk.ListAllUsers(users); + BOOST_CHECK_EQUAL(users.size(), 1); + + users.clear(); sdk.ListUsers(users, backend); BOOST_CHECK_EQUAL(users.size(), 1); - sdk.DeleteUser(users[0], backend); + sdk.DeleteUser(users[0]); users.clear(); sdk.ListUsers(users, backend); BOOST_CHECK(users.empty());
