/** * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * SPDX-License-Identifier: Apache-2.0. */ #include #include #include #include #include using namespace Aws::Auth; using namespace Aws::Utils::Json; using namespace Aws::Utils; static const char* IDENTITY_ID = "IdentityId"; static const char* LOGINS = "Logins"; static const char* ACCESS_TOKEN = "AccessToken"; static const char* LONG_TERM_TOKEN = "LongTermToken"; static const char* EXPIRY = "Expiry"; static const char* FILENAME = ".identities"; static const char* DIR = ".aws"; static const char* LOG_TAG = "PersistentCognitoIdentityProvider_JsonFileImpl"; PersistentCognitoIdentityProvider_JsonFileImpl::PersistentCognitoIdentityProvider_JsonFileImpl(const Aws::String& identityPoolId, const Aws::String& accountId, bool disableCaching) : m_identityPoolId(identityPoolId), m_accountId(accountId), m_disableCaching(disableCaching) { Aws::String identitiesDir = Aws::FileSystem::GetHomeDirectory() + DIR; if (Aws::FileSystem::CreateDirectoryIfNotExists(identitiesDir.c_str())) { m_identityFilePath = identitiesDir + Aws::FileSystem::PATH_DELIM + FILENAME; } if(!m_disableCaching) { LoadAndParseDoc(); } } PersistentCognitoIdentityProvider_JsonFileImpl::PersistentCognitoIdentityProvider_JsonFileImpl(const Aws::String& identityPoolId, bool disableCaching) : m_identityPoolId(identityPoolId), m_disableCaching(disableCaching) { Aws::String identitiesDir = Aws::FileSystem::GetHomeDirectory() + DIR; if (Aws::FileSystem::CreateDirectoryIfNotExists(identitiesDir.c_str())) { m_identityFilePath = identitiesDir + Aws::FileSystem::PATH_DELIM + FILENAME; } if(!m_disableCaching) { LoadAndParseDoc(); } } PersistentCognitoIdentityProvider_JsonFileImpl::PersistentCognitoIdentityProvider_JsonFileImpl(const Aws::String& identityPoolId, const Aws::String& accountId, const char* identitiesFilePath, bool disableCaching) : m_identityPoolId(identityPoolId), m_accountId(accountId), m_identityFilePath(identitiesFilePath), m_disableCaching(disableCaching) { if(!m_disableCaching) { LoadAndParseDoc(); } } void PersistentCognitoIdentityProvider_JsonFileImpl::PersistIdentityId(const Aws::String& identityId) { { std::lock_guard locker(m_docMutex); m_identityId = identityId; auto jsonDoc = LoadJsonDocFromFile(); JsonValue identityNode; if (jsonDoc.View().ValueExists(m_identityPoolId)) { identityNode = jsonDoc.View().GetObject(m_identityPoolId).Materialize(); } identityNode.WithString(IDENTITY_ID, m_identityId); jsonDoc.WithObject(m_identityPoolId, std::move(identityNode)); PersistChangesToFile(jsonDoc); } if (m_identityIdUpdatedCallback) { m_identityIdUpdatedCallback(*this); } } void PersistentCognitoIdentityProvider_JsonFileImpl::PersistLogins(const Aws::Map& logins) { { std::lock_guard locker(m_docMutex); m_logins = logins; auto jsonDoc = LoadJsonDocFromFile(); JsonValue identityNode; if (jsonDoc.View().ValueExists(m_identityPoolId)) { identityNode = jsonDoc.View().GetObject(m_identityPoolId).Materialize(); } JsonValue loginsNode; for (auto& login : m_logins) { JsonValue loginNode; loginNode.WithString(ACCESS_TOKEN, login.second.accessToken); loginNode.WithString(LONG_TERM_TOKEN, login.second.longTermToken); loginNode.WithInt64(EXPIRY, login.second.longTermTokenExpiry); loginsNode.WithObject(login.first, std::move(loginNode)); } identityNode.WithObject(LOGINS, loginsNode); jsonDoc.WithObject(m_identityPoolId, std::move(identityNode)); PersistChangesToFile(jsonDoc); } if (m_loginsUpdatedCallback) { m_loginsUpdatedCallback(*this); } } JsonValue PersistentCognitoIdentityProvider_JsonFileImpl::LoadJsonDocFromFile() const { std::ifstream infile(m_identityFilePath.c_str()); if (infile.is_open() && infile.good()) { return JsonValue(infile); } else { AWS_LOGSTREAM_ERROR(LOG_TAG, "Failed reading from file " << m_identityFilePath); } return JsonValue(); } void PersistentCognitoIdentityProvider_JsonFileImpl::PersistChangesToFile(const JsonValue& jsonValue) const { //the assumption here is that we've already created the directory by the time we make it here. Aws::String identitiesFile = m_identityFilePath; std::ofstream outfile(identitiesFile.c_str(), std::ios_base::trunc | std::ios_base::out); if (outfile.is_open() && outfile.good()) { outfile << jsonValue.View().WriteReadable(); outfile.flush(); outfile.close(); } else { AWS_LOGSTREAM_ERROR(LOG_TAG, "Failed persisting changes to file."); } } void PersistentCognitoIdentityProvider_JsonFileImpl::LoadAndParseDoc() { auto jsonDoc = LoadJsonDocFromFile(); auto docView = jsonDoc.View(); if (docView.ValueExists(m_identityPoolId)) { auto identityNode = docView.GetObject(m_identityPoolId); m_identityId = identityNode.GetString(IDENTITY_ID); if (identityNode.ValueExists(LOGINS)) { auto logins = identityNode.GetObject(LOGINS).GetAllObjects(); BuildLoginsMap(logins, m_logins); } } } bool PersistentCognitoIdentityProvider_JsonFileImpl::HasIdentityId() const { if(m_disableCaching) { auto jsonDoc = LoadJsonDocFromFile(); auto docView = jsonDoc.View(); if (docView.ValueExists(m_identityPoolId)) { auto identityNode = docView.GetObject(m_identityPoolId); return !identityNode.GetString(IDENTITY_ID).empty(); } return false; } else { return !m_identityId.empty(); } } bool PersistentCognitoIdentityProvider_JsonFileImpl::HasLogins() const { if(m_disableCaching) { auto jsonDoc = LoadJsonDocFromFile(); auto docView = jsonDoc.View(); if (docView.ValueExists(m_identityPoolId)) { auto identityNode = docView.GetObject(m_identityPoolId); if (identityNode.ValueExists(LOGINS)) { auto logins = identityNode.GetObject(LOGINS).GetAllObjects(); return logins.size() > 0; } } return false; } else { return !m_logins.empty(); } } Aws::String PersistentCognitoIdentityProvider_JsonFileImpl::GetIdentityId() const { if(m_disableCaching) { auto jsonDoc = LoadJsonDocFromFile(); auto docView = jsonDoc.View(); if (docView.ValueExists(m_identityPoolId)) { auto identityNode = docView.GetObject(m_identityPoolId); return identityNode.GetString(IDENTITY_ID); } return ""; } else { return m_identityId; } } Aws::Map PersistentCognitoIdentityProvider_JsonFileImpl::GetLogins() { if(m_disableCaching) { Aws::Map logins; auto jsonDoc = LoadJsonDocFromFile(); auto docView = jsonDoc.View(); if (docView.ValueExists(m_identityPoolId)) { auto identityNode = docView.GetObject(m_identityPoolId); if (identityNode.ValueExists(LOGINS)) { auto loginsJsonMap = identityNode.GetObject(LOGINS).GetAllObjects(); BuildLoginsMap(loginsJsonMap, logins); } } return logins; } else { return m_logins; } } void PersistentCognitoIdentityProvider_JsonFileImpl::BuildLoginsMap(Aws::Map loginJsonMap, Aws::Map& logins) { for (auto& login : loginJsonMap) { auto& loginTokens = login.second; LoginAccessTokens loginAccessTokens; /*this block is for backwards compatibility with the previous implementation. This used to be a string: string mapping, if access token is not a member, then fallback and assign the value to the accessToken field. Now, next time it will save it in the new format.*/ if(loginTokens.IsString()) { loginAccessTokens.accessToken = loginTokens.AsString(); } else { if (loginTokens.ValueExists(ACCESS_TOKEN)) { loginAccessTokens.accessToken = loginTokens.GetString(ACCESS_TOKEN); } if (loginTokens.ValueExists(LONG_TERM_TOKEN)) { loginAccessTokens.longTermToken = loginTokens.GetString(LONG_TERM_TOKEN); } if (loginTokens.ValueExists(EXPIRY)) { loginAccessTokens.longTermTokenExpiry = loginTokens.GetInt64(EXPIRY); } } logins[login.first] = loginAccessTokens; } }