You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by sa...@apache.org on 2016/09/10 13:37:58 UTC

[14/22] incubator-milagro-mfa-sdk-core git commit: Refactor SDK Core to keep all users from all backends in memory

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 <sl...@certivox.com>
Authored: Tue Apr 26 18:23:29 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
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());