AWSCognitoAuthorizationController.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AWSClientAuthBus.h>
  9. #include <AWSCoreBus.h>
  10. #include <Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h>
  11. #include <Authorization/AWSCognitoAuthorizationController.h>
  12. #include <ResourceMapping/AWSResourceMappingBus.h>
  13. #include <AWSClientAuthResourceMappingConstants.h>
  14. #include <AzCore/EBus/Internal/BusContainer.h>
  15. #include <AzCore/Jobs/JobFunction.h>
  16. #include <AzCore/Interface/Interface.h>
  17. #include <AzCore/Settings/SettingsRegistryImpl.h>
  18. #include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
  19. namespace AWSClientAuth
  20. {
  21. constexpr char CognitoAmazonLoginsId[] = "www.amazon.com";
  22. constexpr char CognitoGoogleLoginsId[] = "accounts.google.com";
  23. constexpr char CognitoUserPoolIdFormat[] = "cognito-idp.%s.amazonaws.com/%s";
  24. AWSCognitoAuthorizationController::AWSCognitoAuthorizationController()
  25. {
  26. AZ::Interface<IAWSCognitoAuthorizationRequests>::Register(this);
  27. AWSCognitoAuthorizationRequestBus::Handler::BusConnect();
  28. AuthenticationProviderNotificationBus::Handler::BusConnect();
  29. AWSCore::AWSCredentialRequestBus::Handler::BusConnect();
  30. m_persistentCognitoIdentityProvider = std::make_shared<AWSClientAuthPersistentCognitoIdentityProvider>();
  31. m_persistentAnonymousCognitoIdentityProvider = std::make_shared<AWSClientAuthPersistentCognitoIdentityProvider>();
  32. auto identityClient = AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIdentityClient();
  33. m_cognitoCachingCredentialsProvider =
  34. std::make_shared<AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider>(
  35. m_persistentCognitoIdentityProvider, identityClient);
  36. m_cognitoCachingAnonymousCredentialsProvider =
  37. std::make_shared<AWSClientAuthCachingAnonymousCredsProvider>(
  38. m_persistentAnonymousCognitoIdentityProvider, identityClient);
  39. }
  40. AWSCognitoAuthorizationController::~AWSCognitoAuthorizationController()
  41. {
  42. m_cognitoCachingCredentialsProvider.reset();
  43. m_persistentAnonymousCognitoIdentityProvider.reset();
  44. m_persistentCognitoIdentityProvider.reset();
  45. m_persistentAnonymousCognitoIdentityProvider.reset();
  46. AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect();
  47. AuthenticationProviderNotificationBus::Handler::BusDisconnect();
  48. AWSCognitoAuthorizationRequestBus::Handler::BusDisconnect();
  49. AZ::Interface<IAWSCognitoAuthorizationRequests>::Unregister(this);
  50. }
  51. bool AWSCognitoAuthorizationController::Initialize()
  52. {
  53. AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
  54. m_awsAccountId, &AWSCore::AWSResourceMappingRequests::GetDefaultAccountId);
  55. AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
  56. m_cognitoIdentityPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoIdentityPoolIdResourceMappingKey);
  57. if (m_awsAccountId.empty())
  58. {
  59. AZ_TracePrintf("AWSCognitoAuthorizationController", "AWS account id not not configured. Proceeding without it.");
  60. }
  61. if (m_cognitoIdentityPoolId.empty())
  62. {
  63. AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings.");
  64. return false;
  65. }
  66. AZStd::string userPoolId;
  67. AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
  68. userPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoUserPoolIdResourceMappingKey);
  69. AZ_Warning("AWSCognitoAuthorizationController", !userPoolId.empty(), "Missing Cognito User pool id in resource mappings. Cognito IDP authenticated identities will not work.");
  70. AZStd::string defaultRegion;
  71. AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
  72. defaultRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
  73. m_formattedCognitoUserPoolId = AZStd::string::format(CognitoUserPoolIdFormat, defaultRegion.c_str(), userPoolId.c_str());
  74. m_persistentCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str());
  75. m_persistentAnonymousCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str());
  76. return true;
  77. }
  78. void AWSCognitoAuthorizationController::Reset()
  79. {
  80. // Brackets for lock guard scopes
  81. {
  82. AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
  83. m_persistentAnonymousCognitoIdentityProvider->ClearLogins();
  84. m_persistentAnonymousCognitoIdentityProvider->ClearIdentity();
  85. }
  86. {
  87. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  88. m_persistentCognitoIdentityProvider->ClearLogins();
  89. m_persistentCognitoIdentityProvider->ClearIdentity();
  90. }
  91. }
  92. AZStd::string AWSCognitoAuthorizationController::GetIdentityId()
  93. {
  94. // Give preference to authenticated credentials provider.
  95. if (HasPersistedLogins())
  96. {
  97. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  98. return m_persistentCognitoIdentityProvider->GetIdentityId().c_str();
  99. }
  100. else
  101. {
  102. AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
  103. return m_persistentAnonymousCognitoIdentityProvider->GetIdentityId().c_str();
  104. }
  105. }
  106. bool AWSCognitoAuthorizationController::HasPersistedLogins()
  107. {
  108. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  109. return m_persistentCognitoIdentityProvider->HasLogins();
  110. }
  111. std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetCognitoCredentialsProvider()
  112. {
  113. return m_cognitoCachingCredentialsProvider;
  114. }
  115. std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetAnonymousCognitoCredentialsProvider()
  116. {
  117. return m_cognitoCachingAnonymousCredentialsProvider;
  118. }
  119. void AWSCognitoAuthorizationController::RequestAWSCredentialsAsync()
  120. {
  121. bool anonymous = true;
  122. // Give preference to authenticated credentials provider.
  123. if (m_persistentCognitoIdentityProvider->HasLogins())
  124. {
  125. anonymous = false;
  126. }
  127. else
  128. {
  129. AZ_Warning("AWSCognitoAuthorizationController", false, "No logins found. Fetching anonymous/unauthenticated credentials");
  130. }
  131. AZ::JobContext* jobContext = nullptr;
  132. AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
  133. AZ::Job* job = AZ::CreateJobFunction(
  134. [this, anonymous]() {
  135. Aws::Auth::AWSCredentials credentials;
  136. // GetAWSCredentials makes Cognito GetId and GetCredentialsForIdentity Cognito identity pool API request if no valid cached credentials found.
  137. if (anonymous)
  138. {
  139. AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
  140. credentials = m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials();
  141. }
  142. else
  143. {
  144. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  145. credentials = m_cognitoCachingCredentialsProvider->GetAWSCredentials();
  146. }
  147. if (!credentials.IsEmpty())
  148. {
  149. ClientAuthAWSCredentials clientAuthAWSCrendentials(credentials.GetAWSAccessKeyId().c_str(), credentials.GetAWSSecretKey().c_str(), credentials.GetSessionToken().c_str());
  150. AWSClientAuth::AWSCognitoAuthorizationNotificationBus::Broadcast(
  151. &AWSClientAuth::AWSCognitoAuthorizationNotifications::OnRequestAWSCredentialsSuccess, clientAuthAWSCrendentials);
  152. }
  153. else
  154. {
  155. AWSClientAuth::AWSCognitoAuthorizationNotificationBus::Broadcast(
  156. &AWSClientAuth::AWSCognitoAuthorizationNotifications::OnRequestAWSCredentialsFail,
  157. "Failed to get AWS credentials");
  158. }
  159. },
  160. true, jobContext);
  161. job->Start();
  162. }
  163. AZStd::string AWSCognitoAuthorizationController::GetAuthenticationProviderId(const ProviderNameEnum& providerName)
  164. {
  165. switch (providerName)
  166. {
  167. case ProviderNameEnum::AWSCognitoIDP:
  168. {
  169. return m_formattedCognitoUserPoolId;
  170. }
  171. case ProviderNameEnum::LoginWithAmazon:
  172. {
  173. return CognitoAmazonLoginsId;
  174. }
  175. case ProviderNameEnum::Google:
  176. {
  177. return CognitoGoogleLoginsId;
  178. }
  179. default:
  180. {
  181. return "";
  182. }
  183. }
  184. }
  185. void AWSCognitoAuthorizationController::PersistLoginsAndRefreshAWSCredentials(const AuthenticationTokens& authenticationTokens)
  186. {
  187. // lock to persist logins as the object is shared with Native SDK. Native SDK reads logins and persists identity id and expiry.
  188. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  189. // Save logins to the shared persistent Cognito identity provider for authenticated authorization.
  190. // Append logins to existing map.
  191. Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> logins = m_persistentCognitoIdentityProvider->GetLogins();
  192. Aws::Auth::LoginAccessTokens tokens;
  193. tokens.accessToken = authenticationTokens.GetOpenIdToken().c_str();
  194. logins[GetAuthenticationProviderId(authenticationTokens.GetProviderName()).c_str()] = tokens;
  195. m_persistentCognitoIdentityProvider->PersistLogins(logins);
  196. }
  197. void AWSCognitoAuthorizationController::OnPasswordGrantSingleFactorSignInSuccess(const AWSClientAuth::AuthenticationTokens& authenticationTokens)
  198. {
  199. PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
  200. }
  201. void AWSCognitoAuthorizationController::OnPasswordGrantMultiFactorConfirmSignInSuccess(
  202. const AWSClientAuth::AuthenticationTokens& authenticationTokens)
  203. {
  204. PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
  205. }
  206. void AWSCognitoAuthorizationController::OnDeviceCodeGrantConfirmSignInSuccess(
  207. const AWSClientAuth::AuthenticationTokens& authenticationTokens)
  208. {
  209. PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
  210. }
  211. void AWSCognitoAuthorizationController::OnRefreshTokensSuccess(const AWSClientAuth::AuthenticationTokens& authenticationTokens)
  212. {
  213. PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
  214. }
  215. void AWSCognitoAuthorizationController::OnSignOut(const ProviderNameEnum& provideName)
  216. {
  217. // lock to persist logins as the object is shared with Native SDK.
  218. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  219. m_persistentCognitoIdentityProvider->RemoveLogin(GetAuthenticationProviderId(provideName).c_str());
  220. }
  221. int AWSCognitoAuthorizationController::GetCredentialHandlerOrder() const
  222. {
  223. return AWSCore::CredentialHandlerOrder::COGNITO_IDENITY_POOL_CREDENTIAL_HANDLER;
  224. }
  225. std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetCredentialsProvider()
  226. {
  227. // If logins are persisted default to using authenticated credentials provide.
  228. // Check authenticated credentials to verify persisted logins are valid.
  229. if (HasPersistedLogins())
  230. {
  231. // lock to protect logins being persisted.
  232. AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
  233. if (!m_cognitoCachingCredentialsProvider->GetAWSCredentials().IsEmpty())
  234. {
  235. return m_cognitoCachingCredentialsProvider;
  236. }
  237. }
  238. // Check anonymous credentials as they are optional settings in Cognito Identity pool.
  239. if (m_cognitoIdentityPoolId.empty())
  240. {
  241. // If the identity pool isn't set, then the anonymous credential won't be found.
  242. // Return null, instead of asking AWS for credentials to avoid failing AWS requests and AWS errors due to a null identity pool id.
  243. return nullptr;
  244. }
  245. // Lock to protect getting identity id.
  246. AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
  247. if (!m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials().IsEmpty())
  248. {
  249. AZ_Warning("AWSCognitoAuthorizationCredentialHandler", false, "No logins found. Using Anonymous credential provider");
  250. return m_cognitoCachingAnonymousCredentialsProvider;
  251. }
  252. return nullptr;
  253. }
  254. } // namespace AWSClientAuth