You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
287 lines
13 KiB
C++
287 lines
13 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include <AWSClientAuthBus.h>
|
|
#include <AWSCoreBus.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<Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider>(m_persistentCognitoIdentityProvider, identityClient);
|
|
|
|
m_cognitoCachingAnonymousCredentialsProvider =
|
|
std::make_shared<Aws::Auth::CognitoCachingAnonymousCredentialsProvider>(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() || m_cognitoIdentityPoolId.empty())
|
|
{
|
|
AZ_Warning("AWSCognitoAuthorizationController", !m_awsAccountId.empty(), "Missing AWS account id not configured.");
|
|
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 no 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;
|
|
}
|
|
}
|
|
|
|
// lock to protect getting identity id.
|
|
AZStd::lock_guard<AZStd::mutex> lock(m_persistentAnonymousCognitoIdentityProviderMutex);
|
|
// Check anonymous credentials as they are optional settings in Cognito Identity pool.
|
|
if (!m_cognitoCachingAnonymousCredentialsProvider->GetAWSCredentials().IsEmpty())
|
|
{
|
|
AZ_Warning("AWSCognitoAuthorizationCredentialHandler", false, "No logins found. Using Anonymous credential provider");
|
|
return m_cognitoCachingAnonymousCredentialsProvider;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
} // namespace AWSClientAuth
|