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:45 UTC

[01/22] incubator-milagro-mfa-sdk-core git commit: Add ListUsers for specific backend and ListBackends functions.

Repository: incubator-milagro-mfa-sdk-core
Updated Branches:
  refs/heads/master 441cabaa9 -> cadbe7c8d


Add ListUsers for specific backend and ListBackends functions.

Added ListUsers(backend) and ListBackends functions.
Fixed unit_tests and added ListUsers(backend) and ListBackends tests.

Closes: MAASMOB-27


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/7815a973
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/7815a973
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/7815a973

Branch: refs/heads/master
Commit: 7815a9734835ccb82df3814b6c30c6378706a438
Parents: 441caba
Author: slav.klenov <sl...@certivox.com>
Authored: Tue Mar 29 15:14:38 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
Committed: Tue Mar 29 15:14:38 2016 +0300

----------------------------------------------------------------------
 project/visual_studio_2012/unit_tests.vcxproj |  1 +
 src/mpin_sdk.cpp                              | 51 +++++++++++++++++++---
 src/mpin_sdk.h                                | 13 +++---
 tests/cmdline_test.cpp                        | 22 ++++++++++
 tests/unit_tests.cpp                          | 21 ++++++---
 5 files changed, 93 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/7815a973/project/visual_studio_2012/unit_tests.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2012/unit_tests.vcxproj b/project/visual_studio_2012/unit_tests.vcxproj
index 65166e2..2160b56 100644
--- a/project/visual_studio_2012/unit_tests.vcxproj
+++ b/project/visual_studio_2012/unit_tests.vcxproj
@@ -55,6 +55,7 @@
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <SubSystem>Console</SubSystem>
     </Link>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/7815a973/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index 3c76dd3..a441448 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -1327,11 +1327,23 @@ void MPinSDK::DeleteUser(UserPtr user)
     m_logoutData.erase(user);
 }
 
-void MPinSDK::ListUsers(std::vector<UserPtr>& users)
+void MPinSDK::ListUsers(std::vector<UserPtr>& users) const
+{
+    ListUsers(users, m_users);
+}
+
+void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const
+{
+    UsersMap usersMap;
+    LoadUsersFromStorage(backend, usersMap);
+    ListUsers(users, usersMap);
+}
+
+void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const UsersMap& usersMap) const
 {
     users.clear();
-    users.reserve(m_users.size());
-    for(UsersMap::iterator i = m_users.begin(); i != m_users.end(); ++i)
+    users.reserve(usersMap.size());
+    for(UsersMap::const_iterator i = usersMap.begin(); i != usersMap.end(); ++i)
     {
         users.push_back(i->second);
     }
@@ -1458,7 +1470,11 @@ Status MPinSDK::WriteUsersToStorage()
 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);
@@ -1474,7 +1490,7 @@ Status MPinSDK::LoadUsersFromStorage()
         std::istringstream str(data);
         json::Reader::Read(allBackendsObject, str);
 
-        String backend = m_RPAServer;
+        String backend = backendServer;
         backend.ReplaceAll("https://", "");
         backend.ReplaceAll("http://", "");
 
@@ -1523,7 +1539,7 @@ Status MPinSDK::LoadUsersFromStorage()
 
             user->CacheTimePermit(timePermit, date);
 
-            m_users[id] = user;
+            usersMap[id] = user;
 		}
     }
     catch(const json::Exception& e)
@@ -1534,6 +1550,31 @@ Status MPinSDK::LoadUsersFromStorage()
 	return Status(Status::OK);
 }
 
+void MPinSDK::ListBackends(OUT std::vector<String>& backends) const
+{
+	IStorage* storage = m_context->GetStorage(IStorage::NONSECURE);
+	String data;
+	storage->GetData(data);
+    data.Trim();
+	if(data.empty())
+    {
+		return;
+	}
+
+	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&) {}
+}
+
 const char * MPinSDK::GetVersion()
 {
     return MPIN_SDK_V2_VERSION;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/7815a973/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index 7644c83..902189a 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -178,7 +178,6 @@ public:
 
     private:
         friend class MPinSDK;
-        friend class MPinSDKv2;
         User(const String& id, const String& deviceName);
         const String& GetDeviceName() const;
         const String& GetMPinIdHex() const;
@@ -245,7 +244,9 @@ public:
     Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);
 
     void DeleteUser(INOUT UserPtr user);
-    void ListUsers(OUT std::vector<UserPtr>& users);
+    void ListUsers(OUT std::vector<UserPtr>& users) const;
+    void ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;
+    void ListBackends(OUT std::vector<String>& backends) const;
     const char * GetVersion();
     bool CanLogout(IN UserPtr user);
     bool Logout(IN UserPtr user);
@@ -330,6 +331,9 @@ private:
 	};
 
 private:
+    typedef std::map<String, UserPtr> UsersMap;
+    typedef std::map<UserPtr, LogoutData> LogoutDataMap;
+    
     bool IsInitilized() const;
     bool IsBackendSet() const;
     Status CheckIfIsInitialized() const;
@@ -347,14 +351,13 @@ private:
     Status CheckUserState(IN UserPtr user, User::State expectedState);
 	Status WriteUsersToStorage();
 	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;
 
 private:
-    typedef std::map<String, UserPtr> UsersMap;
-    typedef std::map<UserPtr, LogoutData> LogoutDataMap;
-    
     State m_state;
     IContext *m_context;
     IMPinCrypto *m_crypto;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/7815a973/tests/cmdline_test.cpp
----------------------------------------------------------------------
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index aae0b13..7ababfa 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -36,6 +36,7 @@ struct Backend
 };
 
 static void TestBackend(const MPinSDK& sdk, const char *backend, const char *rpsPrefix);
+static void TestListBackendAndUsers(const MPinSDK& sdk);
 
 int main(int argc, char *argv[])
 {
@@ -85,6 +86,8 @@ int main(int argc, char *argv[])
         return 0;
     }
 
+    TestListBackendAndUsers(sdk);
+
     vector<MPinSDK::UserPtr> users;
     sdk.ListUsers(users);
     MPinSDK::UserPtr user;
@@ -194,3 +197,22 @@ static void TestBackend(const MPinSDK& sdk, const char *beckend, const char *rps
         cout << "Backend test OK: " << beckend << endl;
     }
 }
+
+static void TestListBackendAndUsers(const MPinSDK& sdk)
+{
+    vector<MPinSDK::String> backends;
+    sdk.ListBackends(backends);
+
+    cout << endl << "TestListBackendAndUsers: Got " << backends.size() << " backends" << endl;
+
+    for(vector<MPinSDK::String>::const_iterator backend = backends.begin(); backend != backends.end(); ++backend)
+    {
+        cout << "    Listing users for backend '" << *backend << "':" << endl;
+        vector<MPinSDK::UserPtr> users;
+        sdk.ListUsers(users, *backend);
+        for(vector<MPinSDK::UserPtr>::iterator user = users.begin(); user != users.end(); ++user)
+        {
+            cout << "        - " << (*user)->GetId() << endl;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/7815a973/tests/unit_tests.cpp
----------------------------------------------------------------------
diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp
index 1950189..6892270 100644
--- a/tests/unit_tests.cpp
+++ b/tests/unit_tests.cpp
@@ -35,7 +35,7 @@ typedef MPinSDK::String String;
 static AutoContext context;
 static MPinSDK sdk;
 static MPinSDK::StringMap config;
-static const char *backend = "http://192.168.98.89:8005";
+static const char *backend = "http://192.168.98.98:8005";
 
 using namespace boost::unit_test;
 
@@ -76,10 +76,6 @@ BOOST_AUTO_TEST_CASE(testNoInit)
     BOOST_CHECK_EQUAL(s, Status::FLOW_ERROR);
     BOOST_CHECK_EQUAL(user->GetState(), User::INVALID);
 
-    s = sdk.VerifyUser(user, "", "");
-    BOOST_CHECK_EQUAL(s, Status::FLOW_ERROR);
-    BOOST_CHECK_EQUAL(user->GetState(), User::INVALID);
-
     s = sdk.ConfirmRegistration(user);
     BOOST_CHECK_EQUAL(s, Status::FLOW_ERROR);
     BOOST_CHECK_EQUAL(user->GetState(), User::INVALID);
@@ -183,6 +179,21 @@ BOOST_AUTO_TEST_CASE(testUsers2)
     sdk.ListUsers(users);
     BOOST_CHECK_EQUAL(users.size(), 1);
 
+    std::vector<String> backends;
+    sdk.ListBackends(backends);
+    BOOST_CHECK_EQUAL(backends.size(), 1);
+
+    if(!backends.empty())
+    {
+        users.clear();
+        sdk.ListUsers(users, backends[0]);
+        BOOST_CHECK_EQUAL(users.size(), 1);
+    }
+
+    users.clear();
+    sdk.ListUsers(users, backend);
+    BOOST_CHECK_EQUAL(users.size(), 1);
+
     sdk.DeleteUser(user);
 
     BOOST_MESSAGE("    testUsers2 finished");


[10/22] incubator-milagro-mfa-sdk-core git commit: Add DeleteUser function for specific backend.

Posted by sa...@apache.org.
Add DeleteUser function for specific backend.

Implemented DeleteUser(user, backend) function.
Fixed bug in shared_ptr class.
Added test for the DeleteUser(user, backend) function.

Closes: MAASMOB-59


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/5c5a025f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/5c5a025f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/5c5a025f

Branch: refs/heads/master
Commit: 5c5a025f04a43113e546adadbdf78a3ad7963102
Parents: e79c120
Author: slav.klenov <sl...@certivox.com>
Authored: Mon Apr 25 17:45:09 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
Committed: Mon Apr 25 17:45:09 2016 +0300

----------------------------------------------------------------------
 src/cv_shared_ptr.h  | 24 ++++++++++++--------
 src/mpin_sdk.cpp     | 57 ++++++++++++++++++++++++++++++++++++-----------
 src/mpin_sdk.h       |  6 ++++-
 tests/unit_tests.cpp |  5 ++++-
 4 files changed, 68 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/5c5a025f/src/cv_shared_ptr.h
----------------------------------------------------------------------
diff --git a/src/cv_shared_ptr.h b/src/cv_shared_ptr.h
index 6f803c6..8201e18 100644
--- a/src/cv_shared_ptr.h
+++ b/src/cv_shared_ptr.h
@@ -185,15 +185,6 @@ public:
         return *operator->();
     }
 
-    operator bool() const
-    {
-        if (!holder)
-        {
-            return false;
-        }
-        return holder->target != NULL;
-    }
-
     element_type* get() const
     {
         return operator->();
@@ -203,6 +194,21 @@ private:
     Holder* holder;
 };
 
+template <typename T, typename U> bool operator==(const shared_ptr<T>& lhs, const shared_ptr<U>& rhs)
+{
+    return lhs.get() == rhs.get();
+}
+
+template <typename T, typename U> bool operator!=(const shared_ptr<T>& lhs, const shared_ptr<U>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template <typename T> bool operator<(const shared_ptr<T>& lhs, const shared_ptr<T>& rhs)
+{
+    return lhs.get() < rhs.get();
+}
+
 template<typename T> shared_ptr<T> make_shared() { return shared_ptr<T>(new T()); }
 template<typename T, typename Arg1> shared_ptr<T> make_shared(const Arg1& arg1) { return shared_ptr<T>(new T(arg1)); }
 template<typename T, typename Arg1, typename Arg2> shared_ptr<T> make_shared(const Arg1& arg1, const Arg2& arg2) { return shared_ptr<T>(new T(arg1, arg2)); }

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/5c5a025f/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index dcaecbe..ad86a75 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -1361,8 +1361,29 @@ String MPinSDK::GetPrerollUserId(const String& accessCode)
 
 void MPinSDK::DeleteUser(UserPtr user)
 {
-    UsersMap::iterator i = m_users.find(user->GetId());
-    if(i == m_users.end() || user != i->second)
+    DeleteUser(user, m_RPAServer);
+}
+
+void MPinSDK::DeleteUser(INOUT UserPtr user, const String& backend)
+{
+    if(MakeBackendKey(backend) == MakeBackendKey(m_RPAServer))
+    {
+        DeleteUser(user, m_RPAServer, m_users);
+    }
+    else
+    {
+        UsersMap usersMap;
+        LoadUsersFromStorage(backend, usersMap);
+        DeleteUser(user, backend, usersMap);
+    }
+}
+
+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())
     {
         return;
     }
@@ -1370,9 +1391,9 @@ void MPinSDK::DeleteUser(UserPtr user)
 	m_crypto->DeleteRegOTT(i->second->GetMPinId());
     m_crypto->DeleteToken(i->second->GetMPinId());
     i->second->Invalidate();
-    m_users.erase(i);
-    WriteUsersToStorage();
-    m_logoutData.erase(user);
+    m_logoutData.erase(i->second);
+    usersMap.erase(i);
+    WriteUsersToStorage(backend, usersMap);
 }
 
 Status MPinSDK::ListUsers(std::vector<UserPtr>& users) const
@@ -1459,7 +1480,21 @@ Status MPinSDK::CheckUserState(UserPtr user, User::State expectedState)
     return Status(Status::OK);
 }
 
-Status MPinSDK::WriteUsersToStorage()
+String MPinSDK::MakeBackendKey(const String& backendServer) const
+{
+    String backend = backendServer;
+    backend.ReplaceAll("https://", "");
+    backend.ReplaceAll("http://", "");
+    backend.TrimRight("/");
+    return backend;
+}
+
+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;
@@ -1475,14 +1510,12 @@ Status MPinSDK::WriteUsersToStorage()
             json::Reader::Read(allBackendsObject, strIn);
         }
 
-        String backend = m_RPAServer;
-        backend.ReplaceAll("https://", "");
-        backend.ReplaceAll("http://", "");
+        String backend = MakeBackendKey(backendServer);
 
         json::Object& rootObject = (json::Object&) allBackendsObject[backend];
         rootObject.Clear();
 		
-		for (UsersMap::iterator i = m_users.begin(); i != m_users.end(); ++i)
+		for (UsersMap::const_iterator i = usersMap.begin(); i != usersMap.end(); ++i)
 		{
 			UserPtr user = i->second;
 
@@ -1557,9 +1590,7 @@ Status MPinSDK::LoadUsersFromStorage(const String& backendServer, UsersMap& user
         std::istringstream str(data);
         json::Reader::Read(allBackendsObject, str);
 
-        String backend = backendServer;
-        backend.ReplaceAll("https://", "");
-        backend.ReplaceAll("http://", "");
+        String backend = MakeBackendKey(backendServer);
 
         json::Object::const_iterator i = allBackendsObject.Find(backend);
         if(i == allBackendsObject.End())

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/5c5a025f/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index ec69d58..f5f77b6 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -246,6 +246,7 @@ public:
     String GetPrerollUserId(const String& accessCode);
 
     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 ListBackends(OUT std::vector<String>& backends) const;
@@ -351,7 +352,10 @@ private:
     bool ValidateAccessNumberChecksum(const String& accessNumber);
     void AddUser(IN UserPtr user);
     Status CheckUserState(IN UserPtr user, User::State expectedState);
-	Status WriteUsersToStorage();
+    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;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/5c5a025f/tests/unit_tests.cpp
----------------------------------------------------------------------
diff --git a/tests/unit_tests.cpp b/tests/unit_tests.cpp
index 6892270..055d7ee 100644
--- a/tests/unit_tests.cpp
+++ b/tests/unit_tests.cpp
@@ -194,7 +194,10 @@ BOOST_AUTO_TEST_CASE(testUsers2)
     sdk.ListUsers(users, backend);
     BOOST_CHECK_EQUAL(users.size(), 1);
 
-    sdk.DeleteUser(user);
+    sdk.DeleteUser(users[0], backend);
+    users.clear();
+    sdk.ListUsers(users, backend);
+    BOOST_CHECK(users.empty());
 
     BOOST_MESSAGE("    testUsers2 finished");
 }


[17/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #12 in MM/mpin-sdk-core from feature/custom_headers to master

Posted by sa...@apache.org.
Merge pull request #12 in MM/mpin-sdk-core from feature/custom_headers to master

* commit '50a8169a7062b963e39e9fd0dc895719d51e261b':
  Add custom headers to MPinSDK


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/a17c6b3d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/a17c6b3d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/a17c6b3d

Branch: refs/heads/master
Commit: a17c6b3d45aa2e952fa499dca5d193467d485486
Parents: ac6536c 50a8169
Author: Slav Klenov <sl...@certivox.com>
Authored: Wed Jul 13 13:55:21 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Wed Jul 13 13:55:21 2016 +0200

----------------------------------------------------------------------
 .gitignore                                      |   3 +
 ext/cvshared/cpp/include/CvTime.h               |  15 +-
 project/visual_studio_2015/mpin_sdk.sln         |  41 ++++
 project/visual_studio_2015/mpin_sdk.vcxproj     | 145 +++++++++++++
 .../visual_studio_2015/mpin_sdk.vcxproj.filters | 204 +++++++++++++++++++
 .../visual_studio_2015/mpin_sdk_test.vcxproj    |  93 +++++++++
 .../mpin_sdk_test.vcxproj.filters               |  24 +++
 .../mpin_sdk_test_common.vcxproj                |  90 ++++++++
 .../mpin_sdk_test_common.vcxproj.filters        |  36 ++++
 project/visual_studio_2015/unit_tests.vcxproj   |  94 +++++++++
 .../unit_tests.vcxproj.filters                  |  24 +++
 src/mpin_sdk.cpp                                |  16 +-
 src/mpin_sdk.h                                  |   2 +
 13 files changed, 776 insertions(+), 11 deletions(-)
----------------------------------------------------------------------



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

Posted by sa...@apache.org.
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());


[03/22] incubator-milagro-mfa-sdk-core git commit: Add support for authentication without time permits

Posted by sa...@apache.org.
Add support for authentication without time permits

Added code to ignore time permits when usePermits = false is specified in client settings.
Fixed bug in JSON parser when reading excaped symbols.

Closes: MAASMOB-29


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/d0631f60
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/d0631f60
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/d0631f60

Branch: refs/heads/master
Commit: d0631f6010719ab9fe9f019039bfab1f1badfece
Parents: ad02ce3
Author: slav.klenov <sl...@certivox.com>
Authored: Wed Mar 30 17:12:56 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
Committed: Wed Mar 30 17:12:56 2016 +0300

----------------------------------------------------------------------
 src/json/reader.inl         | 11 +++++++----
 src/mpin_crypto_non_tee.cpp | 30 ++++++++++++++++++------------
 src/mpin_sdk.cpp            | 21 ++++++++++++++++-----
 tests/cmdline_test.cpp      |  1 +
 4 files changed, 42 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/d0631f60/src/json/reader.inl
----------------------------------------------------------------------
diff --git a/src/json/reader.inl b/src/json/reader.inl
index c903f75..9211675 100644
--- a/src/json/reader.inl
+++ b/src/json/reader.inl
@@ -303,10 +303,13 @@ inline std::string Reader::MatchExpectedString(InputStream& inputStream, const s
 }
 
 static void ConsumeUnicode(std::istream& str, std::vector<utf8::uint16_t>& uni16) {
-    str >> std::hex;
-    utf8::uint16_t cp;
-    str >> cp;
-    str >> std::dec;
+    char bytes[4];
+    memset(bytes, 0, sizeof(bytes));
+    str.get(bytes[0]);
+    str.get(bytes[1]);
+    str.get(bytes[2]);
+    str.get(bytes[3]);
+    utf8::uint16_t cp = (bytes[0] - '0') << 12 | (bytes[1] - '0') << 8 | (bytes[2] - '0') << 4 | (bytes[3] - '0');
     uni16.push_back(cp);
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/d0631f60/src/mpin_crypto_non_tee.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_crypto_non_tee.cpp b/src/mpin_crypto_non_tee.cpp
index cd6848a..77cdbc0 100644
--- a/src/mpin_crypto_non_tee.cpp
+++ b/src/mpin_crypto_non_tee.cpp
@@ -201,20 +201,26 @@ Status MPinCryptoNonTee::AuthenticatePass1(UserPtr user, const String& pin, int
         return Status(Status::CRYPTO_ERROR, String("Session is not opened or not initialized"));
     }
 
-    // Combine time permit shares
-    if(timePermitShares.size() != 2)
-    {
-        return Status(Status::CRYPTO_ERROR, String().Format("Expecting 2 time permit shares (provided=%d)", (int) timePermitShares.size()));
-    }
-
-    Octet tp1(timePermitShares[0]);
-    Octet tp2(timePermitShares[1]);
     Octet timePermit(Octet::TOKEN_SIZE);
 
-    int res = MPIN_RECOMBINE_G1(&tp1, &tp2, &timePermit);
-    if(res)
+    // Valid date (date != 0) means authentication *with* time permit and 2 time permit shares are expected
+    // Invalid date (date == 0) means authentication with *no* time permit and time permit shares are ignored
+    if(date != 0)
     {
-        return Status(Status::CRYPTO_ERROR, String().Format("MPIN_RECOMBINE_G1() failed with code %d", res));
+        // Combine time permit shares
+        if(timePermitShares.size() != 2)
+        {
+            return Status(Status::CRYPTO_ERROR, String().Format("Expecting 2 time permit shares (provided=%d)", (int) timePermitShares.size()));
+        }
+
+        Octet tp1(timePermitShares[0]);
+        Octet tp2(timePermitShares[1]);
+
+        int res = MPIN_RECOMBINE_G1(&tp1, &tp2, &timePermit);
+        if(res)
+        {
+            return Status(Status::CRYPTO_ERROR, String().Format("MPIN_RECOMBINE_G1() failed with code %d", res));
+        }
     }
 
     // Get the stored token
@@ -246,7 +252,7 @@ Status MPinCryptoNonTee::AuthenticatePass1(UserPtr user, const String& pin, int
     Octet ut(Octet::TOKEN_SIZE);
 
     // Authentication pass 1
-    res = MPIN_CLIENT_1(date, &cid, &rng, &x, pin.GetHash(), &token, &clientSecret, &u, &ut, &timePermit);
+    int res = MPIN_CLIENT_1(date, &cid, &rng, &x, pin.GetHash(), &token, &clientSecret, &u, &ut, &timePermit);
     if(res)
     {
         return Status(Status::CRYPTO_ERROR, String().Format("MPIN_CLIENT_1() failed with code %d", res));

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/d0631f60/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index a441448..3f94c73 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -985,6 +985,12 @@ Status MPinSDK::StartAuthentication(INOUT UserPtr user)
         return s;
     }
 
+    bool useTimePermits = m_clientSettings.GetBoolParam("usePermits", true);
+    if(!useTimePermits)
+    {
+        return Status::OK;
+    }
+
     // Request a time permit share from the customer's D-TA and a signed request for a time permit share from CertiVox's D-TA.
     String mpinIdHex = user->GetMPinIdHex();
     String url = String().Format("%s/%s", m_clientSettings.GetStringParam("timePermitsURL"), mpinIdHex.c_str());
@@ -1073,8 +1079,10 @@ Status MPinSDK::FinishAuthenticationImpl(INOUT UserPtr user, const String& pin,
         return s;
     }
 
+    bool useTimePermits = m_clientSettings.GetBoolParam("usePermits", true);
+
     // Check if time permit was obtained from StartAuthentication
-    if(user->m_timePermitShare1.empty() || user->m_timePermitShare2.empty())
+    if(useTimePermits && (user->m_timePermitShare1.empty() || user->m_timePermitShare2.empty()))
     {
         return Status(Status::FLOW_ERROR, String().Format("Cannot finish user '%s' authentication: Invalid time permit", user->GetId().c_str()));
     }
@@ -1088,10 +1096,13 @@ Status MPinSDK::FinishAuthenticationImpl(INOUT UserPtr user, const String& pin,
     }
 
     std::vector<String> timePermitShares;
-    timePermitShares.push_back(user->m_timePermitShare1);
-    timePermitShares.push_back(user->m_timePermitShare2);
-
-	int date =  user->GetTimePermitCache().GetDate();
+    int date = 0;
+    if(useTimePermits)
+    {
+        timePermitShares.push_back(user->m_timePermitShare1);
+        timePermitShares.push_back(user->m_timePermitShare2);
+    	date = user->GetTimePermitCache().GetDate();
+    }
 	
     // Authentication pass 1
     String u, ut;

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/d0631f60/tests/cmdline_test.cpp
----------------------------------------------------------------------
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index 7ababfa..6957afd 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -45,6 +45,7 @@ int main(int argc, char *argv[])
     Backend backends[] = 
     {
         {"https://m-pindemo.certivox.org"},
+        //{"http://192.168.10.159:8001"},
         //{"http://ec2-54-77-232-113.eu-west-1.compute.amazonaws.com", "/rps/"},
         //{"https://mpindemo-qa-v3.certivox.org", "rps"},
     };


[20/22] incubator-milagro-mfa-sdk-core git commit: Add CLIENT_SECRET_EXPIRED sdk status code

Posted by sa...@apache.org.
Add CLIENT_SECRET_EXPIRED sdk status code

Return CLIENT_SECRET_EXPIRED sdk status code in response to HTTP_CONFLICT(409) response from RPA server when authenticating.


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/fbb695cd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/fbb695cd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/fbb695cd

Branch: refs/heads/master
Commit: fbb695cd07ec50566c685bc61b260a107cc9f5c1
Parents: d388206
Author: Slav Klenov <sl...@miracl.com>
Authored: Fri Sep 2 14:57:29 2016 +0300
Committer: Slav Klenov <sl...@miracl.com>
Committed: Fri Sep 2 14:57:29 2016 +0300

----------------------------------------------------------------------
 src/mpin_sdk.cpp | 5 +++++
 src/mpin_sdk.h   | 2 ++
 2 files changed, 7 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/fbb695cd/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index d438156..9077fac 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -485,6 +485,11 @@ Status MPinSDK::HttpResponse::TranslateToMPinStatus(Context context)
             m_mpinStatus.SetStatusCode(Status::IDENTITY_NOT_AUTHORIZED);
             m_mpinStatus.SetErrorMessage("Identity not authorized");
         }
+        else if (m_httpStatus == HTTP_CONFLICT)
+        {
+            m_mpinStatus.SetStatusCode(Status::CLIENT_SECRET_EXPIRED);
+            m_mpinStatus.SetErrorMessage("Client secret expired");
+        }
         break;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/fbb695cd/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index 37aa636..6785143 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -128,6 +128,7 @@ public:
             HTTP_SERVER_ERROR, // Remote error, that was not reduced to one of the above - the remote server returned internal server error status (5xx)
             HTTP_REQUEST_ERROR, // Remote error, that was not reduced to one of the above - invalid data sent to server, the remote server returned 4xx error status
             BAD_USER_AGENT, // Remote error - user agent not supported
+            CLIENT_SECRET_EXPIRED, // Remote error - re-registration required because server master secret expired
         };
 
         Status();
@@ -285,6 +286,7 @@ private:
         static const int HTTP_FORBIDDEN = 403;
         static const int HTTP_NOT_ACCEPTABLE = 406;
         static const int HTTP_REQUEST_TIMEOUT = 408;
+        static const int HTTP_CONFLICT = 409;
         static const int HTTP_GONE = 410;
         static const int HTTP_PRECONDITION_FAILED = 412;
 


[22/22] incubator-milagro-mfa-sdk-core git commit: Add documentation

Posted by sa...@apache.org.
Add documentation


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/cadbe7c8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/cadbe7c8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/cadbe7c8

Branch: refs/heads/master
Commit: cadbe7c8d4287efbba34e1c62e6915d75b4b6c61
Parents: e631fb2
Author: Simeon Aladjem <si...@miracl.com>
Authored: Sat Sep 10 16:30:30 2016 +0300
Committer: Simeon Aladjem <si...@miracl.com>
Committed: Sat Sep 10 16:30:30 2016 +0300

----------------------------------------------------------------------
 M-Pin SDK - Authentication flow.png             | Bin 0 -> 34457 bytes
 M-Pin SDK - Authentication flow.xml             |   2 +
 ...- Authentication to Browser Session flow.png | Bin 0 -> 50192 bytes
 ...- Authentication to Browser Session flow.xml |   2 +
 M-Pin SDK - Registration flow.png               | Bin 0 -> 36643 bytes
 M-Pin SDK - Registration flow.xml               |   2 +
 Mobile-SDK-Architecture.png                     | Bin 0 -> 26171 bytes
 README.md                                       | 359 ++++++++++++++++++-
 8 files changed, 364 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Authentication flow.png
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication flow.png b/M-Pin SDK - Authentication flow.png
new file mode 100644
index 0000000..c386255
Binary files /dev/null and b/M-Pin SDK - Authentication flow.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Authentication flow.xml
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication flow.xml b/M-Pin SDK - Authentication flow.xml
new file mode 100644
index 0000000..4bf06c0
--- /dev/null
+++ b/M-Pin SDK - Authentication flow.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mxGraphModel dx="1050" dy="636" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="#ffffff" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="3" target="5" edge="1"><mxGeometry x="414" y="130" as="geometry"/></mxCell><mxCell id="3" value="Start" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="90" width="70" height="40" as="geometry"/></mxCell><mxCell id="25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" source="5" target="23" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="5" value="&lt;font face=&quot;Lucida Console&quot;&gt;StartAuthentication&lt;/font&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="342" y="180" wid
 th="144" height="40" as="geometry"/></mxCell><mxCell id="9" value="&lt;code&gt;&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;&lt;/code&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;" parent="1" source="23" target="19" edge="1"><mxGeometry as="geometry"><mxPoint y="3" as="offset"/><mxPoint x="414" y="449.6715328467153" as="sourcePoint"/><mxPoint x="414" y="371" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;" parent="1" source="19" target="21" edge="1"><mxGeometry x="414" y="763" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="19" value="Read Secret (PIN)&lt;div&gt;from end user&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="354" y="383" width="120" height="40" as="geometry"/></mxCell><mxCell id="37" value="" style="edgeStyle=orthogonalEdg
 eStyle;rounded=0;html=1;" parent="1" source="21" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="21" value="&lt;p&gt;&lt;code&gt;&lt;font face=&quot;Lucida Console&quot; style=&quot;font-size: 12px&quot;&gt;FinishAuthentication&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="330" y="483" width="168" height="40" as="geometry"/></mxCell><mxCell id="22" value="End" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="759.5999999999999" width="70" height="40" as="geometry"/></mxCell><mxCell id="27" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;REVOKED&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;" parent="1" source="23" target="28" edge="1"><mxGeometry x="-0.04" y="15" relative="1" as="geometry"><mxPoint x="582" y="315" as="targetPoint"/><Array as="points"/><mxPoint as="offset"/></mxGeometry><
 /mxCell><mxCell id="23" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="265" width="95" height="60" as="geometry"/></mxCell><mxCell id="30" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="28" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="637" y="435" as="targetPoint"/><Array as="points"><mxPoint x="637" y="780"/></Array></mxGeometry></mxCell><mxCell id="28" value="User is Revoked" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="580" y="275" width="114" height="40" as="geometry"/></mxCell><mxCell id="39" value="&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="22" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;INCORRECT_PIN&lt;/
 font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="40" edge="1"><mxGeometry x="-0.08" y="-12" relative="1" as="geometry"><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="36" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="573" width="95" height="65" as="geometry"/></mxCell><mxCell id="43" value="&lt;font face=&quot;Lucida Console&quot;&gt;REGISTERED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;exitX=0.5;exitY=0;" parent="1" source="40" target="19" edge="1"><mxGeometry x="-0.5393" relative="1" as="geometry"><mxPoint x="218.5" y="733" as="targetPoint"/><Array as="points"><mxPoint x="219" y="403"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="48" value="&lt;font face=&quot;Lucida Console&quot;&gt;BLOCKED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" sourc
 e="40" target="46" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="40" value="User State?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="171" y="573" width="95" height="65" as="geometry"/></mxCell><mxCell id="50" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="46" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="219" y="1090" as="targetPoint"/><Array as="points"><mxPoint x="219" y="780"/></Array></mxGeometry></mxCell><mxCell id="46" value="User is Blocked&lt;div&gt;(need to re-register)&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="159" y="690" width="120" height="40" as="geometry"/></mxCell></root></mxGraphModel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Authentication to Browser Session flow.png
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication to Browser Session flow.png b/M-Pin SDK - Authentication to Browser Session flow.png
new file mode 100644
index 0000000..3685828
Binary files /dev/null and b/M-Pin SDK - Authentication to Browser Session flow.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Authentication to Browser Session flow.xml
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Authentication to Browser Session flow.xml b/M-Pin SDK - Authentication to Browser Session flow.xml
new file mode 100644
index 0000000..4237a4b
--- /dev/null
+++ b/M-Pin SDK - Authentication to Browser Session flow.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mxGraphModel dx="1050" dy="636" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="#ffffff" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="3" target="5" edge="1"><mxGeometry x="414" y="130" as="geometry"/></mxCell><mxCell id="3" value="Start" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="90" width="70" height="40" as="geometry"/></mxCell><mxCell id="25" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" source="5" target="23" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="5" value="&lt;font face=&quot;Lucida Console&quot;&gt;StartAuthentication&lt;/font&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="342" y="180" wid
 th="144" height="40" as="geometry"/></mxCell><mxCell id="9" value="&lt;code&gt;&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;&lt;/code&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;" parent="1" source="23" target="31" edge="1"><mxGeometry as="geometry"><mxPoint as="offset"/><mxPoint x="414" y="449.6715328467153" as="sourcePoint"/><mxPoint x="414" y="420" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="13" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="14" target="17" edge="1"><mxGeometry x="414" y="585" as="geometry"/></mxCell><mxCell id="14" value="&lt;font face=&quot;Lucida Console&quot;&gt;CheckAccessNumber&lt;/font&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="342" y="460" width="144" height="40" as="geometry"/></mxCell><mxCell id="15" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;INCORRECT_ACCESS_NUMBER&lt;/fon
 t&gt;&lt;/span&gt;&lt;br&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;exitX=0;exitY=0.5;entryX=0;entryY=0.5;" parent="1" source="17" target="31" edge="1"><mxGeometry as="geometry"><mxPoint x="500" y="520" as="targetPoint"/><Array as="points"><mxPoint x="190" y="585"/><mxPoint x="190" y="391"/></Array><mxPoint x="-76" y="82" as="offset"/></mxGeometry></mxCell><mxCell id="35" value="&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="17" target="19" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="17" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="552" width="95" height="65" as="geometry"/></mxCell><mxCell id="18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;" parent="1" source="19" target="21" edge="1"><mxGeometry x="414" y="790" as="geometry"><Array as="poin
 ts"/></mxGeometry></mxCell><mxCell id="19" value="Read Secret (PIN)&lt;div&gt;from end user&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="354" y="670" width="120" height="40" as="geometry"/></mxCell><mxCell id="37" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="21" target="36" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="21" value="&lt;p&gt;&lt;code&gt;&lt;font face=&quot;Lucida Console&quot; style=&quot;font-size: 12px&quot;&gt;FinishAuthenticationAN&lt;/font&gt;&lt;/code&gt;&lt;/p&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="330" y="770" width="168" height="40" as="geometry"/></mxCell><mxCell id="22" value="End" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="379" y="1046.6" width="70" height="40" as="geometry"/></mxCell><mxCell id="27" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;REVOKED&lt;/font&gt;&lt;/span
 &gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;" parent="1" source="23" target="28" edge="1"><mxGeometry x="-0.04" y="15" relative="1" as="geometry"><mxPoint x="582" y="315" as="targetPoint"/><Array as="points"/><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="23" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="265" width="95" height="60" as="geometry"/></mxCell><mxCell id="30" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="28" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="637" y="435" as="targetPoint"/><Array as="points"><mxPoint x="668" y="1067"/></Array></mxGeometry></mxCell><mxCell id="28" value="User is Revoked" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="611" y="275" width="114" height="40" as="geometry"/></mxCell><mxCell id="32" value="" style="edgeStyle=orthog
 onalEdgeStyle;rounded=0;html=1;" parent="1" source="31" target="14" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="31" value="Read Access Number&lt;div&gt;from end user&amp;nbsp;&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="346" y="371" width="136" height="40" as="geometry"/></mxCell><mxCell id="39" value="&lt;font face=&quot;Lucida Console&quot;&gt;OK&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="22" edge="1"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;INCORRECT_PIN&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" parent="1" source="36" target="40" edge="1"><mxGeometry x="-0.08" y="-12" relative="1" as="geometry"><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="52" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;INCORRECT_ACCESS_NU
 MBER&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=1;entryY=0.5;exitX=1;exitY=0.5;" edge="1" parent="1" source="36" target="31"><mxGeometry x="-0.7878" y="13" relative="1" as="geometry"><mxPoint x="561" y="892.5" as="targetPoint"/><Array as="points"><mxPoint x="640" y="893"/><mxPoint x="640" y="391"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="36" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="366" y="860" width="95" height="65" as="geometry"/></mxCell><mxCell id="43" value="&lt;font face=&quot;Lucida Console&quot;&gt;REGISTERED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;" parent="1" source="40" target="19" edge="1"><mxGeometry x="-0.5393" relative="1" as="geometry"><mxPoint x="218.5" y="760" as="targetPoint"/><Array as="points"><mxPoint x="219" y="690"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="48" value="&lt;
 font face=&quot;Lucida Console&quot;&gt;BLOCKED&lt;/font&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" parent="1" source="40" target="46" edge="1"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="40" value="User State?" style="rhombus;whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="171" y="860" width="95" height="65" as="geometry"/></mxCell><mxCell id="50" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0;entryY=0.5;exitX=0.5;exitY=1;" parent="1" source="46" target="22" edge="1"><mxGeometry relative="1" as="geometry"><mxPoint x="219" y="1117" as="targetPoint"/><Array as="points"><mxPoint x="219" y="1067"/></Array></mxGeometry></mxCell><mxCell id="46" value="User is Blocked&lt;div&gt;(need to re-register)&lt;/div&gt;" style="whiteSpace=wrap;html=1;" parent="1" vertex="1"><mxGeometry x="159" y="977" width="120" height="40" as="geometry"/></mxCell></root></mxGraphModel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Registration flow.png
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Registration flow.png b/M-Pin SDK - Registration flow.png
new file mode 100644
index 0000000..460f6f9
Binary files /dev/null and b/M-Pin SDK - Registration flow.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/M-Pin SDK - Registration flow.xml
----------------------------------------------------------------------
diff --git a/M-Pin SDK - Registration flow.xml b/M-Pin SDK - Registration flow.xml
new file mode 100644
index 0000000..fdf50b7
--- /dev/null
+++ b/M-Pin SDK - Registration flow.xml	
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mxGraphModel dx="1050" dy="636" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" background="#ffffff" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="41519c7962ced28-4" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-1" target="41519c7962ced28-2"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-1" value="Start" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="379" y="90" width="70" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-8" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-2" target="41519c7962ced28-6"><mxGeometry relative="1" as="geometry"><mxPoint x="405.5" y="330" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-2" va
 lue="&lt;font face=&quot;Lucida Console&quot;&gt;MakeNewUser&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="366" y="180" width="95" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-10" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-6" target="41519c7962ced28-9"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-6" value="&lt;font face=&quot;Lucida Console&quot;&gt;StartRegistration&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="347" y="270" width="133" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-13" value="&lt;div&gt;&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;STARTED_REGISTRATION&lt;/font&gt;&lt;/span&gt;&lt;br&gt;&lt;/div&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-9" target="41519c7962ced28-11"><m
 xGeometry x="-0.1333" y="15" relative="1" as="geometry"><mxPoint x="582" y="405" as="targetPoint"/><Array as="points"><mxPoint x="617" y="405"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-16" value="&lt;code&gt;&lt;font face=&quot;Lucida Console&quot;&gt;ACTIVATED&lt;/font&gt;&lt;/code&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-9" target="41519c7962ced28-15"><mxGeometry x="0.0139" y="-18" relative="1" as="geometry"><mxPoint x="18" y="-18" as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-9" value="If returned&lt;div&gt;Status is OK,&amp;nbsp;&lt;span style=&quot;line-height: 1.2&quot;&gt;Check&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;line-height: 1.2&quot;&gt;User State&lt;/span&gt;&lt;/div&gt;" style="rhombus;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="345" y="360" width="137" height="90" as="geometry"/></mxCell><mxCell id="41519c7962ced28-
 18" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.75;entryY=0;exitX=0.5;exitY=1;" edge="1" parent="1" source="41519c7962ced28-11" target="41519c7962ced28-15"><mxGeometry relative="1" as="geometry"><mxPoint x="617" y="590" as="targetPoint"/><Array as="points"><mxPoint x="617" y="520"/><mxPoint x="450" y="520"/></Array></mxGeometry></mxCell><mxCell id="41519c7962ced28-11" value="Wait for user to confirm identity" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="560" y="450" width="114" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-20" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-15" target="41519c7962ced28-19"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-15" value="&lt;font face=&quot;Lucida Console&quot;&gt;ConfirmRegistration&lt;/font&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="342" y="545" width
 ="144" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-22" value="&lt;span&gt;&lt;font face=&quot;Lucida Console&quot;&gt;IDENTITY_NOT_VERIFIED&lt;/font&gt;&lt;/span&gt;" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.75;entryY=0;exitX=1;exitY=0.5;" edge="1" parent="1" source="41519c7962ced28-19" target="41519c7962ced28-11"><mxGeometry x="-0.6526" y="15" relative="1" as="geometry"><mxPoint x="583" y="695" as="targetPoint"/><Array as="points"><mxPoint x="710" y="660"/><mxPoint x="710" y="410"/><mxPoint x="646" y="410"/></Array><mxPoint as="offset"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-24" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;" edge="1" parent="1" source="41519c7962ced28-19" target="41519c7962ced28-23"><mxGeometry relative="1" as="geometry"/></mxCell><mxCell id="41519c7962ced28-19" value="Status?" style="rhombus;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="345" y="615" width="137" height="90" as="g
 eometry"/></mxCell><mxCell id="41519c7962ced28-26" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;" edge="1" parent="1" source="41519c7962ced28-23" target="41519c7962ced28-25"><mxGeometry relative="1" as="geometry"><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-23" value="Read Secret (PIN)&lt;div&gt;from end user&lt;/div&gt;" style="whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="354" y="750" width="120" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-29" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;entryX=0.5;entryY=0;" edge="1" parent="1" source="41519c7962ced28-25" target="41519c7962ced28-27"><mxGeometry relative="1" as="geometry"><mxPoint x="413.5" y="1000" as="targetPoint"/><Array as="points"/></mxGeometry></mxCell><mxCell id="41519c7962ced28-25" value="&lt;font face=&quot;Lucida Console&quot;&gt;FinishRegistration&lt;/font&gt;" style="whiteSpace=wrap;htm
 l=1;" vertex="1" parent="1"><mxGeometry x="342" y="848" width="143" height="40" as="geometry"/></mxCell><mxCell id="41519c7962ced28-27" value="End" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="379" y="944.5999999999999" width="70" height="40" as="geometry"/></mxCell></root></mxGraphModel>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/Mobile-SDK-Architecture.png
----------------------------------------------------------------------
diff --git a/Mobile-SDK-Architecture.png b/Mobile-SDK-Architecture.png
new file mode 100644
index 0000000..303021c
Binary files /dev/null and b/Mobile-SDK-Architecture.png differ

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/cadbe7c8/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 44433b4..da6bb7c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,358 @@
-# Mobile SDK core 
+# Apache Milagro Mobile SDK Core
+
+## Architecture and API
+
+### System Overview
+The Mobile SDK is a software library that allows mobile application developers to use the Apache Milagro authentication scheme for authenticating their end-users. It is a "native" library which contains native API for each platform:
+- Java API for Android
+- Objective-C API for iOS
+- C# API for Windows Phone. 
+
+The SDK implements a Client in the Apache Milagro authentication scheme. It is divided into three layers:
+* Crypto
+* Core
+* Platform Adaptation
+
+#### Crypto
+
+The Crypto layer performs all the cryptographic operations required during the Milagro Registration and Authentication process. It is currently based on the _Apache Milagro Crypto_ library. A Trusted Execution Environment (TEE) may be available on some Android platforms (mainly on Samsung devices). The TEE allows for hardware-secured execution of sensitive code and storage of sensitive data. The Mobile SDK is designed in such a way that when the TEE is present, the Crypto code might run on it allowing sensitive data to be stored on it. Thus, two variants of Crypto layer are made available, _Non-TEE Crypto_ and _TEE Crypto_. They provide the same API towards the Core layer and so should be interchangeable.
+
+The Apache Milagro Crypto is a C library which the Non-TEE Crypto wraps with platform-agnostic C++ code.
+
+#### Core
+
+The Core layer implements the logic and flow of the Apache Milagro Authentication Platform. It is written in C++ and is platform-agnostic. As it is not solely able to perform certain tasks, such as storing data on the device, or making HTTP requests, it invokes the _Platform Adaptation_ layer through interfaces provided during the Core initialization, to do them.
+
+#### Platform Adaptation
+
+This layer is implemented separately for every platform, since it is the only platform-specific component in the SDK. It provides a thin adaptation layer for the Core's C++ API to the native languages, Java, Objective-C or C#, for the different Mobile Platforms. It also provides platform-specific implementation of Secure and Non-Secure Storage and HTTP Requests.
+
+![alt text](Mobile-SDK-Architecture.png)
+
+For the platform-specific API's see:
+* [Android SDK API](https://github.com/apache/incubator-milagro-mfa-sdk-android)
+* [iOS SDK API](https://github.com/apache/incubator-milagro-mfa-sdk-ios)
+* [Windows Phone SDK API](https://github.com/apache/incubator-milagro-mfa-sdk-wp)
+
+### Core API
+
+The Core layer is the central part of the Apache Milagro SDK. It implements the functionality of a Milagro Client and drives the communication with the Milagro MFA Services. The SDK Core (and Crypto) are implemented in a portable way, using C/C++ programming languages, to enable them to be compiled for different platforms such as a mobile or a desktop one. Most of the platforms provide a native API to make HTTP requests and store data. The Core utilizes the services on the specific platform it was compiled to, and runs on top of them. Hence, it works with Interfaces for those platform-specific services, as they are implemented at the _Platform Adaptation Layer_. 
+
+The interfaces are:
+
+* `IHttpRequest` - for making HTTP requests
+* `IStorage`     - for storing data on the device
+* `IContext`     - for grouping the rest of the interfaces into a single bundle
+
+Although the SDK Core API (part of it) is the de-facto SDK API, it is not exposed to the application developer. It is an internal API to the Platform Adaptation Layer, which presents the SDK API to the application in a way that is native to the platform.
+
+#### HTTP Request Interface (`IHttpRequest`)
+The Core uses this interface to make HTTP requests. It should be implemented in the Platform Adaptation Layer. The Core creates an HTTP Request object via `IContext::CreateHttpRequest()` method and when done, releases the request via `IContext::ReleaseHttpRequest()`.
+
+##### `virtual void SetHeaders(const StringMap& headers);`
+This method sets the headers for the HTTP Request. The headers are passed in the `headers` key/value map, which is a standard `std::map<std::string, std::string>` object. This method should be called prior to executing the HTTP Request.
+
+##### `virtual void SetQueryParams(const StringMap& queryParams);`
+This method sets the query parameters for the HTTP Request. The query parameters are passed in the `queryParams` key/value map, which is a standard `std::map<std::string, std::string>` object. This method is called prior to executing the HTTP Request.
+
+##### `virtual void SetContent(const String& data);`
+This method sets the content (the data) of the HTTP Request. It is passed in the `data` parameter as a string. This method is called prior to executing the HTTP Request.
+
+##### `virtual void SetTimeout(int seconds);`
+This method sets a timeout for the HTTP Request. The timeout is set in `seconds`. If not set, the timeout is expected to be infinite. This method is called prior to executing the HTTP Request.
+
+##### `virtual bool Execute(Method method, const String& url);`
+This method executes the HTTP Request with the provided `method` and to the given `url`. The `Method` enumerator is defined as follows:
+```c++
+enum Method
+{
+    GET,
+    POST,
+    PUT,
+    DELETE,
+    OPTIONS,
+    PATCH
+};
+```
+The request is made with the previously set headers, query parameters and data. If the HTTP request was successfully executed, and a response received, the return value will be `true`. If the execution failed, the return value would be `false`.<br/>
+**NOTE** that a non-2xx HTTP response does not mean that the request has failed, but that it succeeded while the return status code was not a 2xx HTTP response.
+If the `Execute()` request failed, the `GetExecuteErrorMessage()` will return more information on the reason for the failure.
+
+##### `virtual const String& GetExecuteErrorMessage() const;`
+Returns an error message describing the failure of a preceding `Execute()` request.
+
+##### `virtual int GetHttpStatusCode() const;`
+Returns the status code received in response to the preceding successfully executed HTTP request.
+
+##### `virtual const StringMap& GetResponseHeaders() const;`
+Returns the headers received in response to the preceding successfully executed HTTP request. The headers are returned in a key/value map, which is a standard `std::map<std::string, std::string>` object.
+
+##### `virtual const String& GetResponseData() const;`
+Returns the data received as a response to the preceding successfully executed HTTP request. The data is returned as a string.
+
+#### Storage Interface (`IStorage`)
+The Core uses this interface to store data on the specific platform. As different platforms provide different storage options, the implementation of the interface should be part of the Platform Adaptation Layer. There are two kinds of storages that the Core uses, Secure and Non-secure. In the Secure Storage, the Core stores the _regOTT_ (during registration) and _M-Pin Token_ for every user that is registered through the device. In the Non-Secure Storage, the Core stores all non-sensitive data, like cached Time Permits. The `IContext` provides the interface to the correct Storage via the `IContext::GetStorage(IStorage::Type)` method.
+
+##### `virtual bool SetData(const String& data);`
+This method sets/writes the whole storage data. The data is provided in the data parameter, as a string. The return value is `true` on success or `false` on failure. If the method fails, further information regarding the error can be obtained through the `GetErrorMessage()` method.
+
+##### `virtual bool GetData(OUT String& data);`
+This method gets/reads the whole storage data. The data is returned in the `data` parameter, as a string. The return value is `true` on success or `false` on failure. If the method fails, further information regarding the error can be obtained through the `GetErrorMessage()` method.
+
+##### `virtual const String& GetErrorMessage() const;`
+Returns the error from the preceding failed `GetData()` or `SetData()` methods.
+
+#### Context Interface (`IContext`)
+The Context Interface "bundles" the rest of the interfaces. This is the only interface that is provided to the Core where the other interfaces are used/accessed through it. 
+
+##### `virtual IHttpRequest* CreateHttpRequest() const;`
+This request creates a new HTTP request instance that conforms with `IHttpRequest`, and returns a pointer to it. The Core calls `CreateHttpRequest()` when it needs to make an HTTP request. After receiving a pointer to such an instance, the Core sets the needed headers, query parameters and data, and then executes the request. The Core will then check for the status code, the headers, the data of the response, and will finally release the HTTP request.<br/>
+
+**NOTE** that the HTTP request instance should remain "alive" until calling `ReleaseHttpRequest()`.<br/>
+**NOTE** As the Core might create two or more HTTP request instances in parallel, the implementation should not use global or local (stack) HTTP request objects.
+
+##### `virtual void ReleaseHttpRequest(IN IHttpRequest* request) const;`
+This request destroys/releases a previously created HTTP request instance. The Core calls `CreateHttpRequest()` when it needs to make an HTTP request. After receiving a pointer to such an instance, the Core sets the needed headers, query parameters and data, and then executes the request. The Core checks for the status code, the headers, the data of the response, and finally releases the HTTP request.
+
+**NOTE** that the HTTP request instance should remain "alive" until calling `ReleaseHttpRequest()`.<br/>
+**NOTE** Also, as the Core might create two or more HTTP request instances in parallel, the implementation should not use global or local (stack) HTTP request objects.
+
+##### `virtual IStorage* GetStorage(IStorage::Type type) const;`
+This method returns a pointer to the storage implementation, which conforms to `IStorage`. There are two storage types, Secure and Non-Secure, where you can pass your desired storage type as a parameter. The `IStorage::Type` enumerator is defined as follows:
+```c++
+enum Type
+{
+    SECURE,
+    NONSECURE
+};
+```
+##### `virtual CryptoType GetMPinCryptoType() const;`
+
+This method provides information regarding the supported Crypto Type on the specific platform. Currently, this method could return a different value than Non-TEE Crypto, only on an Android platform. Other platforms will always return a Non-TEE Crypto value. On an Android, the Platform Adaptation needs to check if TEE is supported, and then return TEE or Non-TEE Crypto type accordingly. 
+The `CryptoType` enumerator is defined as follows:
+```c++
+enum CryptoType
+{
+    CRYPTO_TEE,
+    CRYPTO_NON_TEE
+};
+```
+
+#### Main Core API (`MPinSDK`)
+The `MPinSDK` is the main SDK Core class. In order to use the Core, one should create an instance of the `MPinSDK` class and initialize it. Most of the methods return a `MPinSDK::Status` object, which is defined as follows:
+
+```c++
+class Status
+{
+public:
+    enum Code
+    {
+        OK,
+        PIN_INPUT_CANCELLED,     // Local error, returned when a user cancels entering a pin
+        CRYPTO_ERROR,            // Local error in crypto functions
+        STORAGE_ERROR,           // Local storage related error
+        NETWORK_ERROR,           // Local error - unable to connect to remote server (no internet, or invalid server/port)
+        RESPONSE_PARSE_ERROR,    // Local error - unable to parse json response from remote server (invalid json or unexpected json structure)
+        FLOW_ERROR,              // Local error - improper MPinSDK class usage
+        IDENTITY_NOT_AUTHORIZED, // Remote error - remote server refuses user registration or authentication
+        IDENTITY_NOT_VERIFIED,   // Remote error - remote server refuses user registration because identity is not verified
+        REQUEST_EXPIRED,         // Remote error - register/authentication request expired
+        REVOKED,                 // Remote error - unable to get time permit (probably the user is temporarily suspended)
+        INCORRECT_PIN,           // Remote error - user entered wrong pin
+        INCORRECT_ACCESS_NUMBER, // Remote/local error - wrong access number (checksum failed or RPS returned 412)
+        HTTP_SERVER_ERROR,       // Remote error, when the error does not apply to any of the above - the remote server returned internal server error status (5xx)
+        HTTP_REQUEST_ERROR,      // Remote error, where the error does not apply to any of the above - invalid data sent to server, the remote server returned 4xx error status
+        BAD_USER_AGENT,          // Remote error - user agent not supported
+        CLIENT_SECRET_EXPIRED    // Remote error - re-registration required because server master secret expired
+    };
+
+    Code GetStatusCode() const;
+    const String& GetErrorMessage() const;
+    bool operator==(Code statusCode) const;
+    bool operator!=(Code statusCode) const;
+
+    ...
+};
+```
+The methods that return `Status`, will always return `Status::OK` if successful. Many methods expect the provided `User` object to be in a certain state, and if it is not, the method will return `Status::FLOW_ERROR`
+
+##### `Status Init(const StringMap& config, IN IContext* ctx);`
+##### `Status Init(const StringMap& config, IN IContext* ctx, const StringMap& customHeaders);`
+This method initializes the `MPinSDK` instance. It receives a map of configuration parameters and a pointer to a [Context Interface](#Context-Interface). The configuration map is a key-value map into which different configuration options can be inserted. This is a flexible way of passing configurations into the Core, as the method parameters will not change when new configuration parameters are added. 
+Unsupported parameters will be ignored. Currently, the Core recognizes the following parameters:
+
+* `backend` - the URL of the Milagro MFA back-end service (Mandatory)
+* `rpsPrefix` - the prefix that should be added for requests to the RPS (Optional). The default value is `"rps"`.
+* `customHeaders` - (optional) allows the caller to pass additional map of custom headers, which will be added to any HTTP request that the SDK executes.
+Example:
+```c++
+MPinSDK::StringMap config;
+config["backend"] = "http://ec2-54-77-232-113.eu-west-1.compute.amazonaws.com";
+ 
+MPinSDK* sdk = new MPinSDK;
+MPinSDK::Status s = sdk->Init( config, Context::Instance() );
+```
+
+##### `void Destroy();`
+This method clears the `MPinSDK` instance and releases any allocated data by it. After calling this method, one should use `Init()` again in order to re-use the `MPinSDK` instance.
+
+##### `Status TestBackend(const String& server, const String& rpsPrefix = "rps") const;`
+This method will test whether `server` is a valid back-end URL by trying to retrieve Client Settings from it. Optionally, a custom RPS prefix might be specified if it was customized at the back-end and is different than the default `"rps"`. If the back-end URL is a valid one, the method will return `Status::OK`.
+
+##### `Status SetBackend(const String& server, const String& rpsPrefix = "rps");`
+This method will change the currently configured back-end in the Core. Initially the back-end might be set through the `Init()` method, but then it might be change using this method. server is the new back-end URL that should be used. Optionally, a custom RPS prefix might be specified if it was customized at the back-end and is different than the default `"rps"`. If successful, the method will return `Status::OK`. 
+
+##### `UserPtr MakeNewUser(const String& id, const String& deviceName = "") const;`
+This method creates a new `User` object. The User object represents an end-user of the Milagro authentication. The user has its own unique identity, which is passed as the id parameter to this method. Additionally, an optional `deviceName` might be specified. The _Device Name_ is passed to the RPA, which might store it and use it later to determine which Milagro ID is associated with this device. The returned value is of type `UserPtr`, which is a reference counting shared pointer to the newly created `User` instance. The User class itself looks like this:
+```c++
+class User
+{
+public:
+    enum State
+    {
+        INVALID,
+        STARTED_REGISTRATION,
+        ACTIVATED,
+        REGISTERED,
+        BLOCKED
+    };
+
+    const String& GetId() const;
+    const String& GetBackend() const;
+    State GetState() const;
+
+private:
+    ....
+};
+```
+The newly created user is in the `INVALID` state.
+The `User` class is defined in the namespace of the `MPinSDK` class.
+
+##### `void DeleteUser(INOUT UserPtr user);`
+This method deletes a user from the users list that the SDK maintains. All the user data including its _M-Pin ID_, its state and _M-Pin Token_ will be deleted. A new user with the same identity can be created later with the `MakeNewUser()` method.
+
+##### `Status ListUsers(OUT std::vector<UserPtr>& users) const;`
+This method populates the provided vector with all the users that are associated with the currently set backend. Different users might be in different states, reflecting their registration status.
+The method will return `Status::OK` on success and `Status::FLOW_ERROR` if no backend is set through the `Init()` or `SetBackend()` methods.
+
+##### `Status ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;`
+This method populates the provided vector with all the users that are associated with the provided `backend`. Different users might be in different states, reflecting their registration status.
+The method will return `Status::OK` on success and `Status::FLOW_ERROR` if the SDK was not initialized.
+
+##### `Status ListAllUsers(OUT std::vector<UserPtr>& users) const;`
+This method populates the provided vector with all the users associated with all the backends know to the SDK. Different users might be in different states, reflecting their registration status.
+The user association to a backend could be retrieved through the `User::GetBackend()` method.
+The method will return `Status::OK` on success and `Status::FLOW_ERROR` if the SDK was not initialized.
+
+##### `Status ListBackends(OUT std::vector<String>& backends) const;`
+This method will populate the provided vector with all the backends known to the SDK.
+The method will return `Status::OK` on success and `Status::FLOW_ERROR` if the SDK was not initialized.
+
+##### `Status GetSessionDetails(const String& accessCode, OUT SessionDetails& sessionDetails);`
+This method could be optionally used to retrieve details regarding a browser session when the SDK is used to authenticate users to an online service, such as the _MIRACL MFA Platform_.
+In this case an `accessCode` is transferred to the mobile device out-of-band e.g. via scanning a graphical code. The code is then provided to this method to get the session details.
+This method will also notify the backend that the `accessCode` was retrieved from the browser session.
+The returned `SessionDetails` look as follows:
+```c++
+class SessionDetails
+{
+public:
+    void Clear();
+
+    String prerollId;
+    String appName;
+    String appIconUrl;
+};
+```
+During the online browser session an optional user identity might be provided meaning that this is the user that wants to register/authenticate to the online service.
+The `prerollId` will carry that user ID, or it will be empty if no such ID was provided.
+`appName` is the name of the web application to which the service will authenticate the user.
+`appIconUrl` is the URL from which the icon for web application could be downloaded.
+
+
+##### `Status StartRegistration(INOUT UserPtr user, const String& activateCode = "", const String& userData = "");`
+This method initializes the registration for a User that has already been created. The Core starts the Milagro Setup flow, sending the necessary requests to the back-end service. The State of the User instance will change to `STARTED_REGISTRATION`. The status will indicate whether the operation was successful or not. During this call, an _M-Pin ID_ for the end-user will be issued by the RPS and stored within the user object. The RPA could also start a user identity verification procedure, by sending a verification e-mail.
+
+The optional `activateCode` parameter might be provided if the registration process requires such. In cases when the user verification is done through a _One-Time-Code_ (OTC) or through an SMS that carries such code, this OTC should be passed as the `activateCode` parameter. In those cases, the identity verification should be completed instantly and the User State will be set to `ACTIVATED`.
+ 
+Optionally, the application might pass additional `userData` which might help the RPA to verify the user identity. The RPA might decide to verify the identity without starting a verification process. In this case, the `Status` of the call will still be `Status::OK`, but the User State will be set to `ACTIVATED`.
+
+##### `Status RestartRegistration(INOUT UserPtr user, const String& userData = "");`
+This method re-initializes the registration process for a user, where registration has already started. The difference between this method and `StartRegistration()` is that it will not generate a new _M-Pin ID_, but will use the one that was already generated. Besides that, the methods follow the same procedures, such as getting the RPA to re-start the user identity verification procedure of sending a verification email to the user.
+
+The application could also pass additional `userData` to help the RPA to verify the user identity. The RPA might decide to verify the identity without starting a verification process. In this case, the `Status` of the call will still be `Status::OK`, but the User State will be set to `ACTIVATED`.
+
+##### `Status ConfirmRegistration(INOUT UserPtr user, const String& pushMessageIdentifier = "");`
+This method allows the application to check whether the user identity verification process has been finalized or not. The provided `user` object is expected to be either in the `STARTED_REGISTRATION` state or in the `ACTIVATED`state. The latter is possible if the RPA activated the user immediately with the call to `StartRegistration()` and no verification process was started. During the call to `ConfirmRegistration()` the SDK will make an attempt to retrieve _Client Key_ for the user. This attempt will succeed if the user has already been verified/activated but will fail otherwise. The method will return `Status::OK` if the Client Key has been successfully retrieved and `Status::IDENTITY_NOT_VERIFIED` if the identity has not been verified yet. If the method has succeeded, the application is expected to get the desired PIN/secret from the end-user and then call `FinishRegistration()`, and provide the PIN.<br/>
+**Note** Using the optional parameter `pushMessageIdentifier`, the application can provide a platform specific identifier for sending _Push Messages_ to the device. Such push messages might be utilized as an alternative to the _Access Number_, as part of the authentication flow.
+
+##### `Status FinishRegistration(INOUT UserPtr user, const String& pin)`
+This method finalizes the user registration process. It extracts the _M-Pin Token_ from the _Client Key_ for the provided `pin` (secret), and then stores the token in the secure storage. On successful completion, the User state will be set to `REGISTERED` and the method will return `Status::OK`
+
+##### `Status StartAuthentication(INOUT UserPtr user, const String& accessCode = "");`
+This method starts the authentication process for a given `user`. It attempts to retrieve the _Time Permits_ for the user, and if successful, will return `Status::OK`.
+If they cannot be retrieved, the method will return `Status::REVOKED`. If this method is successfully completed, the app should read the PIN/secret from the end-user and call one of the `FinishAuthentication()` variants to authenticate the user.
+
+Optionally, an `accessCode` could be provided. This code is retrieved out-of-band from a browser session when the user has to be authenticated to an online service, such as the _MIRACL MFA Platform_.
+When this code is provided, the SDK will notify the service that authentication associated with the given `accessCode` has started for the provided user. 
+
+
+##### `Status CheckAccessNumber(const String& accessNumber);`
+This method is used only when a user needs to be authenticated to a remote (browser) session, using _Access Number_. The access numbers might have a check-sum digit in them and this check-sum needs to be verified on the client side, in order to prevent calling the back-end with non-compliant access numbers. The method will return `Status::OK` if successful, and `Status::INCORRECT_ACCESS_NUMBER` if not successful.
+
+##### `Status FinishAuthentication(INOUT UserPtr user, const String& pin);`
+##### `Status FinishAuthentication(INOUT UserPtr user, const String& pin, OUT String& authResultData);`
+This method performs end-user authentication where the `user` to be authenticated, is passed as a parameter, along with his `pin` (secret). As it holds the details of the user PIN and the stored _M-Pin Token_, the method will perform the authentication against the _Milagro MFA Server_ and then will login into the RPA. The RPA responds with the authentication _User Data_ which is returned to the application through the `authResultData` parameter.
+If successful, the returned status will be `Status::OK`, and if the authentication fails, the return status would be: `Status::INCORRECT_PIN`.
+After the 3rd (configurable in the RPS) unsuccessful authentication attempt, the method will return `Status::INCORRECT_PIN` and the User State will be set to `User::BLOCKED`.
+
+##### `Status FinishAuthenticationOTP(INOUT UserPtr user, const String& pin, OUT OTP& otp);`
+This method performs end-user authentication for an OTP. The authentication process is similar to `Status FinishAuthentication(INOUT UserPtr user, const String& pin);`, but the RPA issues an OTP instead of logging the user into the application. The returned status is analogical to the `FinishAuthentication()` method, but, in addition to that, an `OTP` structure is returned. The `OTP` structure looks like this:
+```c++
+class OTP
+{
+public:
+    String otp;
+    long expireTime;
+    int ttlSeconds;
+    long nowTime;
+    Status status;
+};
+```
+The `otp` string is the issued OTP.
+The `expireTime` is the Milagro MFA system time when the OTP will expire.
+The `ttlSeconds` is the expiration period in seconds.
+The `nowTime` is the current Milagro MFA system time.
+`Status` is the status of the OTP generation. The status will be `Status::OK` if the OTP was successfully generated, or `Status::FLOW_ERROR` if not.<br/>
+
+**NOTE** that OTP might be generated only by RPA that supports that functionality, such as the MIRACL M-Pin SSO. Other RPA's might not support OTP generation where the `status` inside the returned `otp` structure will be `Status::FLOW_ERROR`.
+
+##### `Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);`
+This method authenticates the end-user using an _Access Number_ (also refered as _Access Code_), provided by a PC/Browser session. After this authentication, the end-user can log into the PC/Browser which provided the Access Number, while the authentication itself is done on the Mobile Device. `accessNumber` is the Access Number from the browser session. The returned status might be:
+`Status::OK` - Successful authentication.
+`Status::INCORRECT_PIN` - The authentication failed because of incorrect PIN. After the 3rd (configurable in the RPS) unsuccessful authentication attempt, the method will still return `Status::INCORRECT_PIN` but the User State will be set to `User::BLOCKED`.
+`Status::INCORRECT_ACCESS_NUMBER` - The authentication failed because of incorrect Access Number. 
+
+##### `bool CanLogout(IN UserPtr user);`
+This method is used after authentication with an Access Number through `FinishAuthenticationAN()`. After such an authentication, the Mobile Device can log out the end-user from the Browser session, if the RPA supports that functionality. This method checks whether logout information was provided by the RPA and the remote (Browser) session can be terminated from the Mobile Device. The method will return `true` if the user can be logged-out from the remote session, and `false` otherwise.
+
+##### `bool Logout(IN UserPtr user);`
+This method tries to log out the end-user from a remote (Browser) session after a successful authentication through `FinishAuthenticationAN()`. Before calling this method, it is recommended to ensure that logout data was provided by the RPA and that the logout operation can be actually performed. The method will return `true` if the logged-out request to the RPA was successful, and `false` otherwise.
+
+##### `const char* GetVersion();`
+This method returns a pointer to a null-terminated string with the version number of the SDK.
+
+##### `String GetClientParam(const String& key);`
+This method returns the value for a _Client Setting_ with the given key. The value is returned as a String always, i.e. when a numeric or a boolean value is expected, the conversion should be handled by the application. 
+Client settings that might interest the applications are:
+* `accessNumberDigits` - The number of Access Number digits that should be entered by the user, prior to calling `FinishAuthenticationAN()`.
+* `setDeviceName` - Indicator (`true/false`) whether the application should ask the user to insert a _Device Name_ and pass it to the `MakeNewUser()` method.
+* `appID` - The _App ID_ used by the backend. The App ID is a unique ID assigned to each customer or application. It is a hex-encoded long numeric value. The App ID can be used only for information purposes and it does not affect the application's behavior in any way.
+
+#### Main Flows
+
+##### User Registration
+![*](M-Pin SDK - Registration flow.png)
+
+##### User Authentication to an Online Session
+![*](M-Pin SDK - Authentication to Browser Session flow.png)


[15/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #11 in MM/mpin-sdk-core from feature/refactor_users_backends to master

Posted by sa...@apache.org.
Merge pull request #11 in MM/mpin-sdk-core from feature/refactor_users_backends to master

* commit 'cad661feca828cbc706c477ef660cd2e6b168498':
  Refactor SDK Core to keep all users from all backends in memory


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/ac6536c4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/ac6536c4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/ac6536c4

Branch: refs/heads/master
Commit: ac6536c47bbb123fcafa83ad3dad034b60a92a3c
Parents: 0c9b7fa cad661f
Author: Slav Klenov <sl...@certivox.com>
Authored: Wed Apr 27 16:34:44 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Wed Apr 27 16:34:44 2016 +0200

----------------------------------------------------------------------
 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(-)
----------------------------------------------------------------------



[11/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #9 in MM/mpin-sdk-core from feature/delete_user_backend to master

Posted by sa...@apache.org.
Merge pull request #9 in MM/mpin-sdk-core from feature/delete_user_backend to master

* commit '5c5a025f04a43113e546adadbdf78a3ad7963102':
  Add DeleteUser function for specific backend.


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/8eef7233
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/8eef7233
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/8eef7233

Branch: refs/heads/master
Commit: 8eef723379f1e86c65cae1d0c55f33e236c76b87
Parents: e79c120 5c5a025
Author: Slav Klenov <sl...@certivox.com>
Authored: Tue Apr 26 09:52:43 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Tue Apr 26 09:52:43 2016 +0200

----------------------------------------------------------------------
 src/cv_shared_ptr.h  | 24 ++++++++++++--------
 src/mpin_sdk.cpp     | 57 ++++++++++++++++++++++++++++++++++++-----------
 src/mpin_sdk.h       |  6 ++++-
 tests/unit_tests.cpp |  5 ++++-
 4 files changed, 68 insertions(+), 24 deletions(-)
----------------------------------------------------------------------



[19/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #13 in MM/mpin-sdk-core from feature/bad_user_agent to master

Posted by sa...@apache.org.
Merge pull request #13 in MM/mpin-sdk-core from feature/bad_user_agent to master

* commit 'e6825711ab78d6220cccf5eaff92c016caf15b8a':
  Add BAD_USER_AGENT sdk status code


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/d388206f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/d388206f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/d388206f

Branch: refs/heads/master
Commit: d388206f4b6f26b5dc6d6b5ede1358183de7379a
Parents: a17c6b3 e682571
Author: Slav Klenov <sl...@certivox.com>
Authored: Fri Sep 2 13:45:04 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Fri Sep 2 13:45:04 2016 +0200

----------------------------------------------------------------------
 src/mpin_sdk.cpp | 9 ++++++++-
 src/mpin_sdk.h   | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
----------------------------------------------------------------------



[12/22] incubator-milagro-mfa-sdk-core git commit: Provide SDK API to get authentication session details

Posted by sa...@apache.org.
Provide SDK API to get authentication session details

Added SessionDetails class and GetSessionDetails() function.
Updated command line test.

Closes: MAASMOB-58


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/9640f6ea
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/9640f6ea
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/9640f6ea

Branch: refs/heads/master
Commit: 9640f6eaf631921db375cb70a6f7504181c1549f
Parents: 8eef723
Author: slav.klenov <sl...@certivox.com>
Authored: Tue Apr 26 12:41:23 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
Committed: Tue Apr 26 14:05:42 2016 +0300

----------------------------------------------------------------------
 src/mpin_sdk.cpp       | 25 ++++++++++++++++++++-----
 src/mpin_sdk.h         | 13 ++++++++++++-
 tests/cmdline_test.cpp | 15 ++++++++++++---
 3 files changed, 44 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/9640f6ea/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index ad86a75..65608aa 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -405,6 +405,7 @@ Status MPinSDK::HttpResponse::TranslateToMPinStatus(Context context)
     case GET_CLIENT_SETTINGS:
     case AUTHENTICATE_PASS1:
     case AUTHENTICATE_PASS2:
+    case GET_SESSION_DETAILS:
         break;
     case REGISTER:
         if(m_httpStatus == HTTP_FORBIDDEN)
@@ -1332,18 +1333,27 @@ bool MPinSDK::ValidateAccessNumberChecksum(const String& accessNumber)
     return calculatedCheckSum == checkSum;
 }
 
-String MPinSDK::GetPrerollUserId(const String& accessCode)
+void MPinSDK::SessionDetails::Clear()
 {
+    prerollId.clear();
+    appName.clear();
+    appIconUrl.clear();
+}
+
+Status MPinSDK::GetSessionDetails(const String& accessCode, OUT SessionDetails& sessionDetails)
+{
+    sessionDetails.Clear();
+
     Status s = CheckIfBackendIsSet();
     if(s != Status::OK)
     {
-        return "";
+        return s;
     }
 
     String codeStatusUrl = m_clientSettings.GetStringParam("codeStatusURL");
     if(codeStatusUrl.empty())
     {
-        return "";
+        return Status::OK;
     }
 
     util::JsonObject data;
@@ -1353,10 +1363,15 @@ String MPinSDK::GetPrerollUserId(const String& accessCode)
     HttpResponse response = MakeRequest(codeStatusUrl, IHttpRequest::POST, data);
     if(response.GetStatus() != HttpResponse::HTTP_OK)
     {
-        return "";
+        return response.TranslateToMPinStatus(HttpResponse::GET_SESSION_DETAILS);
     }
 
-    return response.GetJsonData().GetStringParam("prerollId");
+    const util::JsonObject& json = response.GetJsonData();
+    sessionDetails.prerollId = json.GetStringParam("prerollId");
+    sessionDetails.appName = json.GetStringParam("appName");
+    sessionDetails.appIconUrl = json.GetStringParam("appLogoURL");
+
+    return Status::OK;
 }
 
 void MPinSDK::DeleteUser(UserPtr user)

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/9640f6ea/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index f5f77b6..bd7a2f1 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -221,6 +221,16 @@ public:
 		Status status;
 	};
 
+    class SessionDetails
+    {
+    public:
+        void Clear();
+
+        String prerollId;
+        String appName;
+        String appIconUrl;
+    };
+
     MPinSDK();
     ~MPinSDK();
     Status Init(const StringMap& config, IN IContext* ctx);
@@ -243,7 +253,7 @@ public:
     Status FinishAuthenticationOTP(INOUT UserPtr user, const String& pin, OUT OTP& otp);
     Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);
 
-    String GetPrerollUserId(const String& accessCode);
+    Status GetSessionDetails(const String& accessCode, OUT SessionDetails& sessionDetails);
 
     void DeleteUser(INOUT UserPtr user);
     void DeleteUser(INOUT UserPtr user, const String& backend);
@@ -282,6 +292,7 @@ private:
             AUTHENTICATE_PASS1,
             AUTHENTICATE_PASS2,
             AUTHENTICATE_RPA,
+            GET_SESSION_DETAILS,
         };
 
         enum DataType

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/9640f6ea/tests/cmdline_test.cpp
----------------------------------------------------------------------
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index 685a37a..d08336b 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -82,7 +82,7 @@ int main(int argc, char *argv[])
     }
 
     bool testMaasWorkflow = false;
-    const char *maasBackend = "http://192.168.98.141:8001";
+    const char *maasBackend = "http://mpinaas-demo.miracl.net:8001";
     if(testMaasWorkflow)
     {
         s = sdk.SetBackend(maasBackend);
@@ -161,8 +161,17 @@ int main(int argc, char *argv[])
     {
         cout << "Enter access code: ";
         cin >> accessCode;
-        MPinSDK::String userId = sdk.GetPrerollUserId(accessCode);
-        cout << "GetPrerollUserId() returned '" << userId << "'. Press any key to continue..." << endl;
+        MPinSDK::SessionDetails sd;
+        s = sdk.GetSessionDetails(accessCode, sd);
+        if(s == MPinSDK::Status::OK)
+        {
+            cout << "GetSessionDetails() returned prerollId = '"
+                << sd.prerollId << "' appName = '" << sd.appName << "' appIconUrl = '" << sd.appIconUrl << "'" << endl;
+        }
+        else
+        {
+            cout << "ERROR: GetSessionDetails() returned status = " << s.GetStatusCode() << ", error = '" << s.GetErrorMessage() << "'" << endl;
+        }
     }
 
     s = sdk.StartAuthentication(user, accessCode);


[04/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #6 in MM/mpin-sdk-core from feature/slav_no_time_permits to master

Posted by sa...@apache.org.
Merge pull request #6 in MM/mpin-sdk-core from feature/slav_no_time_permits to master

* commit 'd0631f6010719ab9fe9f019039bfab1f1badfece':
  Add support for authentication without time permits


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/0c54c01e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/0c54c01e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/0c54c01e

Branch: refs/heads/master
Commit: 0c54c01e71f33438e4aba6c6f329e8f423087934
Parents: ad02ce3 d0631f6
Author: Slav Klenov <sl...@certivox.com>
Authored: Thu Mar 31 10:38:23 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Thu Mar 31 10:38:23 2016 +0200

----------------------------------------------------------------------
 src/json/reader.inl         | 11 +++++++----
 src/mpin_crypto_non_tee.cpp | 30 ++++++++++++++++++------------
 src/mpin_sdk.cpp            | 21 ++++++++++++++++-----
 tests/cmdline_test.cpp      |  1 +
 4 files changed, 42 insertions(+), 21 deletions(-)
----------------------------------------------------------------------



[09/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #8 in MM/mpin-sdk-core from bugfix/MAASMOB-40 to master

Posted by sa...@apache.org.
Merge pull request #8 in MM/mpin-sdk-core from bugfix/MAASMOB-40 to master

* commit 'c7805ec4576b5d70e46a4e450abd12a06780c440':
  Protect from failed allocations


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/e79c1203
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/e79c1203
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/e79c1203

Branch: refs/heads/master
Commit: e79c1203dca17b2e4acdd653d29d8ded6e5c52ee
Parents: acd0530 c7805ec
Author: Simeon Aladjem <si...@certivox.com>
Authored: Mon Apr 18 16:33:58 2016 +0200
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Mon Apr 18 16:33:58 2016 +0200

----------------------------------------------------------------------
 src/mpin_crypto_non_tee.cpp | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
----------------------------------------------------------------------



[13/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #10 in MM/mpin-sdk-core from feature/get_session_details to master

Posted by sa...@apache.org.
Merge pull request #10 in MM/mpin-sdk-core from feature/get_session_details to master

* commit '9640f6eaf631921db375cb70a6f7504181c1549f':
  Provide SDK API to get authentication session details


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/0c9b7fa6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/0c9b7fa6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/0c9b7fa6

Branch: refs/heads/master
Commit: 0c9b7fa6256ad4b2b90a14ce3ce7aabfbe6c16f6
Parents: 8eef723 9640f6e
Author: Slav Klenov <sl...@certivox.com>
Authored: Tue Apr 26 13:13:06 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Tue Apr 26 13:13:06 2016 +0200

----------------------------------------------------------------------
 src/mpin_sdk.cpp       | 25 ++++++++++++++++++++-----
 src/mpin_sdk.h         | 13 ++++++++++++-
 tests/cmdline_test.cpp | 15 ++++++++++++---
 3 files changed, 44 insertions(+), 9 deletions(-)
----------------------------------------------------------------------



[08/22] incubator-milagro-mfa-sdk-core git commit: Protect from failed allocations

Posted by sa...@apache.org.
Protect from failed allocations


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/c7805ec4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/c7805ec4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/c7805ec4

Branch: refs/heads/master
Commit: c7805ec4576b5d70e46a4e450abd12a06780c440
Parents: acd0530
Author: Simeon Aladjem <si...@certivox.com>
Authored: Fri Apr 15 17:01:20 2016 +0300
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Fri Apr 15 17:01:20 2016 +0300

----------------------------------------------------------------------
 src/mpin_crypto_non_tee.cpp | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/c7805ec4/src/mpin_crypto_non_tee.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_crypto_non_tee.cpp b/src/mpin_crypto_non_tee.cpp
index 77cdbc0..ebc991c 100644
--- a/src/mpin_crypto_non_tee.cpp
+++ b/src/mpin_crypto_non_tee.cpp
@@ -42,18 +42,27 @@ public:
 
 Octet::Octet(size_t maxSize)
 {
-    this->max = maxSize;
+    this->max = 0;
     this->len = 0;
     this->val = (char *) calloc(maxSize, 1);
+	if(this->val != NULL)
+	{
+		this->max = maxSize;		
+	}		
 }
 
 Octet::Octet(const String& str)
 {
+    this->max = 0;
+    this->len = 0;
     size_t maxSize = str.size();
-    this->max = maxSize;
-    this->len = maxSize;
     this->val = (char *) malloc(maxSize);
-    memcpy(this->val, str.c_str(), maxSize);
+	if(this->val != NULL)
+	{
+		this->max = maxSize;
+		this->len = maxSize;
+		memcpy(this->val, str.c_str(), maxSize);		
+	}
 }
 
 Octet::~Octet()


[16/22] incubator-milagro-mfa-sdk-core git commit: Add custom headers to MPinSDK

Posted by sa...@apache.org.
Add custom headers to MPinSDK

Added custom headers that MPinSDK will send upon each request.
Added visual studio 2015 project.
Fixed CvTime compilation issue with windows platform sdk v14.


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/50a8169a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/50a8169a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/50a8169a

Branch: refs/heads/master
Commit: 50a8169a7062b963e39e9fd0dc895719d51e261b
Parents: ac6536c
Author: Slav Klenov <sl...@miracl.com>
Authored: Thu Jul 7 17:42:16 2016 +0300
Committer: Slav Klenov <sl...@miracl.com>
Committed: Thu Jul 7 17:42:16 2016 +0300

----------------------------------------------------------------------
 .gitignore                                      |   3 +
 ext/cvshared/cpp/include/CvTime.h               |  15 +-
 project/visual_studio_2015/mpin_sdk.sln         |  41 ++++
 project/visual_studio_2015/mpin_sdk.vcxproj     | 145 +++++++++++++
 .../visual_studio_2015/mpin_sdk.vcxproj.filters | 204 +++++++++++++++++++
 .../visual_studio_2015/mpin_sdk_test.vcxproj    |  93 +++++++++
 .../mpin_sdk_test.vcxproj.filters               |  24 +++
 .../mpin_sdk_test_common.vcxproj                |  90 ++++++++
 .../mpin_sdk_test_common.vcxproj.filters        |  36 ++++
 project/visual_studio_2015/unit_tests.vcxproj   |  94 +++++++++
 .../unit_tests.vcxproj.filters                  |  24 +++
 src/mpin_sdk.cpp                                |  16 +-
 src/mpin_sdk.h                                  |   2 +
 13 files changed, 776 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 3e0ce62..c32d55d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,9 @@ dist/
 *.opensdf
 *.suo
 *.user
+.vs/
+*.VC.db
+*.VC.opendb
 *tokens.json
 *users.json
 cvlog.txt

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/ext/cvshared/cpp/include/CvTime.h
----------------------------------------------------------------------
diff --git a/ext/cvshared/cpp/include/CvTime.h b/ext/cvshared/cpp/include/CvTime.h
index 3401b43..4ca6268 100644
--- a/ext/cvshared/cpp/include/CvTime.h
+++ b/ext/cvshared/cpp/include/CvTime.h
@@ -48,11 +48,6 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 	#include "windows.h"
 
 	#define CLOCK_REALTIME	0
-	struct timespec
-	{
-		time_t	tv_sec;		/* seconds */
-		time_t	tv_nsec;	/* nanoseconds */
-	};
 
 	namespace CvShared
 	{
@@ -595,14 +590,14 @@ bool Days::operator>( const Days& aOther ) const	{ return m_value > aOther.m_val
 
 TimeSpec::TimeSpec()								{ tv_sec = 0; tv_nsec = 0; }
 TimeSpec::TimeSpec( const struct timespec& aTimespec )	{ tv_sec = aTimespec.tv_sec; tv_nsec = aTimespec.tv_nsec; }
-TimeSpec::TimeSpec( const Nanosecs& aNanosecs )		{ tv_sec = aNanosecs.ToSeconds(); tv_nsec = aNanosecs.Value() % Seconds(1).ToNanosecs(); }
-TimeSpec::TimeSpec( const Microsecs& aMicrosecs )	{ tv_sec = aMicrosecs.ToSeconds(); tv_nsec = Microsecs( aMicrosecs.Value() % Seconds(1).ToMicrosecs() ).ToNanosecs(); }
-TimeSpec::TimeSpec( const Millisecs& aMillisecs )	{ tv_sec = aMillisecs.ToSeconds(); tv_nsec = Millisecs( aMillisecs.Value() % Seconds(1).ToMillisecs() ).ToNanosecs(); }
+TimeSpec::TimeSpec( const Nanosecs& aNanosecs )		{ tv_sec = aNanosecs.ToSeconds(); tv_nsec = (long) aNanosecs.Value() % Seconds(1).ToNanosecs(); }
+TimeSpec::TimeSpec( const Microsecs& aMicrosecs )	{ tv_sec = aMicrosecs.ToSeconds(); tv_nsec = (long) Microsecs( aMicrosecs.Value() % Seconds(1).ToMicrosecs() ).ToNanosecs(); }
+TimeSpec::TimeSpec( const Millisecs& aMillisecs )	{ tv_sec = aMillisecs.ToSeconds(); tv_nsec = (long) Millisecs( aMillisecs.Value() % Seconds(1).ToMillisecs() ).ToNanosecs(); }
 TimeSpec::TimeSpec( const Seconds& aSeconds )		{ tv_sec = aSeconds.Value(); tv_nsec = 0; }
 TimeSpec::TimeSpec( const Minutes& aMinutes )		{ tv_sec = aMinutes.ToSeconds(); tv_nsec = 0; }
 TimeSpec::TimeSpec( const Hours& aHours )			{ tv_sec = aHours.ToSeconds(); tv_nsec = 0; }
 TimeSpec::TimeSpec( const Days& aDays )				{ tv_sec = aDays.ToSeconds(); tv_nsec = 0; }
-TimeSpec::TimeSpec( const TimeVal& aTimeval )		{ tv_sec = aTimeval.tv_sec; tv_nsec = Microsecs( aTimeval.tv_usec ).ToNanosecs(); }	
+TimeSpec::TimeSpec( const TimeVal& aTimeval )		{ tv_sec = aTimeval.tv_sec; tv_nsec = (long) Microsecs( aTimeval.tv_usec ).ToNanosecs(); }	
 
 TimeValue_t TimeSpec::ToNanosecs() const			{ return Seconds(tv_sec).ToNanosecs() + Nanosecs(tv_nsec).Value(); }
 TimeValue_t TimeSpec::ToMicrosecs() const			{ return Seconds(tv_sec).ToMicrosecs() + Nanosecs(tv_nsec).ToMicrosecs(); }	
@@ -642,7 +637,7 @@ TimeSpec& TimeSpec::operator-=( const TimeSpec& aOther )
 		if ( tv_nsec < 0 )
 		{
 			--tv_sec;
-			tv_nsec += Seconds(1).ToNanosecs();
+			tv_nsec += (long) Seconds(1).ToNanosecs();
 		}
 	}
 	else

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk.sln
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk.sln b/project/visual_studio_2015/mpin_sdk.sln
new file mode 100644
index 0000000..b4a1c59
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk.sln
@@ -0,0 +1,41 @@
+\ufeff
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk", "mpin_sdk.vcxproj", "{C47BB154-F9DF-4C88-81C0-A27510A16840}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit_tests", "unit_tests.vcxproj", "{A08A5798-A25B-4F9F-88A0-F196222A74F3}"
+	ProjectSection(ProjectDependencies) = postProject
+		{C47BB154-F9DF-4C88-81C0-A27510A16840} = {C47BB154-F9DF-4C88-81C0-A27510A16840}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk_test", "mpin_sdk_test.vcxproj", "{39536C4B-3293-4AD4-951F-0C4D5BCE7219}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpin_sdk_test_common", "mpin_sdk_test_common.vcxproj", "{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Debug|Win32.ActiveCfg = Debug|Win32
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Debug|Win32.Build.0 = Debug|Win32
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Release|Win32.ActiveCfg = Release|Win32
+		{C47BB154-F9DF-4C88-81C0-A27510A16840}.Release|Win32.Build.0 = Release|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Debug|Win32.Build.0 = Debug|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Release|Win32.ActiveCfg = Release|Win32
+		{A08A5798-A25B-4F9F-88A0-F196222A74F3}.Release|Win32.Build.0 = Release|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Debug|Win32.ActiveCfg = Debug|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Debug|Win32.Build.0 = Debug|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Release|Win32.ActiveCfg = Release|Win32
+		{39536C4B-3293-4AD4-951F-0C4D5BCE7219}.Release|Win32.Build.0 = Release|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Debug|Win32.ActiveCfg = Debug|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Debug|Win32.Build.0 = Debug|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Release|Win32.ActiveCfg = Release|Win32
+		{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk.vcxproj b/project/visual_studio_2015/mpin_sdk.vcxproj
new file mode 100644
index 0000000..123ddfe
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk.vcxproj
@@ -0,0 +1,145 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{C47BB154-F9DF-4C88-81C0-A27510A16840}</ProjectGuid>
+    <RootNamespace>mpin_sdk</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvString.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvTime.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvXcode.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvHttpRequest.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvLogger.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvMutex.cpp" />
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvThread.cpp" />
+    <ClCompile Include="..\..\src\crypto\aes.c" />
+    <ClCompile Include="..\..\src\crypto\big.c" />
+    <ClCompile Include="..\..\src\crypto\ecp.c" />
+    <ClCompile Include="..\..\src\crypto\ecp2.c" />
+    <ClCompile Include="..\..\src\crypto\ff.c" />
+    <ClCompile Include="..\..\src\crypto\fp.c" />
+    <ClCompile Include="..\..\src\crypto\fp12.c" />
+    <ClCompile Include="..\..\src\crypto\fp2.c" />
+    <ClCompile Include="..\..\src\crypto\fp4.c" />
+    <ClCompile Include="..\..\src\crypto\gcm.c" />
+    <ClCompile Include="..\..\src\crypto\hash.c" />
+    <ClCompile Include="..\..\src\crypto\mpin.c" />
+    <ClCompile Include="..\..\src\crypto\oct.c" />
+    <ClCompile Include="..\..\src\crypto\pair.c" />
+    <ClCompile Include="..\..\src\crypto\rand.c" />
+    <ClCompile Include="..\..\src\crypto\rom.c" />
+    <ClCompile Include="..\..\src\crypto\version.c" />
+    <ClCompile Include="..\..\src\mpin_crypto_non_tee.cpp" />
+    <ClCompile Include="..\..\src\mpin_sdk.cpp" />
+    <ClCompile Include="..\..\src\utils.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvCommon.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvHttpCommon.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvHttpRequest.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvLogger.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvMutex.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvString.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvThread.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvTime.h" />
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvXcode.h" />
+    <ClInclude Include="..\..\src\crypto\clint.h" />
+    <ClInclude Include="..\..\src\crypto\DLLDefines.h" />
+    <ClInclude Include="..\..\src\crypto\mpin.h" />
+    <ClInclude Include="..\..\src\crypto\platform.h" />
+    <ClInclude Include="..\..\src\crypto\version.h" />
+    <ClInclude Include="..\..\src\cv_shared_ptr.h" />
+    <ClInclude Include="..\..\src\json\elements.h" />
+    <ClInclude Include="..\..\src\json\reader.h" />
+    <ClInclude Include="..\..\src\json\visitor.h" />
+    <ClInclude Include="..\..\src\json\writer.h" />
+    <ClInclude Include="..\..\src\mpin_crypto.h" />
+    <ClInclude Include="..\..\src\mpin_crypto_non_tee.h" />
+    <ClInclude Include="..\..\src\mpin_sdk.h" />
+    <ClInclude Include="..\..\src\utf8.h" />
+    <ClInclude Include="..\..\src\utf8\checked.h" />
+    <ClInclude Include="..\..\src\utf8\core.h" />
+    <ClInclude Include="..\..\src\utf8\unchecked.h" />
+    <ClInclude Include="..\..\src\utils.h" />
+    <ClInclude Include="..\..\src\version.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\src\json\elements.inl" />
+    <None Include="..\..\src\json\reader.inl" />
+    <None Include="..\..\src\json\writer.inl" />
+    <None Include="unit_tests.vcxproj.filters" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk.vcxproj.filters
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk.vcxproj.filters b/project/visual_studio_2015/mpin_sdk.vcxproj.filters
new file mode 100644
index 0000000..ee68199
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk.vcxproj.filters
@@ -0,0 +1,204 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{1f2b4e9c-59f9-4a1f-ad54-75881b53a336}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\crypto">
+      <UniqueIdentifier>{cd1eafab-bcdb-4e59-aa36-87cd6762cfe3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\json">
+      <UniqueIdentifier>{dde06548-f846-45f7-9f2e-2db976eda377}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\utf8">
+      <UniqueIdentifier>{733f58c9-cbd3-42f6-a6d3-cb6c0bc53272}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="ext">
+      <UniqueIdentifier>{40bf2383-eb37-43aa-89b4-3292a44ee00c}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="ext\cvshared">
+      <UniqueIdentifier>{1dc90bf8-1a9d-4f94-bb96-30318d0f9197}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\mpin_crypto_non_tee.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\mpin_sdk.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvHttpRequest.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvMutex.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvTime.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvString.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvLogger.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\CvXcode.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\cvshared\cpp\windows\CvThread.cpp">
+      <Filter>ext\cvshared</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\aes.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\big.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\ecp.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\ecp2.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\ff.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\fp.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\fp2.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\fp4.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\fp12.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\gcm.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\hash.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\mpin.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\oct.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\pair.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\rand.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\rom.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\crypto\version.c">
+      <Filter>src\crypto</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\utils.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\src\mpin_crypto.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\mpin_crypto_non_tee.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\mpin_sdk.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\json\elements.h">
+      <Filter>src\json</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\json\reader.h">
+      <Filter>src\json</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\json\visitor.h">
+      <Filter>src\json</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\json\writer.h">
+      <Filter>src\json</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\cv_shared_ptr.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\utf8.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\utf8\checked.h">
+      <Filter>src\utf8</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\utf8\core.h">
+      <Filter>src\utf8</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\utf8\unchecked.h">
+      <Filter>src\utf8</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvCommon.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvHttpCommon.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvHttpRequest.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvMutex.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvTime.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvString.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvLogger.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvXcode.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\version.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\cvshared\cpp\include\CvThread.h">
+      <Filter>ext\cvshared</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\crypto\clint.h">
+      <Filter>src\crypto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\crypto\DLLDefines.h">
+      <Filter>src\crypto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\crypto\mpin.h">
+      <Filter>src\crypto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\crypto\version.h">
+      <Filter>src\crypto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\crypto\platform.h">
+      <Filter>src\crypto</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\utils.h">
+      <Filter>src</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\src\json\elements.inl">
+      <Filter>src\json</Filter>
+    </None>
+    <None Include="..\..\src\json\reader.inl">
+      <Filter>src\json</Filter>
+    </None>
+    <None Include="..\..\src\json\writer.inl">
+      <Filter>src\json</Filter>
+    </None>
+    <None Include="unit_tests.vcxproj.filters" />
+  </ItemGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk_test.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test.vcxproj b/project/visual_studio_2015/mpin_sdk_test.vcxproj
new file mode 100644
index 0000000..0b2a43f
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk_test.vcxproj
@@ -0,0 +1,93 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{39536C4B-3293-4AD4-951F-0C4D5BCE7219}</ProjectGuid>
+    <RootNamespace>mpin_sdk_test</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\cmdline_test.cpp" />
+    <ClCompile Include="..\..\tests\contexts\cmdline_context.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="mpin_sdk.vcxproj">
+      <Project>{c47bb154-f9df-4c88-81c0-a27510a16840}</Project>
+    </ProjectReference>
+    <ProjectReference Include="mpin_sdk_test_common.vcxproj">
+      <Project>{ab7741c8-a26b-4d8d-a0bc-806b5ac86cd9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\contexts\cmdline_context.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk_test.vcxproj.filters
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test.vcxproj.filters b/project/visual_studio_2015/mpin_sdk_test.vcxproj.filters
new file mode 100644
index 0000000..8ba0e25
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk_test.vcxproj.filters
@@ -0,0 +1,24 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{8d8eb6a0-6fa5-40bc-98d7-c54ff7d5cef3}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\contexts">
+      <UniqueIdentifier>{1f200816-1a1d-4f18-8207-e039c8911a1a}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\cmdline_test.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\contexts\cmdline_context.cpp">
+      <Filter>src\contexts</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\contexts\cmdline_context.h">
+      <Filter>src\contexts</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
new file mode 100644
index 0000000..45face2
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj
@@ -0,0 +1,90 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{AB7741C8-A26B-4D8D-A0BC-806B5AC86CD9}</ProjectGuid>
+    <RootNamespace>mpin_sdk_test_common</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\common\access_number_thread.cpp" />
+    <ClCompile Include="..\..\tests\common\file_storage.cpp" />
+    <ClCompile Include="..\..\tests\common\http_request.cpp" />
+    <ClCompile Include="..\..\tests\common\memory_storage.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\common\access_number_thread.h" />
+    <ClInclude Include="..\..\tests\common\file_storage.h" />
+    <ClInclude Include="..\..\tests\common\http_request.h" />
+    <ClInclude Include="..\..\tests\common\memory_storage.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
new file mode 100644
index 0000000..9c5aefc
--- /dev/null
+++ b/project/visual_studio_2015/mpin_sdk_test_common.vcxproj.filters
@@ -0,0 +1,36 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{929ee623-bfc7-49e0-b7cb-71a4eb695eb2}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\common\file_storage.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\http_request.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\memory_storage.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\common\access_number_thread.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\common\file_storage.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\http_request.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\memory_storage.h">
+      <Filter>src</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\tests\common\access_number_thread.h">
+      <Filter>src</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/unit_tests.vcxproj
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/unit_tests.vcxproj b/project/visual_studio_2015/unit_tests.vcxproj
new file mode 100644
index 0000000..be27489
--- /dev/null
+++ b/project/visual_studio_2015/unit_tests.vcxproj
@@ -0,0 +1,94 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A08A5798-A25B-4F9F-88A0-F196222A74F3}</ProjectGuid>
+    <RootNamespace>unit_tests</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(SolutionDir)bin\$(ProjectName)\$(Configuration)\</OutDir>
+    <IntDir>bin\$(ProjectName)\$(Configuration)\</IntDir>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>../../ext/boost; ../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>../../ext/boost; ../../src; ../../ext/cvshared/cpp/include</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;WinHttp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\contexts\auto_context.cpp" />
+    <ClCompile Include="..\..\tests\unit_tests.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="mpin_sdk.vcxproj">
+      <Project>{c47bb154-f9df-4c88-81c0-a27510a16840}</Project>
+    </ProjectReference>
+    <ProjectReference Include="mpin_sdk_test_common.vcxproj">
+      <Project>{ab7741c8-a26b-4d8d-a0bc-806b5ac86cd9}</Project>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\contexts\auto_context.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/project/visual_studio_2015/unit_tests.vcxproj.filters
----------------------------------------------------------------------
diff --git a/project/visual_studio_2015/unit_tests.vcxproj.filters b/project/visual_studio_2015/unit_tests.vcxproj.filters
new file mode 100644
index 0000000..93a6d97
--- /dev/null
+++ b/project/visual_studio_2015/unit_tests.vcxproj.filters
@@ -0,0 +1,24 @@
+\ufeff<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="src">
+      <UniqueIdentifier>{10ea346d-7f81-4894-93cf-de1a2517e2e9}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="src\contexts">
+      <UniqueIdentifier>{9f1c3291-16ce-47a2-8ec0-15d6731b6edc}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\tests\unit_tests.cpp">
+      <Filter>src</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\tests\contexts\auto_context.cpp">
+      <Filter>src\contexts</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\..\tests\contexts\auto_context.h">
+      <Filter>src\contexts</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index 41d34b3..5cfe7a4 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -540,12 +540,20 @@ MPinSDK::HttpResponse MPinSDK::MakeRequest(const String& url, HttpMethod method,
     String requestBody = bodyJson.ToString();
     HttpResponse response(url, requestBody);
 
+    StringMap headers = m_customHeaders;
     if(method != IHttpRequest::GET)
     {
-        StringMap headers;
         headers.Put(IHttpRequest::CONTENT_TYPE_HEADER, IHttpRequest::JSON_CONTENT_TYPE);
         headers.Put(IHttpRequest::ACCEPT_HEADER, IHttpRequest::TEXT_PLAIN_CONTENT_TYPE);
+    }
+
+    if(!headers.empty())
+    {
         r->SetHeaders(headers);
+    }
+
+    if(method != IHttpRequest::GET)
+    {
         r->SetContent(requestBody);
     }
 
@@ -630,12 +638,18 @@ Status MPinSDK::RewriteRelativeUrls()
 
 Status MPinSDK::Init(const StringMap& config, IContext* ctx)
 {
+    return Init(config, ctx, StringMap());
+}
+
+Status MPinSDK::Init(const StringMap& config, IContext* ctx, const StringMap& customHeaders)
+{
     if(IsInitilized())
     {
         return Status(Status::OK);
     }
 
     m_context = ctx;
+    m_customHeaders = customHeaders;
 
     if(ctx->GetMPinCryptoType() == CRYPTO_NON_TEE)
     {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/50a8169a/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index 77ca6f6..fdaa2ba 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -238,6 +238,7 @@ public:
     MPinSDK();
     ~MPinSDK();
     Status Init(const StringMap& config, IN IContext* ctx);
+    Status Init(const StringMap& config, IN IContext* ctx, const StringMap& customHeaders);
     void Destroy();
     void ClearUsers();
 
@@ -381,6 +382,7 @@ private:
     util::JsonObject m_clientSettings;
     UsersMap m_users;
     LogoutDataMap m_logoutData;
+    StringMap m_customHeaders;
 };
 
 #endif // _MPIN_SDK_H_



[02/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #5 in MM/mpin-sdk-core from feature/slav_backend_users to master

Posted by sa...@apache.org.
Merge pull request #5 in MM/mpin-sdk-core from feature/slav_backend_users to master

* commit '7815a9734835ccb82df3814b6c30c6378706a438':
  Add ListUsers for specific backend and ListBackends functions.


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/ad02ce34
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/ad02ce34
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/ad02ce34

Branch: refs/heads/master
Commit: ad02ce348c988f84611db31c46af0c7bd9fb0d74
Parents: 441caba 7815a97
Author: Slav Klenov <sl...@certivox.com>
Authored: Wed Mar 30 12:34:53 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Wed Mar 30 12:34:53 2016 +0200

----------------------------------------------------------------------
 project/visual_studio_2012/unit_tests.vcxproj |  1 +
 src/mpin_sdk.cpp                              | 51 +++++++++++++++++++---
 src/mpin_sdk.h                                | 13 +++---
 tests/cmdline_test.cpp                        | 22 ++++++++++
 tests/unit_tests.cpp                          | 21 ++++++---
 5 files changed, 93 insertions(+), 15 deletions(-)
----------------------------------------------------------------------



[18/22] incubator-milagro-mfa-sdk-core git commit: Add BAD_USER_AGENT sdk status code

Posted by sa...@apache.org.
Add BAD_USER_AGENT sdk status code

Return BAD_USER_AGENT sdk status code in response to each HTTP request, returning HTTP_NOT_ACCEPTABLE(406).


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/e6825711
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/e6825711
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/e6825711

Branch: refs/heads/master
Commit: e6825711ab78d6220cccf5eaff92c016caf15b8a
Parents: a17c6b3
Author: Slav Klenov <sl...@miracl.com>
Authored: Fri Sep 2 12:11:20 2016 +0300
Committer: Slav Klenov <sl...@miracl.com>
Committed: Fri Sep 2 14:39:53 2016 +0300

----------------------------------------------------------------------
 src/mpin_sdk.cpp | 9 ++++++++-
 src/mpin_sdk.h   | 2 ++
 2 files changed, 10 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/e6825711/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index 5cfe7a4..d438156 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -401,7 +401,14 @@ void MPinSDK::HttpResponse::SetHttpError(int httpStatus)
     }
     else if(httpStatus >= 400)
     {
-        m_mpinStatus.SetStatusCode(Status::HTTP_REQUEST_ERROR);
+        if (httpStatus == HTTP_NOT_ACCEPTABLE)
+        {
+            m_mpinStatus.SetStatusCode(Status::BAD_USER_AGENT);
+        }
+        else
+        {
+            m_mpinStatus.SetStatusCode(Status::HTTP_REQUEST_ERROR);
+        }
     }
     else if(httpStatus >= 300)
     {

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/e6825711/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index fdaa2ba..37aa636 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -127,6 +127,7 @@ public:
             INCORRECT_ACCESS_NUMBER, // Remote/local error - wrong access number (checksum failed or RPS returned 412)
             HTTP_SERVER_ERROR, // Remote error, that was not reduced to one of the above - the remote server returned internal server error status (5xx)
             HTTP_REQUEST_ERROR, // Remote error, that was not reduced to one of the above - invalid data sent to server, the remote server returned 4xx error status
+            BAD_USER_AGENT, // Remote error - user agent not supported
         };
 
         Status();
@@ -282,6 +283,7 @@ private:
         static const int HTTP_BAD_REQUEST = 400;
         static const int HTTP_UNAUTHORIZED = 401;
         static const int HTTP_FORBIDDEN = 403;
+        static const int HTTP_NOT_ACCEPTABLE = 406;
         static const int HTTP_REQUEST_TIMEOUT = 408;
         static const int HTTP_GONE = 410;
         static const int HTTP_PRECONDITION_FAILED = 412;


[07/22] incubator-milagro-mfa-sdk-core git commit: Fix the field name "user" -> "userId" in the codeStatus request.

Posted by sa...@apache.org.
Fix the field name "user" -> "userId" in the codeStatus request.


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/acd0530b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/acd0530b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/acd0530b

Branch: refs/heads/master
Commit: acd0530bc597f27c93ebeda3059107f553b955a0
Parents: 58448b9
Author: Simeon Aladjem <si...@certivox.com>
Authored: Thu Apr 7 11:04:42 2016 +0300
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Thu Apr 7 11:04:42 2016 +0300

----------------------------------------------------------------------
 src/mpin_sdk.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/acd0530b/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index c9a17f6..dcaecbe 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -991,7 +991,7 @@ Status MPinSDK::StartAuthentication(INOUT UserPtr user, const String& accessCode
         util::JsonObject data;
         data["status"] = json::String("user");
         data["wid"] = json::String(accessCode);
-        data["user"] = json::String(user->GetId());
+        data["userId"] = json::String(user->GetId());
         MakeRequest(codeStatusURL, IHttpRequest::POST, data);
     }
 


[21/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #14 in MM/mpin-sdk-core from feature/client_secret_expired to master

Posted by sa...@apache.org.
Merge pull request #14 in MM/mpin-sdk-core from feature/client_secret_expired to master

* commit 'fbb695cd07ec50566c685bc61b260a107cc9f5c1':
  Add CLIENT_SECRET_EXPIRED sdk status code


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/e631fb2d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/e631fb2d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/e631fb2d

Branch: refs/heads/master
Commit: e631fb2db35485114e6628abee12a28989e35cff
Parents: d388206 fbb695c
Author: Simeon Aladjem <si...@certivox.com>
Authored: Wed Sep 7 15:24:57 2016 +0200
Committer: Simeon Aladjem <si...@certivox.com>
Committed: Wed Sep 7 15:24:57 2016 +0200

----------------------------------------------------------------------
 src/mpin_sdk.cpp | 5 +++++
 src/mpin_sdk.h   | 2 ++
 2 files changed, 7 insertions(+)
----------------------------------------------------------------------



[06/22] incubator-milagro-mfa-sdk-core git commit: Merge pull request #7 in MM/mpin-sdk-core from feature/slav_maas_workflow to master

Posted by sa...@apache.org.
Merge pull request #7 in MM/mpin-sdk-core from feature/slav_maas_workflow to master

* commit '67c800f5884009a2981b13b5e1def3417becfeff':
  Add support for the MaaS workflow


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/58448b9b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/58448b9b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/58448b9b

Branch: refs/heads/master
Commit: 58448b9b6a1a05e8f5f662bd6c34a0192dca43c8
Parents: 0c54c01 67c800f
Author: Slav Klenov <sl...@certivox.com>
Authored: Thu Mar 31 17:41:05 2016 +0200
Committer: Slav Klenov <sl...@certivox.com>
Committed: Thu Mar 31 17:41:05 2016 +0200

----------------------------------------------------------------------
 src/json/reader.inl    |  3 +-
 src/mpin_sdk.cpp       | 83 ++++++++++++++++++++++++++++++++++++++++-----
 src/mpin_sdk.h         | 10 +++---
 src/version.h          |  2 +-
 tests/cmdline_test.cpp | 32 +++++++++++++++--
 5 files changed, 112 insertions(+), 18 deletions(-)
----------------------------------------------------------------------



[05/22] incubator-milagro-mfa-sdk-core git commit: Add support for the MaaS workflow

Posted by sa...@apache.org.
Add support for the MaaS workflow

Added GetPrerollUserId() function.
Added optional accessCode parameter to StartAuthentication and modified it to POST to codeStatusURL.
Changed ListUsers and ListBackends function to return Status.
Fixed compilation error on Linux in JSON parser.
Changed SDK version string to "2.1.0".
Added possibility to test the MaaS workflow in cmdline_test.cpp.

Closes: MAASMOB-30


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/67c800f5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/tree/67c800f5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/diff/67c800f5

Branch: refs/heads/master
Commit: 67c800f5884009a2981b13b5e1def3417becfeff
Parents: 0c54c01
Author: slav.klenov <sl...@certivox.com>
Authored: Thu Mar 31 13:37:35 2016 +0300
Committer: slav.klenov <sl...@certivox.com>
Committed: Thu Mar 31 16:50:20 2016 +0300

----------------------------------------------------------------------
 src/json/reader.inl    |  3 +-
 src/mpin_sdk.cpp       | 83 ++++++++++++++++++++++++++++++++++++++++-----
 src/mpin_sdk.h         | 10 +++---
 src/version.h          |  2 +-
 tests/cmdline_test.cpp | 32 +++++++++++++++--
 5 files changed, 112 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/67c800f5/src/json/reader.inl
----------------------------------------------------------------------
diff --git a/src/json/reader.inl b/src/json/reader.inl
index 9211675..313e5cb 100644
--- a/src/json/reader.inl
+++ b/src/json/reader.inl
@@ -303,8 +303,7 @@ inline std::string Reader::MatchExpectedString(InputStream& inputStream, const s
 }
 
 static void ConsumeUnicode(std::istream& str, std::vector<utf8::uint16_t>& uni16) {
-    char bytes[4];
-    memset(bytes, 0, sizeof(bytes));
+    char bytes[4] = { '\0' };
     str.get(bytes[0]);
     str.get(bytes[1]);
     str.get(bytes[2]);

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/67c800f5/src/mpin_sdk.cpp
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.cpp b/src/mpin_sdk.cpp
index 3f94c73..c9a17f6 100644
--- a/src/mpin_sdk.cpp
+++ b/src/mpin_sdk.cpp
@@ -970,7 +970,7 @@ Status MPinSDK::FinishRegistration(INOUT UserPtr user, const String& pin)
     return Status::OK;
 }
 
-Status MPinSDK::StartAuthentication(INOUT UserPtr user)
+Status MPinSDK::StartAuthentication(INOUT UserPtr user, const String& accessCode)
 {
     Status s = CheckIfBackendIsSet();
     if(s != Status::OK)
@@ -985,6 +985,16 @@ Status MPinSDK::StartAuthentication(INOUT UserPtr user)
         return s;
     }
 
+    String codeStatusURL = m_clientSettings.GetStringParam("codeStatusURL");
+    if(!codeStatusURL.empty() && !accessCode.empty())
+    {
+        util::JsonObject data;
+        data["status"] = json::String("user");
+        data["wid"] = json::String(accessCode);
+        data["user"] = json::String(user->GetId());
+        MakeRequest(codeStatusURL, IHttpRequest::POST, data);
+    }
+
     bool useTimePermits = m_clientSettings.GetBoolParam("usePermits", true);
     if(!useTimePermits)
     {
@@ -1322,6 +1332,33 @@ bool MPinSDK::ValidateAccessNumberChecksum(const String& accessNumber)
     return calculatedCheckSum == checkSum;
 }
 
+String MPinSDK::GetPrerollUserId(const String& accessCode)
+{
+    Status s = CheckIfBackendIsSet();
+    if(s != Status::OK)
+    {
+        return "";
+    }
+
+    String codeStatusUrl = m_clientSettings.GetStringParam("codeStatusURL");
+    if(codeStatusUrl.empty())
+    {
+        return "";
+    }
+
+    util::JsonObject data;
+    data["status"] = json::String("wid");
+    data["wid"] = json::String(accessCode);
+
+    HttpResponse response = MakeRequest(codeStatusUrl, IHttpRequest::POST, data);
+    if(response.GetStatus() != HttpResponse::HTTP_OK)
+    {
+        return "";
+    }
+
+    return response.GetJsonData().GetStringParam("prerollId");
+}
+
 void MPinSDK::DeleteUser(UserPtr user)
 {
     UsersMap::iterator i = m_users.find(user->GetId());
@@ -1338,16 +1375,35 @@ void MPinSDK::DeleteUser(UserPtr user)
     m_logoutData.erase(user);
 }
 
-void MPinSDK::ListUsers(std::vector<UserPtr>& users) const
+Status MPinSDK::ListUsers(std::vector<UserPtr>& users) const
 {
+    Status s = CheckIfBackendIsSet();
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     ListUsers(users, m_users);
+    return Status::OK;
 }
 
-void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const
+Status MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const
 {
+    Status s = CheckIfIsInitialized();
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     UsersMap usersMap;
-    LoadUsersFromStorage(backend, usersMap);
+    s = LoadUsersFromStorage(backend, usersMap);
+    if(s != Status::OK)
+    {
+        return s;
+    }
+
     ListUsers(users, usersMap);
+    return Status::OK;
 }
 
 void MPinSDK::ListUsers(OUT std::vector<UserPtr>& users, const UsersMap& usersMap) const
@@ -1561,15 +1617,21 @@ Status MPinSDK::LoadUsersFromStorage(const String& backendServer, UsersMap& user
 	return Status(Status::OK);
 }
 
-void MPinSDK::ListBackends(OUT std::vector<String>& backends) const
+Status MPinSDK::ListBackends(OUT std::vector<String>& backends) const
 {
-	IStorage* storage = m_context->GetStorage(IStorage::NONSECURE);
+    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;
+		return Status::OK;
 	}
 
 	try
@@ -1583,7 +1645,12 @@ void MPinSDK::ListBackends(OUT std::vector<String>& backends) const
             backends.push_back(i->name);
         }
     }
-    catch(const json::Exception&) {}
+    catch(const json::Exception& e)
+    {
+        return Status(Status::STORAGE_ERROR, e.what());
+    }
+
+    return Status::OK;
 }
 
 const char * MPinSDK::GetVersion()

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/67c800f5/src/mpin_sdk.h
----------------------------------------------------------------------
diff --git a/src/mpin_sdk.h b/src/mpin_sdk.h
index 902189a..ec69d58 100644
--- a/src/mpin_sdk.h
+++ b/src/mpin_sdk.h
@@ -236,17 +236,19 @@ public:
     Status ConfirmRegistration(INOUT UserPtr user, const String& pushMessageIdentifier = "");
     Status FinishRegistration(INOUT UserPtr user, const String& pin);
 
-    Status StartAuthentication(INOUT UserPtr user);
+    Status StartAuthentication(INOUT UserPtr user, const String& accessCode = "");
     Status CheckAccessNumber(const String& accessNumber);
     Status FinishAuthentication(INOUT UserPtr user, const String& pin);
     Status FinishAuthentication(INOUT UserPtr user, const String& pin, OUT String& authResultData);
     Status FinishAuthenticationOTP(INOUT UserPtr user, const String& pin, OUT OTP& otp);
     Status FinishAuthenticationAN(INOUT UserPtr user, const String& pin, const String& accessNumber);
 
+    String GetPrerollUserId(const String& accessCode);
+
     void DeleteUser(INOUT UserPtr user);
-    void ListUsers(OUT std::vector<UserPtr>& users) const;
-    void ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;
-    void ListBackends(OUT std::vector<String>& backends) const;
+    Status ListUsers(OUT std::vector<UserPtr>& users) const;
+    Status ListUsers(OUT std::vector<UserPtr>& users, const String& backend) const;
+    Status ListBackends(OUT std::vector<String>& backends) const;
     const char * GetVersion();
     bool CanLogout(IN UserPtr user);
     bool Logout(IN UserPtr user);

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/67c800f5/src/version.h
----------------------------------------------------------------------
diff --git a/src/version.h b/src/version.h
index fc4b9bd..a9b268d 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.0.0"
+#define MPIN_SDK_V2_VERSION "2.1.0"
 
 #endif // _MPIN_SDK_VERSION_H_

http://git-wip-us.apache.org/repos/asf/incubator-milagro-mfa-sdk-core/blob/67c800f5/tests/cmdline_test.cpp
----------------------------------------------------------------------
diff --git a/tests/cmdline_test.cpp b/tests/cmdline_test.cpp
index 6957afd..685a37a 100644
--- a/tests/cmdline_test.cpp
+++ b/tests/cmdline_test.cpp
@@ -27,7 +27,10 @@ under the License.
 #include "contexts/cmdline_context.h"
 #include "CvLogger.h"
 
-using namespace std;
+using std::cout;
+using std::cin;
+using std::endl;
+using std::vector;
 
 struct Backend
 {
@@ -78,6 +81,13 @@ int main(int argc, char *argv[])
         TestBackend(sdk, backends[i].backend, backends[i].rpsPrefix);
     }
 
+    bool testMaasWorkflow = false;
+    const char *maasBackend = "http://192.168.98.141:8001";
+    if(testMaasWorkflow)
+    {
+        s = sdk.SetBackend(maasBackend);
+    }
+
     //s = sdk.SetBackend(backends[1].backend, backends[1].rpsPrefix);
     if(s != MPinSDK::Status::OK)
     {
@@ -146,7 +156,16 @@ int main(int argc, char *argv[])
         _getch();
     }
 
-    s = sdk.StartAuthentication(user);
+    MPinSDK::String accessCode;
+    if(testMaasWorkflow)
+    {
+        cout << "Enter access code: ";
+        cin >> accessCode;
+        MPinSDK::String userId = sdk.GetPrerollUserId(accessCode);
+        cout << "GetPrerollUserId() returned '" << userId << "'. Press any key to continue..." << endl;
+    }
+
+    s = sdk.StartAuthentication(user, accessCode);
     if(s != MPinSDK::Status::OK)
     {
         cout << "Failed to start user authentication: status code = " << s.GetStatusCode() << ", error: " << s.GetErrorMessage() << endl;
@@ -160,7 +179,14 @@ int main(int argc, char *argv[])
     cin >> pin;
 
     MPinSDK::String authData;
-    s = sdk.FinishAuthentication(user, pin, authData);
+    if(!testMaasWorkflow)
+    {
+        s = sdk.FinishAuthentication(user, pin, authData);
+    }
+    else
+    {
+        s = sdk.FinishAuthenticationAN(user, pin, accessCode);
+    }
     if(s != MPinSDK::Status::OK)
     {
         cout << "Failed to authenticate user: status code = " << s.GetStatusCode() << ", error: " << s.GetErrorMessage() << endl;