123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AWSClientAuthBus.h>
- #include <AWSCoreBus.h>
- #include <Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h>
- #include <Authorization/AWSCognitoAuthorizationController.h>
- #include <ResourceMapping/AWSResourceMappingBus.h>
- #include <AWSClientAuthResourceMappingConstants.h>
- #include <AzCore/EBus/Internal/BusContainer.h>
- #include <AzCore/Jobs/JobFunction.h>
- #include <AzCore/Interface/Interface.h>
- #include <AzCore/Settings/SettingsRegistryImpl.h>
- #include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
- namespace AWSClientAuth
- {
- constexpr char CognitoAmazonLoginsId[] = "www.amazon.com";
- constexpr char CognitoGoogleLoginsId[] = "accounts.google.com";
- constexpr char CognitoUserPoolIdFormat[] = "cognito-idp.%s.amazonaws.com/%s";
- AWSCognitoAuthorizationController::AWSCognitoAuthorizationController()
- {
- AZ::Interface<IAWSCognitoAuthorizationRequests>::Register(this);
- AWSCognitoAuthorizationRequestBus::Handler::BusConnect();
- AuthenticationProviderNotificationBus::Handler::BusConnect();
- AWSCore::AWSCredentialRequestBus::Handler::BusConnect();
- m_persistentCognitoIdentityProvider = std::make_shared<AWSClientAuthPersistentCognitoIdentityProvider>();
- m_persistentAnonymousCognitoIdentityProvider = std::make_shared<AWSClientAuthPersistentCognitoIdentityProvider>();
- auto identityClient = AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIdentityClient();
- m_cognitoCachingCredentialsProvider =
- std::make_shared<AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider>(
- m_persistentCognitoIdentityProvider, identityClient);
- m_cognitoCachingAnonymousCredentialsProvider =
- std::make_shared<AWSClientAuthCachingAnonymousCredsProvider>(
- m_persistentAnonymousCognitoIdentityProvider, identityClient);
- }
- AWSCognitoAuthorizationController::~AWSCognitoAuthorizationController()
- {
- m_cognitoCachingCredentialsProvider.reset();
- m_persistentAnonymousCognitoIdentityProvider.reset();
- m_persistentCognitoIdentityProvider.reset();
- m_persistentAnonymousCognitoIdentityProvider.reset();
- AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect();
- AuthenticationProviderNotificationBus::Handler::BusDisconnect();
- AWSCognitoAuthorizationRequestBus::Handler::BusDisconnect();
- AZ::Interface<IAWSCognitoAuthorizationRequests>::Unregister(this);
- }
- bool AWSCognitoAuthorizationController::Initialize()
- {
- AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
- m_awsAccountId, &AWSCore::AWSResourceMappingRequests::GetDefaultAccountId);
- AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
- m_cognitoIdentityPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoIdentityPoolIdResourceMappingKey);
- if (m_awsAccountId.empty())
- {
- AZ_TracePrintf("AWSCognitoAuthorizationController", "AWS account id not not configured. Proceeding without it.");
- }
- if (m_cognitoIdentityPoolId.empty())
- {
- AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings.");
- return false;
- }
- AZStd::string userPoolId;
- AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
- userPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoUserPoolIdResourceMappingKey);
- AZ_Warning("AWSCognitoAuthorizationController", !userPoolId.empty(), "Missing Cognito User pool id in resource mappings. Cognito IDP authenticated identities will not work.");
- AZStd::string defaultRegion;
- AWSCore::AWSResourceMappingRequestBus::BroadcastResult(
- defaultRegion, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
- m_formattedCognitoUserPoolId = AZStd::string::format(CognitoUserPoolIdFormat, defaultRegion.c_str(), userPoolId.c_str());
- m_persistentCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str());
- m_persistentAnonymousCognitoIdentityProvider->Initialize(m_awsAccountId.c_str(), m_cognitoIdentityPoolId.c_str());
- return true;
- }
- void AWSCognitoAuthorizationController::Reset()
- {
- // Brackets for lock guard scopes
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
- m_persistentAnonymousCognitoIdentityProvider->ClearLogins();
- m_persistentAnonymousCognitoIdentityProvider->ClearIdentity();
- }
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- m_persistentCognitoIdentityProvider->ClearLogins();
- m_persistentCognitoIdentityProvider->ClearIdentity();
- }
- }
- AZStd::string AWSCognitoAuthorizationController::GetIdentityId()
- {
- // Give preference to authenticated credentials provider.
- if (HasPersistedLogins())
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- return m_persistentCognitoIdentityProvider->GetIdentityId().c_str();
- }
- else
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
- return m_persistentAnonymousCognitoIdentityProvider->GetIdentityId().c_str();
- }
- }
- bool AWSCognitoAuthorizationController::HasPersistedLogins()
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- return m_persistentCognitoIdentityProvider->HasLogins();
- }
- std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetCognitoCredentialsProvider()
- {
- return m_cognitoCachingCredentialsProvider;
- }
- std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetAnonymousCognitoCredentialsProvider()
- {
- return m_cognitoCachingAnonymousCredentialsProvider;
- }
- void AWSCognitoAuthorizationController::RequestAWSCredentialsAsync()
- {
- bool anonymous = true;
- // Give preference to authenticated credentials provider.
- if (m_persistentCognitoIdentityProvider->HasLogins())
- {
- anonymous = false;
- }
- else
- {
- AZ_Warning("AWSCognitoAuthorizationController", false, "No logins found. Fetching anonymous/unauthenticated credentials");
- }
- AZ::JobContext* jobContext = nullptr;
- AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
- AZ::Job* job = AZ::CreateJobFunction(
- [this, anonymous]() {
- Aws::Auth::AWSCredentials credentials;
- // GetAWSCredentials makes Cognito GetId and GetCredentialsForIdentity Cognito identity pool API request if no valid cached credentials found.
- if (anonymous)
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
- credentials = m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials();
- }
- else
- {
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- credentials = m_cognitoCachingCredentialsProvider->GetAWSCredentials();
- }
-
- if (!credentials.IsEmpty())
- {
- ClientAuthAWSCredentials clientAuthAWSCrendentials(credentials.GetAWSAccessKeyId().c_str(), credentials.GetAWSSecretKey().c_str(), credentials.GetSessionToken().c_str());
- AWSClientAuth::AWSCognitoAuthorizationNotificationBus::Broadcast(
- &AWSClientAuth::AWSCognitoAuthorizationNotifications::OnRequestAWSCredentialsSuccess, clientAuthAWSCrendentials);
- }
- else
- {
- AWSClientAuth::AWSCognitoAuthorizationNotificationBus::Broadcast(
- &AWSClientAuth::AWSCognitoAuthorizationNotifications::OnRequestAWSCredentialsFail,
- "Failed to get AWS credentials");
- }
- },
- true, jobContext);
- job->Start();
- }
- AZStd::string AWSCognitoAuthorizationController::GetAuthenticationProviderId(const ProviderNameEnum& providerName)
- {
- switch (providerName)
- {
- case ProviderNameEnum::AWSCognitoIDP:
- {
- return m_formattedCognitoUserPoolId;
- }
- case ProviderNameEnum::LoginWithAmazon:
- {
- return CognitoAmazonLoginsId;
- }
- case ProviderNameEnum::Google:
- {
- return CognitoGoogleLoginsId;
- }
- default:
- {
- return "";
- }
- }
- }
- void AWSCognitoAuthorizationController::PersistLoginsAndRefreshAWSCredentials(const AuthenticationTokens& authenticationTokens)
- {
- // lock to persist logins as the object is shared with Native SDK. Native SDK reads logins and persists identity id and expiry.
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- // Save logins to the shared persistent Cognito identity provider for authenticated authorization.
- // Append logins to existing map.
- Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> logins = m_persistentCognitoIdentityProvider->GetLogins();
- Aws::Auth::LoginAccessTokens tokens;
- tokens.accessToken = authenticationTokens.GetOpenIdToken().c_str();
- logins[GetAuthenticationProviderId(authenticationTokens.GetProviderName()).c_str()] = tokens;
- m_persistentCognitoIdentityProvider->PersistLogins(logins);
- }
- void AWSCognitoAuthorizationController::OnPasswordGrantSingleFactorSignInSuccess(const AWSClientAuth::AuthenticationTokens& authenticationTokens)
- {
- PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
- }
- void AWSCognitoAuthorizationController::OnPasswordGrantMultiFactorConfirmSignInSuccess(
- const AWSClientAuth::AuthenticationTokens& authenticationTokens)
- {
- PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
- }
- void AWSCognitoAuthorizationController::OnDeviceCodeGrantConfirmSignInSuccess(
- const AWSClientAuth::AuthenticationTokens& authenticationTokens)
- {
- PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
- }
- void AWSCognitoAuthorizationController::OnRefreshTokensSuccess(const AWSClientAuth::AuthenticationTokens& authenticationTokens)
- {
- PersistLoginsAndRefreshAWSCredentials(authenticationTokens);
- }
- void AWSCognitoAuthorizationController::OnSignOut(const ProviderNameEnum& provideName)
- {
- // lock to persist logins as the object is shared with Native SDK.
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- m_persistentCognitoIdentityProvider->RemoveLogin(GetAuthenticationProviderId(provideName).c_str());
- }
- int AWSCognitoAuthorizationController::GetCredentialHandlerOrder() const
- {
- return AWSCore::CredentialHandlerOrder::COGNITO_IDENITY_POOL_CREDENTIAL_HANDLER;
- }
- std::shared_ptr<Aws::Auth::AWSCredentialsProvider> AWSCognitoAuthorizationController::GetCredentialsProvider()
- {
- // If logins are persisted default to using authenticated credentials provide.
- // Check authenticated credentials to verify persisted logins are valid.
- if (HasPersistedLogins())
- {
- // lock to protect logins being persisted.
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentCognitoIdentityProviderMutex);
- if (!m_cognitoCachingCredentialsProvider->GetAWSCredentials().IsEmpty())
- {
- return m_cognitoCachingCredentialsProvider;
- }
- }
- // Check anonymous credentials as they are optional settings in Cognito Identity pool.
- if (m_cognitoIdentityPoolId.empty())
- {
- // If the identity pool isn't set, then the anonymous credential won't be found.
- // Return null, instead of asking AWS for credentials to avoid failing AWS requests and AWS errors due to a null identity pool id.
- return nullptr;
- }
- // Lock to protect getting identity id.
- AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
- if (!m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials().IsEmpty())
- {
- AZ_Warning("AWSCognitoAuthorizationCredentialHandler", false, "No logins found. Using Anonymous credential provider");
- return m_cognitoCachingAnonymousCredentialsProvider;
- }
- return nullptr;
- }
- } // namespace AWSClientAuth
|